Improve a safety check when writing data into StatBuffer
[mono.git] / mono / mini / method-to-ir.c
1 /*
2  * method-to-ir.c: Convert CIL to the JIT internal representation
3  *
4  * Author:
5  *   Paolo Molaro (lupus@ximian.com)
6  *   Dietmar Maurer (dietmar@ximian.com)
7  *
8  * (C) 2002 Ximian, Inc.
9  * Copyright 2003-2010 Novell, Inc (http://www.novell.com)
10  * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
11  */
12
13 #include <config.h>
14
15 #ifndef DISABLE_JIT
16
17 #include <signal.h>
18
19 #ifdef HAVE_UNISTD_H
20 #include <unistd.h>
21 #endif
22
23 #include <math.h>
24 #include <string.h>
25 #include <ctype.h>
26
27 #ifdef HAVE_SYS_TIME_H
28 #include <sys/time.h>
29 #endif
30
31 #ifdef HAVE_ALLOCA_H
32 #include <alloca.h>
33 #endif
34
35 #include <mono/utils/memcheck.h>
36 #include "mini.h"
37 #include <mono/metadata/abi-details.h>
38 #include <mono/metadata/assembly.h>
39 #include <mono/metadata/attrdefs.h>
40 #include <mono/metadata/loader.h>
41 #include <mono/metadata/tabledefs.h>
42 #include <mono/metadata/class.h>
43 #include <mono/metadata/object.h>
44 #include <mono/metadata/exception.h>
45 #include <mono/metadata/opcodes.h>
46 #include <mono/metadata/mono-endian.h>
47 #include <mono/metadata/tokentype.h>
48 #include <mono/metadata/tabledefs.h>
49 #include <mono/metadata/marshal.h>
50 #include <mono/metadata/debug-helpers.h>
51 #include <mono/metadata/mono-debug.h>
52 #include <mono/metadata/mono-debug-debugger.h>
53 #include <mono/metadata/gc-internals.h>
54 #include <mono/metadata/security-manager.h>
55 #include <mono/metadata/threads-types.h>
56 #include <mono/metadata/security-core-clr.h>
57 #include <mono/metadata/profiler-private.h>
58 #include <mono/metadata/profiler.h>
59 #include <mono/metadata/monitor.h>
60 #include <mono/metadata/debug-mono-symfile.h>
61 #include <mono/utils/mono-compiler.h>
62 #include <mono/utils/mono-memory-model.h>
63 #include <mono/utils/mono-error-internals.h>
64 #include <mono/metadata/mono-basic-block.h>
65 #include <mono/metadata/reflection-internals.h>
66
67 #include "trace.h"
68
69 #include "ir-emit.h"
70
71 #include "jit-icalls.h"
72 #include "jit.h"
73 #include "debugger-agent.h"
74 #include "seq-points.h"
75 #include "aot-compiler.h"
76 #include "mini-llvm.h"
77
78 #define BRANCH_COST 10
79 #define INLINE_LENGTH_LIMIT 20
80
81 /* These have 'cfg' as an implicit argument */
82 #define INLINE_FAILURE(msg) do {                                                                        \
83         if ((cfg->method != cfg->current_method) && (cfg->current_method->wrapper_type == MONO_WRAPPER_NONE)) { \
84                 inline_failure (cfg, msg);                                                                              \
85                 goto exception_exit;                                                                                    \
86         } \
87         } while (0)
88 #define CHECK_CFG_EXCEPTION do {\
89                 if (cfg->exception_type != MONO_EXCEPTION_NONE) \
90                         goto exception_exit;                                            \
91         } while (0)
92 #define METHOD_ACCESS_FAILURE(method, cmethod) do {                     \
93                 method_access_failure ((cfg), (method), (cmethod));                     \
94                 goto exception_exit;                                                                            \
95         } while (0)
96 #define FIELD_ACCESS_FAILURE(method, field) do {                                        \
97                 field_access_failure ((cfg), (method), (field));                        \
98                 goto exception_exit;    \
99         } while (0)
100 #define GENERIC_SHARING_FAILURE(opcode) do {            \
101                 if (cfg->gshared) {                                                                     \
102                         gshared_failure (cfg, opcode, __FILE__, __LINE__);      \
103                         goto exception_exit;    \
104                 }                       \
105         } while (0)
106 #define GSHAREDVT_FAILURE(opcode) do {          \
107         if (cfg->gsharedvt) {                                                                                           \
108                 gsharedvt_failure (cfg, opcode, __FILE__, __LINE__);                    \
109                 goto exception_exit;                                                                                    \
110         }                                                                                                                                       \
111         } while (0)
112 #define OUT_OF_MEMORY_FAILURE do {      \
113                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);                \
114                 mono_error_set_out_of_memory (&cfg->error, "");                                 \
115                 goto exception_exit;    \
116         } while (0)
117 #define DISABLE_AOT(cfg) do { \
118                 if ((cfg)->verbose_level >= 2)                                            \
119                         printf ("AOT disabled: %s:%d\n", __FILE__, __LINE__);   \
120                 (cfg)->disable_aot = TRUE;                                                        \
121         } while (0)
122 #define LOAD_ERROR do { \
123                 break_on_unverified ();                                                         \
124                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD); \
125                 goto exception_exit;                                                                    \
126         } while (0)
127
128 #define TYPE_LOAD_ERROR(klass) do { \
129                 cfg->exception_ptr = klass; \
130                 LOAD_ERROR;                                     \
131         } while (0)
132
133 #define CHECK_CFG_ERROR do {\
134                 if (!mono_error_ok (&cfg->error)) { \
135                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);        \
136                         goto mono_error_exit; \
137                 } \
138         } while (0)
139
140 /* Determine whenever 'ins' represents a load of the 'this' argument */
141 #define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && ((ins)->opcode == OP_MOVE) && ((ins)->sreg1 == cfg->args [0]->dreg))
142
143 static int ldind_to_load_membase (int opcode);
144 static int stind_to_store_membase (int opcode);
145
146 int mono_op_to_op_imm (int opcode);
147 int mono_op_to_op_imm_noemul (int opcode);
148
149 MONO_API MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
150
151 static int inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
152                                                   guchar *ip, guint real_offset, gboolean inline_always);
153 static MonoInst*
154 emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used, MonoInst **sp);
155
156 /* helper methods signatures */
157 static MonoMethodSignature *helper_sig_domain_get;
158 static MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline;
159 static MonoMethodSignature *helper_sig_llvmonly_imt_thunk;
160
161
162 /* type loading helpers */
163 static GENERATE_GET_CLASS_WITH_CACHE (runtime_helpers, System.Runtime.CompilerServices, RuntimeHelpers)
164 static GENERATE_TRY_GET_CLASS_WITH_CACHE (debuggable_attribute, System.Diagnostics, DebuggableAttribute)
165
166 /*
167  * Instruction metadata
168  */
169 #ifdef MINI_OP
170 #undef MINI_OP
171 #endif
172 #ifdef MINI_OP3
173 #undef MINI_OP3
174 #endif
175 #define MINI_OP(a,b,dest,src1,src2) dest, src1, src2, ' ',
176 #define MINI_OP3(a,b,dest,src1,src2,src3) dest, src1, src2, src3,
177 #define NONE ' '
178 #define IREG 'i'
179 #define FREG 'f'
180 #define VREG 'v'
181 #define XREG 'x'
182 #if SIZEOF_REGISTER == 8 && SIZEOF_REGISTER == SIZEOF_VOID_P
183 #define LREG IREG
184 #else
185 #define LREG 'l'
186 #endif
187 /* keep in sync with the enum in mini.h */
188 const char
189 ins_info[] = {
190 #include "mini-ops.h"
191 };
192 #undef MINI_OP
193 #undef MINI_OP3
194
195 #define MINI_OP(a,b,dest,src1,src2) ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0)),
196 #define MINI_OP3(a,b,dest,src1,src2,src3) ((src3) != NONE ? 3 : ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0))),
197 /* 
198  * This should contain the index of the last sreg + 1. This is not the same
199  * as the number of sregs for opcodes like IA64_CMP_EQ_IMM.
200  */
201 const gint8 ins_sreg_counts[] = {
202 #include "mini-ops.h"
203 };
204 #undef MINI_OP
205 #undef MINI_OP3
206
207 #define MONO_INIT_VARINFO(vi,id) do { \
208         (vi)->range.first_use.pos.bid = 0xffff; \
209         (vi)->reg = -1; \
210         (vi)->idx = (id); \
211 } while (0)
212
213 guint32
214 mono_alloc_ireg (MonoCompile *cfg)
215 {
216         return alloc_ireg (cfg);
217 }
218
219 guint32
220 mono_alloc_lreg (MonoCompile *cfg)
221 {
222         return alloc_lreg (cfg);
223 }
224
225 guint32
226 mono_alloc_freg (MonoCompile *cfg)
227 {
228         return alloc_freg (cfg);
229 }
230
231 guint32
232 mono_alloc_preg (MonoCompile *cfg)
233 {
234         return alloc_preg (cfg);
235 }
236
237 guint32
238 mono_alloc_dreg (MonoCompile *cfg, MonoStackType stack_type)
239 {
240         return alloc_dreg (cfg, stack_type);
241 }
242
243 /*
244  * mono_alloc_ireg_ref:
245  *
246  *   Allocate an IREG, and mark it as holding a GC ref.
247  */
248 guint32
249 mono_alloc_ireg_ref (MonoCompile *cfg)
250 {
251         return alloc_ireg_ref (cfg);
252 }
253
254 /*
255  * mono_alloc_ireg_mp:
256  *
257  *   Allocate an IREG, and mark it as holding a managed pointer.
258  */
259 guint32
260 mono_alloc_ireg_mp (MonoCompile *cfg)
261 {
262         return alloc_ireg_mp (cfg);
263 }
264
265 /*
266  * mono_alloc_ireg_copy:
267  *
268  *   Allocate an IREG with the same GC type as VREG.
269  */
270 guint32
271 mono_alloc_ireg_copy (MonoCompile *cfg, guint32 vreg)
272 {
273         if (vreg_is_ref (cfg, vreg))
274                 return alloc_ireg_ref (cfg);
275         else if (vreg_is_mp (cfg, vreg))
276                 return alloc_ireg_mp (cfg);
277         else
278                 return alloc_ireg (cfg);
279 }
280
281 guint
282 mono_type_to_regmove (MonoCompile *cfg, MonoType *type)
283 {
284         if (type->byref)
285                 return OP_MOVE;
286
287         type = mini_get_underlying_type (type);
288 handle_enum:
289         switch (type->type) {
290         case MONO_TYPE_I1:
291         case MONO_TYPE_U1:
292                 return OP_MOVE;
293         case MONO_TYPE_I2:
294         case MONO_TYPE_U2:
295                 return OP_MOVE;
296         case MONO_TYPE_I4:
297         case MONO_TYPE_U4:
298                 return OP_MOVE;
299         case MONO_TYPE_I:
300         case MONO_TYPE_U:
301         case MONO_TYPE_PTR:
302         case MONO_TYPE_FNPTR:
303                 return OP_MOVE;
304         case MONO_TYPE_CLASS:
305         case MONO_TYPE_STRING:
306         case MONO_TYPE_OBJECT:
307         case MONO_TYPE_SZARRAY:
308         case MONO_TYPE_ARRAY:    
309                 return OP_MOVE;
310         case MONO_TYPE_I8:
311         case MONO_TYPE_U8:
312 #if SIZEOF_REGISTER == 8
313                 return OP_MOVE;
314 #else
315                 return OP_LMOVE;
316 #endif
317         case MONO_TYPE_R4:
318                 return cfg->r4fp ? OP_RMOVE : OP_FMOVE;
319         case MONO_TYPE_R8:
320                 return OP_FMOVE;
321         case MONO_TYPE_VALUETYPE:
322                 if (type->data.klass->enumtype) {
323                         type = mono_class_enum_basetype (type->data.klass);
324                         goto handle_enum;
325                 }
326                 if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
327                         return OP_XMOVE;
328                 return OP_VMOVE;
329         case MONO_TYPE_TYPEDBYREF:
330                 return OP_VMOVE;
331         case MONO_TYPE_GENERICINST:
332                 type = &type->data.generic_class->container_class->byval_arg;
333                 goto handle_enum;
334         case MONO_TYPE_VAR:
335         case MONO_TYPE_MVAR:
336                 g_assert (cfg->gshared);
337                 if (mini_type_var_is_vt (type))
338                         return OP_VMOVE;
339                 else
340                         return mono_type_to_regmove (cfg, mini_get_underlying_type (type));
341         default:
342                 g_error ("unknown type 0x%02x in type_to_regstore", type->type);
343         }
344         return -1;
345 }
346
347 void
348 mono_print_bb (MonoBasicBlock *bb, const char *msg)
349 {
350         int i;
351         MonoInst *tree;
352
353         printf ("\n%s %d: [IN: ", msg, bb->block_num);
354         for (i = 0; i < bb->in_count; ++i)
355                 printf (" BB%d(%d)", bb->in_bb [i]->block_num, bb->in_bb [i]->dfn);
356         printf (", OUT: ");
357         for (i = 0; i < bb->out_count; ++i)
358                 printf (" BB%d(%d)", bb->out_bb [i]->block_num, bb->out_bb [i]->dfn);
359         printf (" ]\n");
360         for (tree = bb->code; tree; tree = tree->next)
361                 mono_print_ins_index (-1, tree);
362 }
363
364 void
365 mono_create_helper_signatures (void)
366 {
367         helper_sig_domain_get = mono_create_icall_signature ("ptr");
368         helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
369         helper_sig_llvmonly_imt_thunk = mono_create_icall_signature ("ptr ptr ptr");
370 }
371
372 static MONO_NEVER_INLINE void
373 break_on_unverified (void)
374 {
375         if (mini_get_debug_options ()->break_on_unverified)
376                 G_BREAKPOINT ();
377 }
378
379 static MONO_NEVER_INLINE void
380 method_access_failure (MonoCompile *cfg, MonoMethod *method, MonoMethod *cil_method)
381 {
382         char *method_fname = mono_method_full_name (method, TRUE);
383         char *cil_method_fname = mono_method_full_name (cil_method, TRUE);
384         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
385         mono_error_set_generic_error (&cfg->error, "System", "MethodAccessException", "Method `%s' is inaccessible from method `%s'\n", cil_method_fname, method_fname);
386         g_free (method_fname);
387         g_free (cil_method_fname);
388 }
389
390 static MONO_NEVER_INLINE void
391 field_access_failure (MonoCompile *cfg, MonoMethod *method, MonoClassField *field)
392 {
393         char *method_fname = mono_method_full_name (method, TRUE);
394         char *field_fname = mono_field_full_name (field);
395         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
396         mono_error_set_generic_error (&cfg->error, "System", "FieldAccessException", "Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname);
397         g_free (method_fname);
398         g_free (field_fname);
399 }
400
401 static MONO_NEVER_INLINE void
402 inline_failure (MonoCompile *cfg, const char *msg)
403 {
404         if (cfg->verbose_level >= 2)
405                 printf ("inline failed: %s\n", msg);
406         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INLINE_FAILED);
407 }
408
409 static MONO_NEVER_INLINE void
410 gshared_failure (MonoCompile *cfg, int opcode, const char *file, int line)
411 {
412         if (cfg->verbose_level > 2)                                                                                     \
413                 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);
414         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
415 }
416
417 static MONO_NEVER_INLINE void
418 gsharedvt_failure (MonoCompile *cfg, int opcode, const char *file, int line)
419 {
420         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);
421         if (cfg->verbose_level >= 2)
422                 printf ("%s\n", cfg->exception_message);
423         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
424 }
425
426 /*
427  * When using gsharedvt, some instatiations might be verifiable, and some might be not. i.e. 
428  * foo<T> (int i) { ldarg.0; box T; }
429  */
430 #define UNVERIFIED do { \
431         if (cfg->gsharedvt) { \
432                 if (cfg->verbose_level > 2)                                                                     \
433                         printf ("gsharedvt method failed to verify, falling back to instantiation.\n"); \
434                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED); \
435                 goto exception_exit;                                                                                    \
436         }                                                                                                                                       \
437         break_on_unverified ();                                                                                         \
438         goto unverified;                                                                                                        \
439 } while (0)
440
441 #define GET_BBLOCK(cfg,tblock,ip) do {  \
442                 (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
443                 if (!(tblock)) {        \
444                         if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
445             NEW_BBLOCK (cfg, (tblock)); \
446                         (tblock)->cil_code = (ip);      \
447                         ADD_BBLOCK (cfg, (tblock));     \
448                 } \
449         } while (0)
450
451 #if defined(TARGET_X86) || defined(TARGET_AMD64)
452 #define EMIT_NEW_X86_LEA(cfg,dest,sr1,sr2,shift,imm) do { \
453                 MONO_INST_NEW (cfg, dest, OP_X86_LEA); \
454                 (dest)->dreg = alloc_ireg_mp ((cfg)); \
455                 (dest)->sreg1 = (sr1); \
456                 (dest)->sreg2 = (sr2); \
457                 (dest)->inst_imm = (imm); \
458                 (dest)->backend.shift_amount = (shift); \
459                 MONO_ADD_INS ((cfg)->cbb, (dest)); \
460         } while (0)
461 #endif
462
463 /* Emit conversions so both operands of a binary opcode are of the same type */
464 static void
465 add_widen_op (MonoCompile *cfg, MonoInst *ins, MonoInst **arg1_ref, MonoInst **arg2_ref)
466 {
467         MonoInst *arg1 = *arg1_ref;
468         MonoInst *arg2 = *arg2_ref;
469
470         if (cfg->r4fp &&
471                 ((arg1->type == STACK_R4 && arg2->type == STACK_R8) ||
472                  (arg1->type == STACK_R8 && arg2->type == STACK_R4))) {
473                 MonoInst *conv;
474
475                 /* Mixing r4/r8 is allowed by the spec */
476                 if (arg1->type == STACK_R4) {
477                         int dreg = alloc_freg (cfg);
478
479                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg1->dreg);
480                         conv->type = STACK_R8;
481                         ins->sreg1 = dreg;
482                         *arg1_ref = conv;
483                 }
484                 if (arg2->type == STACK_R4) {
485                         int dreg = alloc_freg (cfg);
486
487                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg2->dreg);
488                         conv->type = STACK_R8;
489                         ins->sreg2 = dreg;
490                         *arg2_ref = conv;
491                 }
492         }
493
494 #if SIZEOF_REGISTER == 8
495         /* FIXME: Need to add many more cases */
496         if ((arg1)->type == STACK_PTR && (arg2)->type == STACK_I4) {
497                 MonoInst *widen;
498
499                 int dr = alloc_preg (cfg);
500                 EMIT_NEW_UNALU (cfg, widen, OP_SEXT_I4, dr, (arg2)->dreg);
501                 (ins)->sreg2 = widen->dreg;
502         }
503 #endif
504 }
505
506 #define ADD_BINOP(op) do {      \
507                 MONO_INST_NEW (cfg, ins, (op)); \
508                 sp -= 2;        \
509                 ins->sreg1 = sp [0]->dreg;      \
510                 ins->sreg2 = sp [1]->dreg;      \
511                 type_from_op (cfg, ins, sp [0], sp [1]);        \
512                 CHECK_TYPE (ins);       \
513                 /* Have to insert a widening op */               \
514         add_widen_op (cfg, ins, &sp [0], &sp [1]);               \
515         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type); \
516         MONO_ADD_INS ((cfg)->cbb, (ins)); \
517         *sp++ = mono_decompose_opcode ((cfg), (ins));   \
518         } while (0)
519
520 #define ADD_UNOP(op) do {       \
521                 MONO_INST_NEW (cfg, ins, (op)); \
522                 sp--;   \
523                 ins->sreg1 = sp [0]->dreg;      \
524                 type_from_op (cfg, ins, sp [0], NULL);  \
525                 CHECK_TYPE (ins);       \
526         (ins)->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type); \
527         MONO_ADD_INS ((cfg)->cbb, (ins)); \
528                 *sp++ = mono_decompose_opcode (cfg, ins);       \
529         } while (0)
530
531 #define ADD_BINCOND(next_block) do {    \
532                 MonoInst *cmp;  \
533                 sp -= 2; \
534                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
535                 cmp->sreg1 = sp [0]->dreg;      \
536                 cmp->sreg2 = sp [1]->dreg;      \
537                 type_from_op (cfg, cmp, sp [0], sp [1]);        \
538                 CHECK_TYPE (cmp);       \
539                 add_widen_op (cfg, cmp, &sp [0], &sp [1]);                                              \
540                 type_from_op (cfg, ins, sp [0], sp [1]);                                                        \
541                 ins->inst_many_bb = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);   \
542                 GET_BBLOCK (cfg, tblock, target);               \
543                 link_bblock (cfg, cfg->cbb, tblock);    \
544                 ins->inst_true_bb = tblock;     \
545                 if ((next_block)) {     \
546                         link_bblock (cfg, cfg->cbb, (next_block));      \
547                         ins->inst_false_bb = (next_block);      \
548                         start_new_bblock = 1;   \
549                 } else {        \
550                         GET_BBLOCK (cfg, tblock, ip);           \
551                         link_bblock (cfg, cfg->cbb, tblock);    \
552                         ins->inst_false_bb = tblock;    \
553                         start_new_bblock = 2;   \
554                 }       \
555                 if (sp != stack_start) {                                                                        \
556                     handle_stack_args (cfg, stack_start, sp - stack_start); \
557                         CHECK_UNVERIFIABLE (cfg); \
558                 } \
559         MONO_ADD_INS (cfg->cbb, cmp); \
560                 MONO_ADD_INS (cfg->cbb, ins);   \
561         } while (0)
562
563 /* *
564  * link_bblock: Links two basic blocks
565  *
566  * links two basic blocks in the control flow graph, the 'from'
567  * argument is the starting block and the 'to' argument is the block
568  * the control flow ends to after 'from'.
569  */
570 static void
571 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
572 {
573         MonoBasicBlock **newa;
574         int i, found;
575
576 #if 0
577         if (from->cil_code) {
578                 if (to->cil_code)
579                         printf ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
580                 else
581                         printf ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
582         } else {
583                 if (to->cil_code)
584                         printf ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
585                 else
586                         printf ("edge from entry to exit\n");
587         }
588 #endif
589
590         found = FALSE;
591         for (i = 0; i < from->out_count; ++i) {
592                 if (to == from->out_bb [i]) {
593                         found = TRUE;
594                         break;
595                 }
596         }
597         if (!found) {
598                 newa = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
599                 for (i = 0; i < from->out_count; ++i) {
600                         newa [i] = from->out_bb [i];
601                 }
602                 newa [i] = to;
603                 from->out_count++;
604                 from->out_bb = newa;
605         }
606
607         found = FALSE;
608         for (i = 0; i < to->in_count; ++i) {
609                 if (from == to->in_bb [i]) {
610                         found = TRUE;
611                         break;
612                 }
613         }
614         if (!found) {
615                 newa = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
616                 for (i = 0; i < to->in_count; ++i) {
617                         newa [i] = to->in_bb [i];
618                 }
619                 newa [i] = from;
620                 to->in_count++;
621                 to->in_bb = newa;
622         }
623 }
624
625 void
626 mono_link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
627 {
628         link_bblock (cfg, from, to);
629 }
630
631 /**
632  * mono_find_block_region:
633  *
634  *   We mark each basic block with a region ID. We use that to avoid BB
635  *   optimizations when blocks are in different regions.
636  *
637  * Returns:
638  *   A region token that encodes where this region is, and information
639  *   about the clause owner for this block.
640  *
641  *   The region encodes the try/catch/filter clause that owns this block
642  *   as well as the type.  -1 is a special value that represents a block
643  *   that is in none of try/catch/filter.
644  */
645 static int
646 mono_find_block_region (MonoCompile *cfg, int offset)
647 {
648         MonoMethodHeader *header = cfg->header;
649         MonoExceptionClause *clause;
650         int i;
651
652         for (i = 0; i < header->num_clauses; ++i) {
653                 clause = &header->clauses [i];
654                 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
655                     (offset < (clause->handler_offset)))
656                         return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
657                            
658                 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
659                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
660                                 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
661                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
662                                 return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
663                         else
664                                 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
665                 }
666         }
667         for (i = 0; i < header->num_clauses; ++i) {
668                 clause = &header->clauses [i];
669
670                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
671                         return ((i + 1) << 8) | clause->flags;
672         }
673
674         return -1;
675 }
676
677 static GList*
678 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
679 {
680         MonoMethodHeader *header = cfg->header;
681         MonoExceptionClause *clause;
682         int i;
683         GList *res = NULL;
684
685         for (i = 0; i < header->num_clauses; ++i) {
686                 clause = &header->clauses [i];
687                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
688                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
689                         if (clause->flags == type)
690                                 res = g_list_append (res, clause);
691                 }
692         }
693         return res;
694 }
695
696 static void
697 mono_create_spvar_for_region (MonoCompile *cfg, int region)
698 {
699         MonoInst *var;
700
701         var = (MonoInst *)g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
702         if (var)
703                 return;
704
705         var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
706         /* prevent it from being register allocated */
707         var->flags |= MONO_INST_VOLATILE;
708
709         g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
710 }
711
712 MonoInst *
713 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
714 {
715         return (MonoInst *)g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
716 }
717
718 static MonoInst*
719 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
720 {
721         MonoInst *var;
722
723         var = (MonoInst *)g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
724         if (var)
725                 return var;
726
727         var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
728         /* prevent it from being register allocated */
729         var->flags |= MONO_INST_VOLATILE;
730
731         g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
732
733         return var;
734 }
735
736 /*
737  * Returns the type used in the eval stack when @type is loaded.
738  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
739  */
740 void
741 type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
742 {
743         MonoClass *klass;
744
745         type = mini_get_underlying_type (type);
746         inst->klass = klass = mono_class_from_mono_type (type);
747         if (type->byref) {
748                 inst->type = STACK_MP;
749                 return;
750         }
751
752 handle_enum:
753         switch (type->type) {
754         case MONO_TYPE_VOID:
755                 inst->type = STACK_INV;
756                 return;
757         case MONO_TYPE_I1:
758         case MONO_TYPE_U1:
759         case MONO_TYPE_I2:
760         case MONO_TYPE_U2:
761         case MONO_TYPE_I4:
762         case MONO_TYPE_U4:
763                 inst->type = STACK_I4;
764                 return;
765         case MONO_TYPE_I:
766         case MONO_TYPE_U:
767         case MONO_TYPE_PTR:
768         case MONO_TYPE_FNPTR:
769                 inst->type = STACK_PTR;
770                 return;
771         case MONO_TYPE_CLASS:
772         case MONO_TYPE_STRING:
773         case MONO_TYPE_OBJECT:
774         case MONO_TYPE_SZARRAY:
775         case MONO_TYPE_ARRAY:    
776                 inst->type = STACK_OBJ;
777                 return;
778         case MONO_TYPE_I8:
779         case MONO_TYPE_U8:
780                 inst->type = STACK_I8;
781                 return;
782         case MONO_TYPE_R4:
783                 inst->type = cfg->r4_stack_type;
784                 break;
785         case MONO_TYPE_R8:
786                 inst->type = STACK_R8;
787                 return;
788         case MONO_TYPE_VALUETYPE:
789                 if (type->data.klass->enumtype) {
790                         type = mono_class_enum_basetype (type->data.klass);
791                         goto handle_enum;
792                 } else {
793                         inst->klass = klass;
794                         inst->type = STACK_VTYPE;
795                         return;
796                 }
797         case MONO_TYPE_TYPEDBYREF:
798                 inst->klass = mono_defaults.typed_reference_class;
799                 inst->type = STACK_VTYPE;
800                 return;
801         case MONO_TYPE_GENERICINST:
802                 type = &type->data.generic_class->container_class->byval_arg;
803                 goto handle_enum;
804         case MONO_TYPE_VAR:
805         case MONO_TYPE_MVAR:
806                 g_assert (cfg->gshared);
807                 if (mini_is_gsharedvt_type (type)) {
808                         g_assert (cfg->gsharedvt);
809                         inst->type = STACK_VTYPE;
810                 } else {
811                         type_to_eval_stack_type (cfg, mini_get_underlying_type (type), inst);
812                 }
813                 return;
814         default:
815                 g_error ("unknown type 0x%02x in eval stack type", type->type);
816         }
817 }
818
819 /*
820  * The following tables are used to quickly validate the IL code in type_from_op ().
821  */
822 static const char
823 bin_num_table [STACK_MAX] [STACK_MAX] = {
824         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
825         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
826         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
827         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
828         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV, STACK_R8},
829         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
830         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
831         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
832         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4}
833 };
834
835 static const char 
836 neg_table [] = {
837         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4
838 };
839
840 /* reduce the size of this table */
841 static const char
842 bin_int_table [STACK_MAX] [STACK_MAX] = {
843         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
844         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
845         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
846         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
847         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
848         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
849         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
850         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
851 };
852
853 static const char
854 bin_comp_table [STACK_MAX] [STACK_MAX] = {
855 /*      Inv i  L  p  F  &  O  vt r4 */
856         {0},
857         {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
858         {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
859         {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
860         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* F, R8 */
861         {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
862         {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
863         {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
864         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* r, r4 */
865 };
866
867 /* reduce the size of this table */
868 static const char
869 shift_table [STACK_MAX] [STACK_MAX] = {
870         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
871         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
872         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
873         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
874         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
875         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
876         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
877         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
878 };
879
880 /*
881  * Tables to map from the non-specific opcode to the matching
882  * type-specific opcode.
883  */
884 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
885 static const guint16
886 binops_op_map [STACK_MAX] = {
887         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
888 };
889
890 /* handles from CEE_NEG to CEE_CONV_U8 */
891 static const guint16
892 unops_op_map [STACK_MAX] = {
893         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
894 };
895
896 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
897 static const guint16
898 ovfops_op_map [STACK_MAX] = {
899         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
900 };
901
902 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
903 static const guint16
904 ovf2ops_op_map [STACK_MAX] = {
905         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
906 };
907
908 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
909 static const guint16
910 ovf3ops_op_map [STACK_MAX] = {
911         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
912 };
913
914 /* handles from CEE_BEQ to CEE_BLT_UN */
915 static const guint16
916 beqops_op_map [STACK_MAX] = {
917         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
918 };
919
920 /* handles from CEE_CEQ to CEE_CLT_UN */
921 static const guint16
922 ceqops_op_map [STACK_MAX] = {
923         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
924 };
925
926 /*
927  * Sets ins->type (the type on the eval stack) according to the
928  * type of the opcode and the arguments to it.
929  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
930  *
931  * FIXME: this function sets ins->type unconditionally in some cases, but
932  * it should set it to invalid for some types (a conv.x on an object)
933  */
934 static void
935 type_from_op (MonoCompile *cfg, MonoInst *ins, MonoInst *src1, MonoInst *src2)
936 {
937         switch (ins->opcode) {
938         /* binops */
939         case CEE_ADD:
940         case CEE_SUB:
941         case CEE_MUL:
942         case CEE_DIV:
943         case CEE_REM:
944                 /* FIXME: check unverifiable args for STACK_MP */
945                 ins->type = bin_num_table [src1->type] [src2->type];
946                 ins->opcode += binops_op_map [ins->type];
947                 break;
948         case CEE_DIV_UN:
949         case CEE_REM_UN:
950         case CEE_AND:
951         case CEE_OR:
952         case CEE_XOR:
953                 ins->type = bin_int_table [src1->type] [src2->type];
954                 ins->opcode += binops_op_map [ins->type];
955                 break;
956         case CEE_SHL:
957         case CEE_SHR:
958         case CEE_SHR_UN:
959                 ins->type = shift_table [src1->type] [src2->type];
960                 ins->opcode += binops_op_map [ins->type];
961                 break;
962         case OP_COMPARE:
963         case OP_LCOMPARE:
964         case OP_ICOMPARE:
965                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
966                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
967                         ins->opcode = OP_LCOMPARE;
968                 else if (src1->type == STACK_R4)
969                         ins->opcode = OP_RCOMPARE;
970                 else if (src1->type == STACK_R8)
971                         ins->opcode = OP_FCOMPARE;
972                 else
973                         ins->opcode = OP_ICOMPARE;
974                 break;
975         case OP_ICOMPARE_IMM:
976                 ins->type = bin_comp_table [src1->type] [src1->type] ? STACK_I4 : STACK_INV;
977                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
978                         ins->opcode = OP_LCOMPARE_IMM;          
979                 break;
980         case CEE_BEQ:
981         case CEE_BGE:
982         case CEE_BGT:
983         case CEE_BLE:
984         case CEE_BLT:
985         case CEE_BNE_UN:
986         case CEE_BGE_UN:
987         case CEE_BGT_UN:
988         case CEE_BLE_UN:
989         case CEE_BLT_UN:
990                 ins->opcode += beqops_op_map [src1->type];
991                 break;
992         case OP_CEQ:
993                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
994                 ins->opcode += ceqops_op_map [src1->type];
995                 break;
996         case OP_CGT:
997         case OP_CGT_UN:
998         case OP_CLT:
999         case OP_CLT_UN:
1000                 ins->type = (bin_comp_table [src1->type] [src2->type] & 1) ? STACK_I4: STACK_INV;
1001                 ins->opcode += ceqops_op_map [src1->type];
1002                 break;
1003         /* unops */
1004         case CEE_NEG:
1005                 ins->type = neg_table [src1->type];
1006                 ins->opcode += unops_op_map [ins->type];
1007                 break;
1008         case CEE_NOT:
1009                 if (src1->type >= STACK_I4 && src1->type <= STACK_PTR)
1010                         ins->type = src1->type;
1011                 else
1012                         ins->type = STACK_INV;
1013                 ins->opcode += unops_op_map [ins->type];
1014                 break;
1015         case CEE_CONV_I1:
1016         case CEE_CONV_I2:
1017         case CEE_CONV_I4:
1018         case CEE_CONV_U4:
1019                 ins->type = STACK_I4;
1020                 ins->opcode += unops_op_map [src1->type];
1021                 break;
1022         case CEE_CONV_R_UN:
1023                 ins->type = STACK_R8;
1024                 switch (src1->type) {
1025                 case STACK_I4:
1026                 case STACK_PTR:
1027                         ins->opcode = OP_ICONV_TO_R_UN;
1028                         break;
1029                 case STACK_I8:
1030                         ins->opcode = OP_LCONV_TO_R_UN; 
1031                         break;
1032                 }
1033                 break;
1034         case CEE_CONV_OVF_I1:
1035         case CEE_CONV_OVF_U1:
1036         case CEE_CONV_OVF_I2:
1037         case CEE_CONV_OVF_U2:
1038         case CEE_CONV_OVF_I4:
1039         case CEE_CONV_OVF_U4:
1040                 ins->type = STACK_I4;
1041                 ins->opcode += ovf3ops_op_map [src1->type];
1042                 break;
1043         case CEE_CONV_OVF_I_UN:
1044         case CEE_CONV_OVF_U_UN:
1045                 ins->type = STACK_PTR;
1046                 ins->opcode += ovf2ops_op_map [src1->type];
1047                 break;
1048         case CEE_CONV_OVF_I1_UN:
1049         case CEE_CONV_OVF_I2_UN:
1050         case CEE_CONV_OVF_I4_UN:
1051         case CEE_CONV_OVF_U1_UN:
1052         case CEE_CONV_OVF_U2_UN:
1053         case CEE_CONV_OVF_U4_UN:
1054                 ins->type = STACK_I4;
1055                 ins->opcode += ovf2ops_op_map [src1->type];
1056                 break;
1057         case CEE_CONV_U:
1058                 ins->type = STACK_PTR;
1059                 switch (src1->type) {
1060                 case STACK_I4:
1061                         ins->opcode = OP_ICONV_TO_U;
1062                         break;
1063                 case STACK_PTR:
1064                 case STACK_MP:
1065 #if SIZEOF_VOID_P == 8
1066                         ins->opcode = OP_LCONV_TO_U;
1067 #else
1068                         ins->opcode = OP_MOVE;
1069 #endif
1070                         break;
1071                 case STACK_I8:
1072                         ins->opcode = OP_LCONV_TO_U;
1073                         break;
1074                 case STACK_R8:
1075                         ins->opcode = OP_FCONV_TO_U;
1076                         break;
1077                 }
1078                 break;
1079         case CEE_CONV_I8:
1080         case CEE_CONV_U8:
1081                 ins->type = STACK_I8;
1082                 ins->opcode += unops_op_map [src1->type];
1083                 break;
1084         case CEE_CONV_OVF_I8:
1085         case CEE_CONV_OVF_U8:
1086                 ins->type = STACK_I8;
1087                 ins->opcode += ovf3ops_op_map [src1->type];
1088                 break;
1089         case CEE_CONV_OVF_U8_UN:
1090         case CEE_CONV_OVF_I8_UN:
1091                 ins->type = STACK_I8;
1092                 ins->opcode += ovf2ops_op_map [src1->type];
1093                 break;
1094         case CEE_CONV_R4:
1095                 ins->type = cfg->r4_stack_type;
1096                 ins->opcode += unops_op_map [src1->type];
1097                 break;
1098         case CEE_CONV_R8:
1099                 ins->type = STACK_R8;
1100                 ins->opcode += unops_op_map [src1->type];
1101                 break;
1102         case OP_CKFINITE:
1103                 ins->type = STACK_R8;           
1104                 break;
1105         case CEE_CONV_U2:
1106         case CEE_CONV_U1:
1107                 ins->type = STACK_I4;
1108                 ins->opcode += ovfops_op_map [src1->type];
1109                 break;
1110         case CEE_CONV_I:
1111         case CEE_CONV_OVF_I:
1112         case CEE_CONV_OVF_U:
1113                 ins->type = STACK_PTR;
1114                 ins->opcode += ovfops_op_map [src1->type];
1115                 break;
1116         case CEE_ADD_OVF:
1117         case CEE_ADD_OVF_UN:
1118         case CEE_MUL_OVF:
1119         case CEE_MUL_OVF_UN:
1120         case CEE_SUB_OVF:
1121         case CEE_SUB_OVF_UN:
1122                 ins->type = bin_num_table [src1->type] [src2->type];
1123                 ins->opcode += ovfops_op_map [src1->type];
1124                 if (ins->type == STACK_R8)
1125                         ins->type = STACK_INV;
1126                 break;
1127         case OP_LOAD_MEMBASE:
1128                 ins->type = STACK_PTR;
1129                 break;
1130         case OP_LOADI1_MEMBASE:
1131         case OP_LOADU1_MEMBASE:
1132         case OP_LOADI2_MEMBASE:
1133         case OP_LOADU2_MEMBASE:
1134         case OP_LOADI4_MEMBASE:
1135         case OP_LOADU4_MEMBASE:
1136                 ins->type = STACK_PTR;
1137                 break;
1138         case OP_LOADI8_MEMBASE:
1139                 ins->type = STACK_I8;
1140                 break;
1141         case OP_LOADR4_MEMBASE:
1142                 ins->type = cfg->r4_stack_type;
1143                 break;
1144         case OP_LOADR8_MEMBASE:
1145                 ins->type = STACK_R8;
1146                 break;
1147         default:
1148                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1149                 break;
1150         }
1151
1152         if (ins->type == STACK_MP)
1153                 ins->klass = mono_defaults.object_class;
1154 }
1155
1156 static const char 
1157 ldind_type [] = {
1158         STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
1159 };
1160
1161 #if 0
1162
1163 static const char
1164 param_table [STACK_MAX] [STACK_MAX] = {
1165         {0},
1166 };
1167
1168 static int
1169 check_values_to_signature (MonoInst *args, MonoType *this_ins, MonoMethodSignature *sig)
1170 {
1171         int i;
1172
1173         if (sig->hasthis) {
1174                 switch (args->type) {
1175                 case STACK_I4:
1176                 case STACK_I8:
1177                 case STACK_R8:
1178                 case STACK_VTYPE:
1179                 case STACK_INV:
1180                         return 0;
1181                 }
1182                 args++;
1183         }
1184         for (i = 0; i < sig->param_count; ++i) {
1185                 switch (args [i].type) {
1186                 case STACK_INV:
1187                         return 0;
1188                 case STACK_MP:
1189                         if (!sig->params [i]->byref)
1190                                 return 0;
1191                         continue;
1192                 case STACK_OBJ:
1193                         if (sig->params [i]->byref)
1194                                 return 0;
1195                         switch (sig->params [i]->type) {
1196                         case MONO_TYPE_CLASS:
1197                         case MONO_TYPE_STRING:
1198                         case MONO_TYPE_OBJECT:
1199                         case MONO_TYPE_SZARRAY:
1200                         case MONO_TYPE_ARRAY:
1201                                 break;
1202                         default:
1203                                 return 0;
1204                         }
1205                         continue;
1206                 case STACK_R8:
1207                         if (sig->params [i]->byref)
1208                                 return 0;
1209                         if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1210                                 return 0;
1211                         continue;
1212                 case STACK_PTR:
1213                 case STACK_I4:
1214                 case STACK_I8:
1215                 case STACK_VTYPE:
1216                         break;
1217                 }
1218                 /*if (!param_table [args [i].type] [sig->params [i]->type])
1219                         return 0;*/
1220         }
1221         return 1;
1222 }
1223 #endif
1224
1225 /*
1226  * When we need a pointer to the current domain many times in a method, we
1227  * call mono_domain_get() once and we store the result in a local variable.
1228  * This function returns the variable that represents the MonoDomain*.
1229  */
1230 inline static MonoInst *
1231 mono_get_domainvar (MonoCompile *cfg)
1232 {
1233         if (!cfg->domainvar)
1234                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1235         return cfg->domainvar;
1236 }
1237
1238 /*
1239  * The got_var contains the address of the Global Offset Table when AOT 
1240  * compiling.
1241  */
1242 MonoInst *
1243 mono_get_got_var (MonoCompile *cfg)
1244 {
1245         if (!cfg->compile_aot || !cfg->backend->need_got_var)
1246                 return NULL;
1247         if (!cfg->got_var) {
1248                 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1249         }
1250         return cfg->got_var;
1251 }
1252
1253 static MonoInst *
1254 mono_get_vtable_var (MonoCompile *cfg)
1255 {
1256         g_assert (cfg->gshared);
1257
1258         if (!cfg->rgctx_var) {
1259                 cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1260                 /* force the var to be stack allocated */
1261                 cfg->rgctx_var->flags |= MONO_INST_VOLATILE;
1262         }
1263
1264         return cfg->rgctx_var;
1265 }
1266
1267 static MonoType*
1268 type_from_stack_type (MonoInst *ins) {
1269         switch (ins->type) {
1270         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1271         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1272         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1273         case STACK_R4: return &mono_defaults.single_class->byval_arg;
1274         case STACK_R8: return &mono_defaults.double_class->byval_arg;
1275         case STACK_MP:
1276                 return &ins->klass->this_arg;
1277         case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1278         case STACK_VTYPE: return &ins->klass->byval_arg;
1279         default:
1280                 g_error ("stack type %d to monotype not handled\n", ins->type);
1281         }
1282         return NULL;
1283 }
1284
1285 static G_GNUC_UNUSED int
1286 type_to_stack_type (MonoCompile *cfg, MonoType *t)
1287 {
1288         t = mono_type_get_underlying_type (t);
1289         switch (t->type) {
1290         case MONO_TYPE_I1:
1291         case MONO_TYPE_U1:
1292         case MONO_TYPE_I2:
1293         case MONO_TYPE_U2:
1294         case MONO_TYPE_I4:
1295         case MONO_TYPE_U4:
1296                 return STACK_I4;
1297         case MONO_TYPE_I:
1298         case MONO_TYPE_U:
1299         case MONO_TYPE_PTR:
1300         case MONO_TYPE_FNPTR:
1301                 return STACK_PTR;
1302         case MONO_TYPE_CLASS:
1303         case MONO_TYPE_STRING:
1304         case MONO_TYPE_OBJECT:
1305         case MONO_TYPE_SZARRAY:
1306         case MONO_TYPE_ARRAY:    
1307                 return STACK_OBJ;
1308         case MONO_TYPE_I8:
1309         case MONO_TYPE_U8:
1310                 return STACK_I8;
1311         case MONO_TYPE_R4:
1312                 return cfg->r4_stack_type;
1313         case MONO_TYPE_R8:
1314                 return STACK_R8;
1315         case MONO_TYPE_VALUETYPE:
1316         case MONO_TYPE_TYPEDBYREF:
1317                 return STACK_VTYPE;
1318         case MONO_TYPE_GENERICINST:
1319                 if (mono_type_generic_inst_is_valuetype (t))
1320                         return STACK_VTYPE;
1321                 else
1322                         return STACK_OBJ;
1323                 break;
1324         default:
1325                 g_assert_not_reached ();
1326         }
1327
1328         return -1;
1329 }
1330
1331 static MonoClass*
1332 array_access_to_klass (int opcode)
1333 {
1334         switch (opcode) {
1335         case CEE_LDELEM_U1:
1336                 return mono_defaults.byte_class;
1337         case CEE_LDELEM_U2:
1338                 return mono_defaults.uint16_class;
1339         case CEE_LDELEM_I:
1340         case CEE_STELEM_I:
1341                 return mono_defaults.int_class;
1342         case CEE_LDELEM_I1:
1343         case CEE_STELEM_I1:
1344                 return mono_defaults.sbyte_class;
1345         case CEE_LDELEM_I2:
1346         case CEE_STELEM_I2:
1347                 return mono_defaults.int16_class;
1348         case CEE_LDELEM_I4:
1349         case CEE_STELEM_I4:
1350                 return mono_defaults.int32_class;
1351         case CEE_LDELEM_U4:
1352                 return mono_defaults.uint32_class;
1353         case CEE_LDELEM_I8:
1354         case CEE_STELEM_I8:
1355                 return mono_defaults.int64_class;
1356         case CEE_LDELEM_R4:
1357         case CEE_STELEM_R4:
1358                 return mono_defaults.single_class;
1359         case CEE_LDELEM_R8:
1360         case CEE_STELEM_R8:
1361                 return mono_defaults.double_class;
1362         case CEE_LDELEM_REF:
1363         case CEE_STELEM_REF:
1364                 return mono_defaults.object_class;
1365         default:
1366                 g_assert_not_reached ();
1367         }
1368         return NULL;
1369 }
1370
1371 /*
1372  * We try to share variables when possible
1373  */
1374 static MonoInst *
1375 mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
1376 {
1377         MonoInst *res;
1378         int pos, vnum;
1379
1380         /* inlining can result in deeper stacks */ 
1381         if (slot >= cfg->header->max_stack)
1382                 return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1383
1384         pos = ins->type - 1 + slot * STACK_MAX;
1385
1386         switch (ins->type) {
1387         case STACK_I4:
1388         case STACK_I8:
1389         case STACK_R8:
1390         case STACK_PTR:
1391         case STACK_MP:
1392         case STACK_OBJ:
1393                 if ((vnum = cfg->intvars [pos]))
1394                         return cfg->varinfo [vnum];
1395                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1396                 cfg->intvars [pos] = res->inst_c0;
1397                 break;
1398         default:
1399                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1400         }
1401         return res;
1402 }
1403
1404 static void
1405 mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
1406 {
1407         /* 
1408          * Don't use this if a generic_context is set, since that means AOT can't
1409          * look up the method using just the image+token.
1410          * table == 0 means this is a reference made from a wrapper.
1411          */
1412         if (cfg->compile_aot && !cfg->generic_context && (mono_metadata_token_table (token) > 0)) {
1413                 MonoJumpInfoToken *jump_info_token = (MonoJumpInfoToken *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
1414                 jump_info_token->image = image;
1415                 jump_info_token->token = token;
1416                 g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
1417         }
1418 }
1419
1420 /*
1421  * This function is called to handle items that are left on the evaluation stack
1422  * at basic block boundaries. What happens is that we save the values to local variables
1423  * and we reload them later when first entering the target basic block (with the
1424  * handle_loaded_temps () function).
1425  * A single joint point will use the same variables (stored in the array bb->out_stack or
1426  * bb->in_stack, if the basic block is before or after the joint point).
1427  *
1428  * This function needs to be called _before_ emitting the last instruction of
1429  * the bb (i.e. before emitting a branch).
1430  * If the stack merge fails at a join point, cfg->unverifiable is set.
1431  */
1432 static void
1433 handle_stack_args (MonoCompile *cfg, MonoInst **sp, int count)
1434 {
1435         int i, bindex;
1436         MonoBasicBlock *bb = cfg->cbb;
1437         MonoBasicBlock *outb;
1438         MonoInst *inst, **locals;
1439         gboolean found;
1440
1441         if (!count)
1442                 return;
1443         if (cfg->verbose_level > 3)
1444                 printf ("%d item(s) on exit from B%d\n", count, bb->block_num);
1445         if (!bb->out_scount) {
1446                 bb->out_scount = count;
1447                 //printf ("bblock %d has out:", bb->block_num);
1448                 found = FALSE;
1449                 for (i = 0; i < bb->out_count; ++i) {
1450                         outb = bb->out_bb [i];
1451                         /* exception handlers are linked, but they should not be considered for stack args */
1452                         if (outb->flags & BB_EXCEPTION_HANDLER)
1453                                 continue;
1454                         //printf (" %d", outb->block_num);
1455                         if (outb->in_stack) {
1456                                 found = TRUE;
1457                                 bb->out_stack = outb->in_stack;
1458                                 break;
1459                         }
1460                 }
1461                 //printf ("\n");
1462                 if (!found) {
1463                         bb->out_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1464                         for (i = 0; i < count; ++i) {
1465                                 /* 
1466                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
1467                                  * stack slot and if they are of the same type.
1468                                  * This won't cause conflicts since if 'local' is used to 
1469                                  * store one of the values in the in_stack of a bblock, then
1470                                  * the same variable will be used for the same outgoing stack 
1471                                  * slot as well. 
1472                                  * This doesn't work when inlining methods, since the bblocks
1473                                  * in the inlined methods do not inherit their in_stack from
1474                                  * the bblock they are inlined to. See bug #58863 for an
1475                                  * example.
1476                                  */
1477                                 if (cfg->inlined_method)
1478                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1479                                 else
1480                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
1481                         }
1482                 }
1483         }
1484
1485         for (i = 0; i < bb->out_count; ++i) {
1486                 outb = bb->out_bb [i];
1487                 /* exception handlers are linked, but they should not be considered for stack args */
1488                 if (outb->flags & BB_EXCEPTION_HANDLER)
1489                         continue;
1490                 if (outb->in_scount) {
1491                         if (outb->in_scount != bb->out_scount) {
1492                                 cfg->unverifiable = TRUE;
1493                                 return;
1494                         }
1495                         continue; /* check they are the same locals */
1496                 }
1497                 outb->in_scount = count;
1498                 outb->in_stack = bb->out_stack;
1499         }
1500
1501         locals = bb->out_stack;
1502         cfg->cbb = bb;
1503         for (i = 0; i < count; ++i) {
1504                 EMIT_NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
1505                 inst->cil_code = sp [i]->cil_code;
1506                 sp [i] = locals [i];
1507                 if (cfg->verbose_level > 3)
1508                         printf ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
1509         }
1510
1511         /*
1512          * It is possible that the out bblocks already have in_stack assigned, and
1513          * the in_stacks differ. In this case, we will store to all the different 
1514          * in_stacks.
1515          */
1516
1517         found = TRUE;
1518         bindex = 0;
1519         while (found) {
1520                 /* Find a bblock which has a different in_stack */
1521                 found = FALSE;
1522                 while (bindex < bb->out_count) {
1523                         outb = bb->out_bb [bindex];
1524                         /* exception handlers are linked, but they should not be considered for stack args */
1525                         if (outb->flags & BB_EXCEPTION_HANDLER) {
1526                                 bindex++;
1527                                 continue;
1528                         }
1529                         if (outb->in_stack != locals) {
1530                                 for (i = 0; i < count; ++i) {
1531                                         EMIT_NEW_TEMPSTORE (cfg, inst, outb->in_stack [i]->inst_c0, sp [i]);
1532                                         inst->cil_code = sp [i]->cil_code;
1533                                         sp [i] = locals [i];
1534                                         if (cfg->verbose_level > 3)
1535                                                 printf ("storing %d to temp %d\n", i, (int)outb->in_stack [i]->inst_c0);
1536                                 }
1537                                 locals = outb->in_stack;
1538                                 found = TRUE;
1539                                 break;
1540                         }
1541                         bindex ++;
1542                 }
1543         }
1544 }
1545
1546 static MonoInst*
1547 emit_runtime_constant (MonoCompile *cfg, MonoJumpInfoType patch_type, gpointer data)
1548 {
1549         MonoInst *ins;
1550
1551         if (cfg->compile_aot) {
1552                 EMIT_NEW_AOTCONST (cfg, ins, patch_type, data);
1553         } else {
1554                 MonoJumpInfo ji;
1555                 gpointer target;
1556                 MonoError error;
1557
1558                 ji.type = patch_type;
1559                 ji.data.target = data;
1560                 target = mono_resolve_patch_target (NULL, cfg->domain, NULL, &ji, FALSE, &error);
1561                 mono_error_assert_ok (&error);
1562
1563                 EMIT_NEW_PCONST (cfg, ins, target);
1564         }
1565         return ins;
1566 }
1567
1568 static void
1569 mini_emit_interface_bitmap_check (MonoCompile *cfg, int intf_bit_reg, int base_reg, int offset, MonoClass *klass)
1570 {
1571         int ibitmap_reg = alloc_preg (cfg);
1572 #ifdef COMPRESSED_INTERFACE_BITMAP
1573         MonoInst *args [2];
1574         MonoInst *res, *ins;
1575         NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, ibitmap_reg, base_reg, offset);
1576         MONO_ADD_INS (cfg->cbb, ins);
1577         args [0] = ins;
1578         args [1] = emit_runtime_constant (cfg, MONO_PATCH_INFO_IID, klass);
1579         res = mono_emit_jit_icall (cfg, mono_class_interface_match, args);
1580         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, intf_bit_reg, res->dreg);
1581 #else
1582         int ibitmap_byte_reg = alloc_preg (cfg);
1583
1584         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, base_reg, offset);
1585
1586         if (cfg->compile_aot) {
1587                 int iid_reg = alloc_preg (cfg);
1588                 int shifted_iid_reg = alloc_preg (cfg);
1589                 int ibitmap_byte_address_reg = alloc_preg (cfg);
1590                 int masked_iid_reg = alloc_preg (cfg);
1591                 int iid_one_bit_reg = alloc_preg (cfg);
1592                 int iid_bit_reg = alloc_preg (cfg);
1593                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1594                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, shifted_iid_reg, iid_reg, 3);
1595                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ibitmap_byte_address_reg, ibitmap_reg, shifted_iid_reg);
1596                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, ibitmap_byte_reg, ibitmap_byte_address_reg, 0);
1597                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, masked_iid_reg, iid_reg, 7);
1598                 MONO_EMIT_NEW_ICONST (cfg, iid_one_bit_reg, 1);
1599                 MONO_EMIT_NEW_BIALU (cfg, OP_ISHL, iid_bit_reg, iid_one_bit_reg, masked_iid_reg);
1600                 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, intf_bit_reg, ibitmap_byte_reg, iid_bit_reg);
1601         } else {
1602                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, klass->interface_id >> 3);
1603                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (klass->interface_id & 7));
1604         }
1605 #endif
1606 }
1607
1608 /* 
1609  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoClass
1610  * stored in "klass_reg" implements the interface "klass".
1611  */
1612 static void
1613 mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass_reg, MonoClass *klass)
1614 {
1615         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, interface_bitmap), klass);
1616 }
1617
1618 /* 
1619  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoVTable
1620  * stored in "vtable_reg" implements the interface "klass".
1621  */
1622 static void
1623 mini_emit_load_intf_bit_reg_vtable (MonoCompile *cfg, int intf_bit_reg, int vtable_reg, MonoClass *klass)
1624 {
1625         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, interface_bitmap), klass);
1626 }
1627
1628 /* 
1629  * Emit code which checks whenever the interface id of @klass is smaller than
1630  * than the value given by max_iid_reg.
1631 */
1632 static void
1633 mini_emit_max_iid_check (MonoCompile *cfg, int max_iid_reg, MonoClass *klass,
1634                                                  MonoBasicBlock *false_target)
1635 {
1636         if (cfg->compile_aot) {
1637                 int iid_reg = alloc_preg (cfg);
1638                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1639                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, max_iid_reg, iid_reg);
1640         }
1641         else
1642                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, max_iid_reg, klass->interface_id);
1643         if (false_target)
1644                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1645         else
1646                 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1647 }
1648
1649 /* Same as above, but obtains max_iid from a vtable */
1650 static void
1651 mini_emit_max_iid_check_vtable (MonoCompile *cfg, int vtable_reg, MonoClass *klass,
1652                                                                  MonoBasicBlock *false_target)
1653 {
1654         int max_iid_reg = alloc_preg (cfg);
1655                 
1656         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, max_interface_id));
1657         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1658 }
1659
1660 /* Same as above, but obtains max_iid from a klass */
1661 static void
1662 mini_emit_max_iid_check_class (MonoCompile *cfg, int klass_reg, MonoClass *klass,
1663                                                                  MonoBasicBlock *false_target)
1664 {
1665         int max_iid_reg = alloc_preg (cfg);
1666
1667         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, max_interface_id));
1668         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1669 }
1670
1671 static void
1672 mini_emit_isninst_cast_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_ins, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1673 {
1674         int idepth_reg = alloc_preg (cfg);
1675         int stypes_reg = alloc_preg (cfg);
1676         int stype = alloc_preg (cfg);
1677
1678         mono_class_setup_supertypes (klass);
1679
1680         if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1681                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1682                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1683                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1684         }
1685         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1686         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1687         if (klass_ins) {
1688                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, klass_ins->dreg);
1689         } else if (cfg->compile_aot) {
1690                 int const_reg = alloc_preg (cfg);
1691                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1692                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, const_reg);
1693         } else {
1694                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, stype, klass);
1695         }
1696         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, true_target);
1697 }
1698
1699 static void
1700 mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1701 {
1702         mini_emit_isninst_cast_inst (cfg, klass_reg, klass, NULL, false_target, true_target);
1703 }
1704
1705 static void
1706 mini_emit_iface_cast (MonoCompile *cfg, int vtable_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1707 {
1708         int intf_reg = alloc_preg (cfg);
1709
1710         mini_emit_max_iid_check_vtable (cfg, vtable_reg, klass, false_target);
1711         mini_emit_load_intf_bit_reg_vtable (cfg, intf_reg, vtable_reg, klass);
1712         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_reg, 0);
1713         if (true_target)
1714                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1715         else
1716                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");               
1717 }
1718
1719 /*
1720  * Variant of the above that takes a register to the class, not the vtable.
1721  */
1722 static void
1723 mini_emit_iface_class_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1724 {
1725         int intf_bit_reg = alloc_preg (cfg);
1726
1727         mini_emit_max_iid_check_class (cfg, klass_reg, klass, false_target);
1728         mini_emit_load_intf_bit_reg_class (cfg, intf_bit_reg, klass_reg, klass);
1729         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_bit_reg, 0);
1730         if (true_target)
1731                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1732         else
1733                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
1734 }
1735
1736 static inline void
1737 mini_emit_class_check_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_inst)
1738 {
1739         if (klass_inst) {
1740                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_inst->dreg);
1741         } else {
1742                 MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
1743                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, ins->dreg);
1744         }
1745         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1746 }
1747
1748 static inline void
1749 mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass)
1750 {
1751         mini_emit_class_check_inst (cfg, klass_reg, klass, NULL);
1752 }
1753
1754 static inline void
1755 mini_emit_class_check_branch (MonoCompile *cfg, int klass_reg, MonoClass *klass, int branch_op, MonoBasicBlock *target)
1756 {
1757         if (cfg->compile_aot) {
1758                 int const_reg = alloc_preg (cfg);
1759                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1760                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1761         } else {
1762                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1763         }
1764         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, branch_op, target);
1765 }
1766
1767 static void
1768 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null);
1769         
1770 static void
1771 mini_emit_castclass_inst (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoInst *klass_inst, MonoBasicBlock *object_is_null)
1772 {
1773         if (klass->rank) {
1774                 int rank_reg = alloc_preg (cfg);
1775                 int eclass_reg = alloc_preg (cfg);
1776
1777                 g_assert (!klass_inst);
1778                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, rank));
1779                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
1780                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1781                 //              MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
1782                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
1783                 if (klass->cast_class == mono_defaults.object_class) {
1784                         int parent_reg = alloc_preg (cfg);
1785                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
1786                         mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, object_is_null);
1787                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1788                 } else if (klass->cast_class == mono_defaults.enum_class->parent) {
1789                         mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, object_is_null);
1790                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1791                 } else if (klass->cast_class == mono_defaults.enum_class) {
1792                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1793                 } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1794                         mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, NULL, NULL);
1795                 } else {
1796                         // Pass -1 as obj_reg to skip the check below for arrays of arrays
1797                         mini_emit_castclass (cfg, -1, eclass_reg, klass->cast_class, object_is_null);
1798                 }
1799
1800                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY) && (obj_reg != -1)) {
1801                         /* Check that the object is a vector too */
1802                         int bounds_reg = alloc_preg (cfg);
1803                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
1804                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
1805                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1806                 }
1807         } else {
1808                 int idepth_reg = alloc_preg (cfg);
1809                 int stypes_reg = alloc_preg (cfg);
1810                 int stype = alloc_preg (cfg);
1811
1812                 mono_class_setup_supertypes (klass);
1813
1814                 if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1815                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1816                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1817                         MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1818                 }
1819                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1820                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1821                 mini_emit_class_check_inst (cfg, stype, klass, klass_inst);
1822         }
1823 }
1824
1825 static void
1826 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null)
1827 {
1828         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, NULL, object_is_null);
1829 }
1830
1831 static void 
1832 mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align)
1833 {
1834         int val_reg;
1835
1836         g_assert (val == 0);
1837
1838         if (align == 0)
1839                 align = 4;
1840
1841         if ((size <= SIZEOF_REGISTER) && (size <= align)) {
1842                 switch (size) {
1843                 case 1:
1844                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, destreg, offset, val);
1845                         return;
1846                 case 2:
1847                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI2_MEMBASE_IMM, destreg, offset, val);
1848                         return;
1849                 case 4:
1850                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI4_MEMBASE_IMM, destreg, offset, val);
1851                         return;
1852 #if SIZEOF_REGISTER == 8
1853                 case 8:
1854                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI8_MEMBASE_IMM, destreg, offset, val);
1855                         return;
1856 #endif
1857                 }
1858         }
1859
1860         val_reg = alloc_preg (cfg);
1861
1862         if (SIZEOF_REGISTER == 8)
1863                 MONO_EMIT_NEW_I8CONST (cfg, val_reg, val);
1864         else
1865                 MONO_EMIT_NEW_ICONST (cfg, val_reg, val);
1866
1867         if (align < 4) {
1868                 /* This could be optimized further if neccesary */
1869                 while (size >= 1) {
1870                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1871                         offset += 1;
1872                         size -= 1;
1873                 }
1874                 return;
1875         }       
1876
1877         if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
1878                 if (offset % 8) {
1879                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1880                         offset += 4;
1881                         size -= 4;
1882                 }
1883                 while (size >= 8) {
1884                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, offset, val_reg);
1885                         offset += 8;
1886                         size -= 8;
1887                 }
1888         }       
1889
1890         while (size >= 4) {
1891                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1892                 offset += 4;
1893                 size -= 4;
1894         }
1895         while (size >= 2) {
1896                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, val_reg);
1897                 offset += 2;
1898                 size -= 2;
1899         }
1900         while (size >= 1) {
1901                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1902                 offset += 1;
1903                 size -= 1;
1904         }
1905 }
1906
1907 void 
1908 mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align)
1909 {
1910         int cur_reg;
1911
1912         if (align == 0)
1913                 align = 4;
1914
1915         /*FIXME arbitrary hack to avoid unbound code expansion.*/
1916         g_assert (size < 10000);
1917
1918         if (align < 4) {
1919                 /* This could be optimized further if neccesary */
1920                 while (size >= 1) {
1921                         cur_reg = alloc_preg (cfg);
1922                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1923                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1924                         doffset += 1;
1925                         soffset += 1;
1926                         size -= 1;
1927                 }
1928         }
1929
1930         if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
1931                 while (size >= 8) {
1932                         cur_reg = alloc_preg (cfg);
1933                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI8_MEMBASE, cur_reg, srcreg, soffset);
1934                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, doffset, cur_reg);
1935                         doffset += 8;
1936                         soffset += 8;
1937                         size -= 8;
1938                 }
1939         }       
1940
1941         while (size >= 4) {
1942                 cur_reg = alloc_preg (cfg);
1943                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, cur_reg, srcreg, soffset);
1944                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, doffset, cur_reg);
1945                 doffset += 4;
1946                 soffset += 4;
1947                 size -= 4;
1948         }
1949         while (size >= 2) {
1950                 cur_reg = alloc_preg (cfg);
1951                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, cur_reg, srcreg, soffset);
1952                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, doffset, cur_reg);
1953                 doffset += 2;
1954                 soffset += 2;
1955                 size -= 2;
1956         }
1957         while (size >= 1) {
1958                 cur_reg = alloc_preg (cfg);
1959                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1960                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1961                 doffset += 1;
1962                 soffset += 1;
1963                 size -= 1;
1964         }
1965 }
1966
1967 static void
1968 emit_tls_set (MonoCompile *cfg, int sreg1, MonoTlsKey tls_key)
1969 {
1970         MonoInst *ins, *c;
1971
1972         if (cfg->compile_aot) {
1973                 EMIT_NEW_TLS_OFFSETCONST (cfg, c, tls_key);
1974                 MONO_INST_NEW (cfg, ins, OP_TLS_SET_REG);
1975                 ins->sreg1 = sreg1;
1976                 ins->sreg2 = c->dreg;
1977                 MONO_ADD_INS (cfg->cbb, ins);
1978         } else {
1979                 MONO_INST_NEW (cfg, ins, OP_TLS_SET);
1980                 ins->sreg1 = sreg1;
1981                 ins->inst_offset = mini_get_tls_offset (tls_key);
1982                 MONO_ADD_INS (cfg->cbb, ins);
1983         }
1984 }
1985
1986 /*
1987  * emit_push_lmf:
1988  *
1989  *   Emit IR to push the current LMF onto the LMF stack.
1990  */
1991 static void
1992 emit_push_lmf (MonoCompile *cfg)
1993 {
1994         /*
1995          * Emit IR to push the LMF:
1996          * lmf_addr = <lmf_addr from tls>
1997          * lmf->lmf_addr = lmf_addr
1998          * lmf->prev_lmf = *lmf_addr
1999          * *lmf_addr = lmf
2000          */
2001         int lmf_reg, prev_lmf_reg;
2002         MonoInst *ins, *lmf_ins;
2003
2004         if (!cfg->lmf_ir)
2005                 return;
2006
2007         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
2008                 /* Load current lmf */
2009                 lmf_ins = mono_get_lmf_intrinsic (cfg);
2010                 g_assert (lmf_ins);
2011                 MONO_ADD_INS (cfg->cbb, lmf_ins);
2012                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2013                 lmf_reg = ins->dreg;
2014                 /* Save previous_lmf */
2015                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), lmf_ins->dreg);
2016                 /* Set new LMF */
2017                 emit_tls_set (cfg, lmf_reg, TLS_KEY_LMF);
2018         } else {
2019                 /*
2020                  * Store lmf_addr in a variable, so it can be allocated to a global register.
2021                  */
2022                 if (!cfg->lmf_addr_var)
2023                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2024
2025 #ifdef HOST_WIN32
2026                 ins = mono_get_jit_tls_intrinsic (cfg);
2027                 if (ins) {
2028                         int jit_tls_dreg = ins->dreg;
2029
2030                         MONO_ADD_INS (cfg->cbb, ins);
2031                         lmf_reg = alloc_preg (cfg);
2032                         EMIT_NEW_BIALU_IMM (cfg, lmf_ins, OP_PADD_IMM, lmf_reg, jit_tls_dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2033                 } else {
2034                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2035                 }
2036 #else
2037                 lmf_ins = mono_get_lmf_addr_intrinsic (cfg);
2038                 if (lmf_ins) {
2039                         MONO_ADD_INS (cfg->cbb, lmf_ins);
2040                 } else {
2041 #ifdef TARGET_IOS
2042                         MonoInst *args [16], *jit_tls_ins, *ins;
2043
2044                         /* Inline mono_get_lmf_addr () */
2045                         /* jit_tls = pthread_getspecific (mono_jit_tls_id); lmf_addr = &jit_tls->lmf; */
2046
2047                         /* Load mono_jit_tls_id */
2048                         if (cfg->compile_aot)
2049                                 EMIT_NEW_AOTCONST (cfg, args [0], MONO_PATCH_INFO_JIT_TLS_ID, NULL);
2050                         else
2051                                 EMIT_NEW_ICONST (cfg, args [0], mono_jit_tls_id);
2052                         /* call pthread_getspecific () */
2053                         jit_tls_ins = mono_emit_jit_icall (cfg, pthread_getspecific, args);
2054                         /* lmf_addr = &jit_tls->lmf */
2055                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, cfg->lmf_addr_var->dreg, jit_tls_ins->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2056                         lmf_ins = ins;
2057 #else
2058                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2059 #endif
2060                 }
2061 #endif
2062                 lmf_ins->dreg = cfg->lmf_addr_var->dreg;
2063
2064                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2065                 lmf_reg = ins->dreg;
2066
2067                 prev_lmf_reg = alloc_preg (cfg);
2068                 /* Save previous_lmf */
2069                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, cfg->lmf_addr_var->dreg, 0);
2070                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), prev_lmf_reg);
2071                 /* Set new lmf */
2072                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, cfg->lmf_addr_var->dreg, 0, lmf_reg);
2073         }
2074 }
2075
2076 /*
2077  * emit_pop_lmf:
2078  *
2079  *   Emit IR to pop the current LMF from the LMF stack.
2080  */
2081 static void
2082 emit_pop_lmf (MonoCompile *cfg)
2083 {
2084         int lmf_reg, lmf_addr_reg, prev_lmf_reg;
2085         MonoInst *ins;
2086
2087         if (!cfg->lmf_ir)
2088                 return;
2089
2090         EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2091         lmf_reg = ins->dreg;
2092
2093         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
2094                 /* Load previous_lmf */
2095                 prev_lmf_reg = alloc_preg (cfg);
2096                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2097                 /* Set new LMF */
2098                 emit_tls_set (cfg, prev_lmf_reg, TLS_KEY_LMF);
2099         } else {
2100                 /*
2101                  * Emit IR to pop the LMF:
2102                  * *(lmf->lmf_addr) = lmf->prev_lmf
2103                  */
2104                 /* This could be called before emit_push_lmf () */
2105                 if (!cfg->lmf_addr_var)
2106                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2107                 lmf_addr_reg = cfg->lmf_addr_var->dreg;
2108
2109                 prev_lmf_reg = alloc_preg (cfg);
2110                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2111                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_addr_reg, 0, prev_lmf_reg);
2112         }
2113 }
2114
2115 static void
2116 emit_instrumentation_call (MonoCompile *cfg, void *func)
2117 {
2118         MonoInst *iargs [1];
2119
2120         /*
2121          * Avoid instrumenting inlined methods since it can
2122          * distort profiling results.
2123          */
2124         if (cfg->method != cfg->current_method)
2125                 return;
2126
2127         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
2128                 EMIT_NEW_METHODCONST (cfg, iargs [0], cfg->method);
2129                 mono_emit_jit_icall (cfg, func, iargs);
2130         }
2131 }
2132
2133 static int
2134 ret_type_to_call_opcode (MonoCompile *cfg, MonoType *type, int calli, int virt)
2135 {
2136 handle_enum:
2137         type = mini_get_underlying_type (type);
2138         switch (type->type) {
2139         case MONO_TYPE_VOID:
2140                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALL_MEMBASE: OP_VOIDCALL;
2141         case MONO_TYPE_I1:
2142         case MONO_TYPE_U1:
2143         case MONO_TYPE_I2:
2144         case MONO_TYPE_U2:
2145         case MONO_TYPE_I4:
2146         case MONO_TYPE_U4:
2147                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2148         case MONO_TYPE_I:
2149         case MONO_TYPE_U:
2150         case MONO_TYPE_PTR:
2151         case MONO_TYPE_FNPTR:
2152                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2153         case MONO_TYPE_CLASS:
2154         case MONO_TYPE_STRING:
2155         case MONO_TYPE_OBJECT:
2156         case MONO_TYPE_SZARRAY:
2157         case MONO_TYPE_ARRAY:    
2158                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2159         case MONO_TYPE_I8:
2160         case MONO_TYPE_U8:
2161                 return calli? OP_LCALL_REG: virt? OP_LCALL_MEMBASE: OP_LCALL;
2162         case MONO_TYPE_R4:
2163                 if (cfg->r4fp)
2164                         return calli? OP_RCALL_REG: virt? OP_RCALL_MEMBASE: OP_RCALL;
2165                 else
2166                         return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2167         case MONO_TYPE_R8:
2168                 return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2169         case MONO_TYPE_VALUETYPE:
2170                 if (type->data.klass->enumtype) {
2171                         type = mono_class_enum_basetype (type->data.klass);
2172                         goto handle_enum;
2173                 } else
2174                         return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2175         case MONO_TYPE_TYPEDBYREF:
2176                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2177         case MONO_TYPE_GENERICINST:
2178                 type = &type->data.generic_class->container_class->byval_arg;
2179                 goto handle_enum;
2180         case MONO_TYPE_VAR:
2181         case MONO_TYPE_MVAR:
2182                 /* gsharedvt */
2183                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2184         default:
2185                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
2186         }
2187         return -1;
2188 }
2189
2190 //XXX this ignores if t is byref
2191 #define MONO_TYPE_IS_PRIMITIVE_SCALAR(t) ((((((t)->type >= MONO_TYPE_BOOLEAN && (t)->type <= MONO_TYPE_U8) || ((t)->type >= MONO_TYPE_I && (t)->type <= MONO_TYPE_U)))))
2192
2193 /*
2194  * target_type_is_incompatible:
2195  * @cfg: MonoCompile context
2196  *
2197  * Check that the item @arg on the evaluation stack can be stored
2198  * in the target type (can be a local, or field, etc).
2199  * The cfg arg can be used to check if we need verification or just
2200  * validity checks.
2201  *
2202  * Returns: non-0 value if arg can't be stored on a target.
2203  */
2204 static int
2205 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
2206 {
2207         MonoType *simple_type;
2208         MonoClass *klass;
2209
2210         if (target->byref) {
2211                 /* FIXME: check that the pointed to types match */
2212                 if (arg->type == STACK_MP) {
2213                         if (cfg->verbose_level) printf ("ok\n");
2214                         /* This is needed to handle gshared types + ldaddr. We lower the types so we can handle enums and other typedef-like types. */
2215                         MonoClass *target_class_lowered = mono_class_from_mono_type (mini_get_underlying_type (&mono_class_from_mono_type (target)->byval_arg));
2216                         MonoClass *source_class_lowered = mono_class_from_mono_type (mini_get_underlying_type (&arg->klass->byval_arg));
2217
2218                         /* if the target is native int& or same type */
2219                         if (target->type == MONO_TYPE_I || target_class_lowered == source_class_lowered)
2220                                 return 0;
2221
2222                         /* Both are primitive type byrefs and the source points to a larger type that the destination */
2223                         if (MONO_TYPE_IS_PRIMITIVE_SCALAR (&target_class_lowered->byval_arg) && MONO_TYPE_IS_PRIMITIVE_SCALAR (&source_class_lowered->byval_arg) &&
2224                                 mono_class_instance_size (target_class_lowered) <= mono_class_instance_size (source_class_lowered))
2225                                 return 0;
2226                         return 1;
2227                 }
2228                 if (arg->type == STACK_PTR)
2229                         return 0;
2230                 return 1;
2231         }
2232
2233         simple_type = mini_get_underlying_type (target);
2234         switch (simple_type->type) {
2235         case MONO_TYPE_VOID:
2236                 return 1;
2237         case MONO_TYPE_I1:
2238         case MONO_TYPE_U1:
2239         case MONO_TYPE_I2:
2240         case MONO_TYPE_U2:
2241         case MONO_TYPE_I4:
2242         case MONO_TYPE_U4:
2243                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2244                         return 1;
2245                 return 0;
2246         case MONO_TYPE_PTR:
2247                 /* STACK_MP is needed when setting pinned locals */
2248                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2249                         return 1;
2250                 return 0;
2251         case MONO_TYPE_I:
2252         case MONO_TYPE_U:
2253         case MONO_TYPE_FNPTR:
2254                 /* 
2255                  * Some opcodes like ldloca returns 'transient pointers' which can be stored in
2256                  * in native int. (#688008).
2257                  */
2258                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2259                         return 1;
2260                 return 0;
2261         case MONO_TYPE_CLASS:
2262         case MONO_TYPE_STRING:
2263         case MONO_TYPE_OBJECT:
2264         case MONO_TYPE_SZARRAY:
2265         case MONO_TYPE_ARRAY:    
2266                 if (arg->type != STACK_OBJ)
2267                         return 1;
2268                 /* FIXME: check type compatibility */
2269                 return 0;
2270         case MONO_TYPE_I8:
2271         case MONO_TYPE_U8:
2272                 if (arg->type != STACK_I8)
2273                         return 1;
2274                 return 0;
2275         case MONO_TYPE_R4:
2276                 if (arg->type != cfg->r4_stack_type)
2277                         return 1;
2278                 return 0;
2279         case MONO_TYPE_R8:
2280                 if (arg->type != STACK_R8)
2281                         return 1;
2282                 return 0;
2283         case MONO_TYPE_VALUETYPE:
2284                 if (arg->type != STACK_VTYPE)
2285                         return 1;
2286                 klass = mono_class_from_mono_type (simple_type);
2287                 if (klass != arg->klass)
2288                         return 1;
2289                 return 0;
2290         case MONO_TYPE_TYPEDBYREF:
2291                 if (arg->type != STACK_VTYPE)
2292                         return 1;
2293                 klass = mono_class_from_mono_type (simple_type);
2294                 if (klass != arg->klass)
2295                         return 1;
2296                 return 0;
2297         case MONO_TYPE_GENERICINST:
2298                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
2299                         MonoClass *target_class;
2300                         if (arg->type != STACK_VTYPE)
2301                                 return 1;
2302                         klass = mono_class_from_mono_type (simple_type);
2303                         target_class = mono_class_from_mono_type (target);
2304                         /* The second cases is needed when doing partial sharing */
2305                         if (klass != arg->klass && target_class != arg->klass && target_class != mono_class_from_mono_type (mini_get_underlying_type (&arg->klass->byval_arg)))
2306                                 return 1;
2307                         return 0;
2308                 } else {
2309                         if (arg->type != STACK_OBJ)
2310                                 return 1;
2311                         /* FIXME: check type compatibility */
2312                         return 0;
2313                 }
2314         case MONO_TYPE_VAR:
2315         case MONO_TYPE_MVAR:
2316                 g_assert (cfg->gshared);
2317                 if (mini_type_var_is_vt (simple_type)) {
2318                         if (arg->type != STACK_VTYPE)
2319                                 return 1;
2320                 } else {
2321                         if (arg->type != STACK_OBJ)
2322                                 return 1;
2323                 }
2324                 return 0;
2325         default:
2326                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
2327         }
2328         return 1;
2329 }
2330
2331 /*
2332  * Prepare arguments for passing to a function call.
2333  * Return a non-zero value if the arguments can't be passed to the given
2334  * signature.
2335  * The type checks are not yet complete and some conversions may need
2336  * casts on 32 or 64 bit architectures.
2337  *
2338  * FIXME: implement this using target_type_is_incompatible ()
2339  */
2340 static int
2341 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2342 {
2343         MonoType *simple_type;
2344         int i;
2345
2346         if (sig->hasthis) {
2347                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2348                         return 1;
2349                 args++;
2350         }
2351         for (i = 0; i < sig->param_count; ++i) {
2352                 if (sig->params [i]->byref) {
2353                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2354                                 return 1;
2355                         continue;
2356                 }
2357                 simple_type = mini_get_underlying_type (sig->params [i]);
2358 handle_enum:
2359                 switch (simple_type->type) {
2360                 case MONO_TYPE_VOID:
2361                         return 1;
2362                         continue;
2363                 case MONO_TYPE_I1:
2364                 case MONO_TYPE_U1:
2365                 case MONO_TYPE_I2:
2366                 case MONO_TYPE_U2:
2367                 case MONO_TYPE_I4:
2368                 case MONO_TYPE_U4:
2369                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2370                                 return 1;
2371                         continue;
2372                 case MONO_TYPE_I:
2373                 case MONO_TYPE_U:
2374                 case MONO_TYPE_PTR:
2375                 case MONO_TYPE_FNPTR:
2376                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2377                                 return 1;
2378                         continue;
2379                 case MONO_TYPE_CLASS:
2380                 case MONO_TYPE_STRING:
2381                 case MONO_TYPE_OBJECT:
2382                 case MONO_TYPE_SZARRAY:
2383                 case MONO_TYPE_ARRAY:    
2384                         if (args [i]->type != STACK_OBJ)
2385                                 return 1;
2386                         continue;
2387                 case MONO_TYPE_I8:
2388                 case MONO_TYPE_U8:
2389                         if (args [i]->type != STACK_I8)
2390                                 return 1;
2391                         continue;
2392                 case MONO_TYPE_R4:
2393                         if (args [i]->type != cfg->r4_stack_type)
2394                                 return 1;
2395                         continue;
2396                 case MONO_TYPE_R8:
2397                         if (args [i]->type != STACK_R8)
2398                                 return 1;
2399                         continue;
2400                 case MONO_TYPE_VALUETYPE:
2401                         if (simple_type->data.klass->enumtype) {
2402                                 simple_type = mono_class_enum_basetype (simple_type->data.klass);
2403                                 goto handle_enum;
2404                         }
2405                         if (args [i]->type != STACK_VTYPE)
2406                                 return 1;
2407                         continue;
2408                 case MONO_TYPE_TYPEDBYREF:
2409                         if (args [i]->type != STACK_VTYPE)
2410                                 return 1;
2411                         continue;
2412                 case MONO_TYPE_GENERICINST:
2413                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2414                         goto handle_enum;
2415                 case MONO_TYPE_VAR:
2416                 case MONO_TYPE_MVAR:
2417                         /* gsharedvt */
2418                         if (args [i]->type != STACK_VTYPE)
2419                                 return 1;
2420                         continue;
2421                 default:
2422                         g_error ("unknown type 0x%02x in check_call_signature",
2423                                  simple_type->type);
2424                 }
2425         }
2426         return 0;
2427 }
2428
2429 static int
2430 callvirt_to_call (int opcode)
2431 {
2432         switch (opcode) {
2433         case OP_CALL_MEMBASE:
2434                 return OP_CALL;
2435         case OP_VOIDCALL_MEMBASE:
2436                 return OP_VOIDCALL;
2437         case OP_FCALL_MEMBASE:
2438                 return OP_FCALL;
2439         case OP_RCALL_MEMBASE:
2440                 return OP_RCALL;
2441         case OP_VCALL_MEMBASE:
2442                 return OP_VCALL;
2443         case OP_LCALL_MEMBASE:
2444                 return OP_LCALL;
2445         default:
2446                 g_assert_not_reached ();
2447         }
2448
2449         return -1;
2450 }
2451
2452 static int
2453 callvirt_to_call_reg (int opcode)
2454 {
2455         switch (opcode) {
2456         case OP_CALL_MEMBASE:
2457                 return OP_CALL_REG;
2458         case OP_VOIDCALL_MEMBASE:
2459                 return OP_VOIDCALL_REG;
2460         case OP_FCALL_MEMBASE:
2461                 return OP_FCALL_REG;
2462         case OP_RCALL_MEMBASE:
2463                 return OP_RCALL_REG;
2464         case OP_VCALL_MEMBASE:
2465                 return OP_VCALL_REG;
2466         case OP_LCALL_MEMBASE:
2467                 return OP_LCALL_REG;
2468         default:
2469                 g_assert_not_reached ();
2470         }
2471
2472         return -1;
2473 }
2474
2475 /* Either METHOD or IMT_ARG needs to be set */
2476 static void
2477 emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoMethod *method, MonoInst *imt_arg)
2478 {
2479         int method_reg;
2480
2481         if (COMPILE_LLVM (cfg)) {
2482                 if (imt_arg) {
2483                         method_reg = alloc_preg (cfg);
2484                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2485                 } else {
2486                         MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHODCONST, method);
2487                         method_reg = ins->dreg;
2488                 }
2489
2490 #ifdef ENABLE_LLVM
2491                 call->imt_arg_reg = method_reg;
2492 #endif
2493                 mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2494                 return;
2495         }
2496
2497         if (imt_arg) {
2498                 method_reg = alloc_preg (cfg);
2499                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2500         } else {
2501                 MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHODCONST, method);
2502                 method_reg = ins->dreg;
2503         }
2504
2505         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2506 }
2507
2508 static MonoJumpInfo *
2509 mono_patch_info_new (MonoMemPool *mp, int ip, MonoJumpInfoType type, gconstpointer target)
2510 {
2511         MonoJumpInfo *ji = (MonoJumpInfo *)mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
2512
2513         ji->ip.i = ip;
2514         ji->type = type;
2515         ji->data.target = target;
2516
2517         return ji;
2518 }
2519
2520 static int
2521 mini_class_check_context_used (MonoCompile *cfg, MonoClass *klass)
2522 {
2523         if (cfg->gshared)
2524                 return mono_class_check_context_used (klass);
2525         else
2526                 return 0;
2527 }
2528
2529 static int
2530 mini_method_check_context_used (MonoCompile *cfg, MonoMethod *method)
2531 {
2532         if (cfg->gshared)
2533                 return mono_method_check_context_used (method);
2534         else
2535                 return 0;
2536 }
2537
2538 /*
2539  * check_method_sharing:
2540  *
2541  *   Check whenever the vtable or an mrgctx needs to be passed when calling CMETHOD.
2542  */
2543 static void
2544 check_method_sharing (MonoCompile *cfg, MonoMethod *cmethod, gboolean *out_pass_vtable, gboolean *out_pass_mrgctx)
2545 {
2546         gboolean pass_vtable = FALSE;
2547         gboolean pass_mrgctx = FALSE;
2548
2549         if (((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
2550                 (cmethod->klass->generic_class || cmethod->klass->generic_container)) {
2551                 gboolean sharable = FALSE;
2552
2553                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE))
2554                         sharable = TRUE;
2555
2556                 /*
2557                  * Pass vtable iff target method might
2558                  * be shared, which means that sharing
2559                  * is enabled for its class and its
2560                  * context is sharable (and it's not a
2561                  * generic method).
2562                  */
2563                 if (sharable && !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
2564                         pass_vtable = TRUE;
2565         }
2566
2567         if (mini_method_get_context (cmethod) &&
2568                 mini_method_get_context (cmethod)->method_inst) {
2569                 g_assert (!pass_vtable);
2570
2571                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE)) {
2572                         pass_mrgctx = TRUE;
2573                 } else {
2574                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (mono_method_signature (cmethod)))
2575                                 pass_mrgctx = TRUE;
2576                 }
2577         }
2578
2579         if (out_pass_vtable)
2580                 *out_pass_vtable = pass_vtable;
2581         if (out_pass_mrgctx)
2582                 *out_pass_mrgctx = pass_mrgctx;
2583 }
2584
2585 inline static MonoCallInst *
2586 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
2587                                          MonoInst **args, int calli, int virtual_, int tail, int rgctx, int unbox_trampoline)
2588 {
2589         MonoType *sig_ret;
2590         MonoCallInst *call;
2591 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2592         int i;
2593 #endif
2594
2595         if (cfg->llvm_only)
2596                 tail = FALSE;
2597
2598         if (tail) {
2599                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
2600
2601                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
2602         } else
2603                 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (cfg, sig->ret, calli, virtual_));
2604
2605         call->args = args;
2606         call->signature = sig;
2607         call->rgctx_reg = rgctx;
2608         sig_ret = mini_get_underlying_type (sig->ret);
2609
2610         type_to_eval_stack_type ((cfg), sig_ret, &call->inst);
2611
2612         if (tail) {
2613                 if (mini_type_is_vtype (sig_ret)) {
2614                         call->vret_var = cfg->vret_addr;
2615                         //g_assert_not_reached ();
2616                 }
2617         } else if (mini_type_is_vtype (sig_ret)) {
2618                 MonoInst *temp = mono_compile_create_var (cfg, sig_ret, OP_LOCAL);
2619                 MonoInst *loada;
2620
2621                 temp->backend.is_pinvoke = sig->pinvoke;
2622
2623                 /*
2624                  * We use a new opcode OP_OUTARG_VTRETADDR instead of LDADDR for emitting the
2625                  * address of return value to increase optimization opportunities.
2626                  * Before vtype decomposition, the dreg of the call ins itself represents the
2627                  * fact the call modifies the return value. After decomposition, the call will
2628                  * be transformed into one of the OP_VOIDCALL opcodes, and the VTRETADDR opcode
2629                  * will be transformed into an LDADDR.
2630                  */
2631                 MONO_INST_NEW (cfg, loada, OP_OUTARG_VTRETADDR);
2632                 loada->dreg = alloc_preg (cfg);
2633                 loada->inst_p0 = temp;
2634                 /* We reference the call too since call->dreg could change during optimization */
2635                 loada->inst_p1 = call;
2636                 MONO_ADD_INS (cfg->cbb, loada);
2637
2638                 call->inst.dreg = temp->dreg;
2639
2640                 call->vret_var = loada;
2641         } else if (!MONO_TYPE_IS_VOID (sig_ret))
2642                 call->inst.dreg = alloc_dreg (cfg, (MonoStackType)call->inst.type);
2643
2644 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2645         if (COMPILE_SOFT_FLOAT (cfg)) {
2646                 /* 
2647                  * If the call has a float argument, we would need to do an r8->r4 conversion using 
2648                  * an icall, but that cannot be done during the call sequence since it would clobber
2649                  * the call registers + the stack. So we do it before emitting the call.
2650                  */
2651                 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2652                         MonoType *t;
2653                         MonoInst *in = call->args [i];
2654
2655                         if (i >= sig->hasthis)
2656                                 t = sig->params [i - sig->hasthis];
2657                         else
2658                                 t = &mono_defaults.int_class->byval_arg;
2659                         t = mono_type_get_underlying_type (t);
2660
2661                         if (!t->byref && t->type == MONO_TYPE_R4) {
2662                                 MonoInst *iargs [1];
2663                                 MonoInst *conv;
2664
2665                                 iargs [0] = in;
2666                                 conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
2667
2668                                 /* The result will be in an int vreg */
2669                                 call->args [i] = conv;
2670                         }
2671                 }
2672         }
2673 #endif
2674
2675         call->need_unbox_trampoline = unbox_trampoline;
2676
2677 #ifdef ENABLE_LLVM
2678         if (COMPILE_LLVM (cfg))
2679                 mono_llvm_emit_call (cfg, call);
2680         else
2681                 mono_arch_emit_call (cfg, call);
2682 #else
2683         mono_arch_emit_call (cfg, call);
2684 #endif
2685
2686         cfg->param_area = MAX (cfg->param_area, call->stack_usage);
2687         cfg->flags |= MONO_CFG_HAS_CALLS;
2688         
2689         return call;
2690 }
2691
2692 static void
2693 set_rgctx_arg (MonoCompile *cfg, MonoCallInst *call, int rgctx_reg, MonoInst *rgctx_arg)
2694 {
2695         mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
2696         cfg->uses_rgctx_reg = TRUE;
2697         call->rgctx_reg = TRUE;
2698 #ifdef ENABLE_LLVM
2699         call->rgctx_arg_reg = rgctx_reg;
2700 #endif
2701 }       
2702
2703 inline static MonoInst*
2704 mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg)
2705 {
2706         MonoCallInst *call;
2707         MonoInst *ins;
2708         int rgctx_reg = -1;
2709         gboolean check_sp = FALSE;
2710
2711         if (cfg->check_pinvoke_callconv && cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
2712                 WrapperInfo *info = mono_marshal_get_wrapper_info (cfg->method);
2713
2714                 if (info && info->subtype == WRAPPER_SUBTYPE_PINVOKE)
2715                         check_sp = TRUE;
2716         }
2717
2718         if (rgctx_arg) {
2719                 rgctx_reg = mono_alloc_preg (cfg);
2720                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2721         }
2722
2723         if (check_sp) {
2724                 if (!cfg->stack_inbalance_var)
2725                         cfg->stack_inbalance_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2726
2727                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2728                 ins->dreg = cfg->stack_inbalance_var->dreg;
2729                 MONO_ADD_INS (cfg->cbb, ins);
2730         }
2731
2732         call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE, FALSE);
2733
2734         call->inst.sreg1 = addr->dreg;
2735
2736         if (imt_arg)
2737                 emit_imt_argument (cfg, call, NULL, imt_arg);
2738
2739         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2740
2741         if (check_sp) {
2742                 int sp_reg;
2743
2744                 sp_reg = mono_alloc_preg (cfg);
2745
2746                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2747                 ins->dreg = sp_reg;
2748                 MONO_ADD_INS (cfg->cbb, ins);
2749
2750                 /* Restore the stack so we don't crash when throwing the exception */
2751                 MONO_INST_NEW (cfg, ins, OP_SET_SP);
2752                 ins->sreg1 = cfg->stack_inbalance_var->dreg;
2753                 MONO_ADD_INS (cfg->cbb, ins);
2754
2755                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, cfg->stack_inbalance_var->dreg, sp_reg);
2756                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ExecutionEngineException");
2757         }
2758
2759         if (rgctx_arg)
2760                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2761
2762         return (MonoInst*)call;
2763 }
2764
2765 static MonoInst*
2766 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2767
2768 static MonoInst*
2769 emit_get_rgctx_method (MonoCompile *cfg, int context_used, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type);
2770 static MonoInst*
2771 emit_get_rgctx_klass (MonoCompile *cfg, int context_used, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2772
2773 static MonoInst*
2774 mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig, gboolean tail,
2775                                                         MonoInst **args, MonoInst *this_ins, MonoInst *imt_arg, MonoInst *rgctx_arg)
2776 {
2777 #ifndef DISABLE_REMOTING
2778         gboolean might_be_remote = FALSE;
2779 #endif
2780         gboolean virtual_ = this_ins != NULL;
2781         gboolean enable_for_aot = TRUE;
2782         int context_used;
2783         MonoCallInst *call;
2784         MonoInst *call_target = NULL;
2785         int rgctx_reg = 0;
2786         gboolean need_unbox_trampoline;
2787
2788         if (!sig)
2789                 sig = mono_method_signature (method);
2790
2791         if (cfg->llvm_only && (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE))
2792                 g_assert_not_reached ();
2793
2794         if (rgctx_arg) {
2795                 rgctx_reg = mono_alloc_preg (cfg);
2796                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2797         }
2798
2799         if (method->string_ctor) {
2800                 /* Create the real signature */
2801                 /* FIXME: Cache these */
2802                 MonoMethodSignature *ctor_sig = mono_metadata_signature_dup_mempool (cfg->mempool, sig);
2803                 ctor_sig->ret = &mono_defaults.string_class->byval_arg;
2804
2805                 sig = ctor_sig;
2806         }
2807
2808         context_used = mini_method_check_context_used (cfg, method);
2809
2810 #ifndef DISABLE_REMOTING
2811         might_be_remote = this_ins && sig->hasthis &&
2812                 (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) &&
2813                 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && (!MONO_CHECK_THIS (this_ins) || context_used);
2814
2815         if (might_be_remote && context_used) {
2816                 MonoInst *addr;
2817
2818                 g_assert (cfg->gshared);
2819
2820                 addr = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK);
2821
2822                 return mono_emit_calli (cfg, sig, args, addr, NULL, NULL);
2823         }
2824 #endif
2825
2826         if (cfg->llvm_only && !call_target && virtual_ && (method->flags & METHOD_ATTRIBUTE_VIRTUAL))
2827                 return emit_llvmonly_virtual_call (cfg, method, sig, 0, args);
2828
2829         need_unbox_trampoline = method->klass == mono_defaults.object_class || (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
2830
2831         call = mono_emit_call_args (cfg, sig, args, FALSE, virtual_, tail, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline);
2832
2833 #ifndef DISABLE_REMOTING
2834         if (might_be_remote)
2835                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2836         else
2837 #endif
2838                 call->method = method;
2839         call->inst.flags |= MONO_INST_HAS_METHOD;
2840         call->inst.inst_left = this_ins;
2841         call->tail_call = tail;
2842
2843         if (virtual_) {
2844                 int vtable_reg, slot_reg, this_reg;
2845                 int offset;
2846
2847                 this_reg = this_ins->dreg;
2848
2849                 if (!cfg->llvm_only && (method->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (method->name, "Invoke")) {
2850                         MonoInst *dummy_use;
2851
2852                         MONO_EMIT_NULL_CHECK (cfg, this_reg);
2853
2854                         /* Make a call to delegate->invoke_impl */
2855                         call->inst.inst_basereg = this_reg;
2856                         call->inst.inst_offset = MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl);
2857                         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2858
2859                         /* We must emit a dummy use here because the delegate trampoline will
2860                         replace the 'this' argument with the delegate target making this activation
2861                         no longer a root for the delegate.
2862                         This is an issue for delegates that target collectible code such as dynamic
2863                         methods of GC'able assemblies.
2864
2865                         For a test case look into #667921.
2866
2867                         FIXME: a dummy use is not the best way to do it as the local register allocator
2868                         will put it on a caller save register and spil it around the call. 
2869                         Ideally, we would either put it on a callee save register or only do the store part.  
2870                          */
2871                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, args [0]);
2872
2873                         return (MonoInst*)call;
2874                 }
2875
2876                 if ((!cfg->compile_aot || enable_for_aot) && 
2877                         (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || 
2878                          (MONO_METHOD_IS_FINAL (method) &&
2879                           method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)) &&
2880                         !(mono_class_is_marshalbyref (method->klass) && context_used)) {
2881                         /* 
2882                          * the method is not virtual, we just need to ensure this is not null
2883                          * and then we can call the method directly.
2884                          */
2885 #ifndef DISABLE_REMOTING
2886                         if (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) {
2887                                 /* 
2888                                  * The check above ensures method is not gshared, this is needed since
2889                                  * gshared methods can't have wrappers.
2890                                  */
2891                                 method = call->method = mono_marshal_get_remoting_invoke_with_check (method);
2892                         }
2893 #endif
2894
2895                         if (!method->string_ctor)
2896                                 MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2897
2898                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2899                 } else if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && MONO_METHOD_IS_FINAL (method)) {
2900                         /*
2901                          * the method is virtual, but we can statically dispatch since either
2902                          * it's class or the method itself are sealed.
2903                          * But first we need to ensure it's not a null reference.
2904                          */
2905                         MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2906
2907                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2908                 } else if (call_target) {
2909                         vtable_reg = alloc_preg (cfg);
2910                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2911
2912                         call->inst.opcode = callvirt_to_call_reg (call->inst.opcode);
2913                         call->inst.sreg1 = call_target->dreg;
2914                         call->inst.flags &= !MONO_INST_HAS_METHOD;
2915                 } else {
2916                         vtable_reg = alloc_preg (cfg);
2917                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2918                         if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2919                                 guint32 imt_slot = mono_method_get_imt_slot (method);
2920                                 emit_imt_argument (cfg, call, call->method, imt_arg);
2921                                 slot_reg = vtable_reg;
2922                                 offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
2923                         } else {
2924                                 slot_reg = vtable_reg;
2925                                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) +
2926                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
2927                                 if (imt_arg) {
2928                                         g_assert (mono_method_signature (method)->generic_param_count);
2929                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2930                                 }
2931                         }
2932
2933                         call->inst.sreg1 = slot_reg;
2934                         call->inst.inst_offset = offset;
2935                         call->is_virtual = TRUE;
2936                 }
2937         }
2938
2939         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2940
2941         if (rgctx_arg)
2942                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2943
2944         return (MonoInst*)call;
2945 }
2946
2947 MonoInst*
2948 mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoInst **args, MonoInst *this_ins)
2949 {
2950         return mono_emit_method_call_full (cfg, method, mono_method_signature (method), FALSE, args, this_ins, NULL, NULL);
2951 }
2952
2953 MonoInst*
2954 mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig,
2955                                            MonoInst **args)
2956 {
2957         MonoCallInst *call;
2958
2959         g_assert (sig);
2960
2961         call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE, FALSE, FALSE);
2962         call->fptr = func;
2963
2964         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2965
2966         return (MonoInst*)call;
2967 }
2968
2969 MonoInst*
2970 mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args)
2971 {
2972         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2973
2974         g_assert (info);
2975
2976         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2977 }
2978
2979 /*
2980  * mono_emit_abs_call:
2981  *
2982  *   Emit a call to the runtime function described by PATCH_TYPE and DATA.
2983  */
2984 inline static MonoInst*
2985 mono_emit_abs_call (MonoCompile *cfg, MonoJumpInfoType patch_type, gconstpointer data, 
2986                                         MonoMethodSignature *sig, MonoInst **args)
2987 {
2988         MonoJumpInfo *ji = mono_patch_info_new (cfg->mempool, 0, patch_type, data);
2989         MonoInst *ins;
2990
2991         /* 
2992          * We pass ji as the call address, the PATCH_INFO_ABS resolving code will
2993          * handle it.
2994          */
2995         if (cfg->abs_patches == NULL)
2996                 cfg->abs_patches = g_hash_table_new (NULL, NULL);
2997         g_hash_table_insert (cfg->abs_patches, ji, ji);
2998         ins = mono_emit_native_call (cfg, ji, sig, args);
2999         ((MonoCallInst*)ins)->fptr_is_patch = TRUE;
3000         return ins;
3001 }
3002
3003 static MonoMethodSignature*
3004 sig_to_rgctx_sig (MonoMethodSignature *sig)
3005 {
3006         // FIXME: memory allocation
3007         MonoMethodSignature *res;
3008         int i;
3009
3010         res = (MonoMethodSignature *)g_malloc (MONO_SIZEOF_METHOD_SIGNATURE + (sig->param_count + 1) * sizeof (MonoType*));
3011         memcpy (res, sig, MONO_SIZEOF_METHOD_SIGNATURE);
3012         res->param_count = sig->param_count + 1;
3013         for (i = 0; i < sig->param_count; ++i)
3014                 res->params [i] = sig->params [i];
3015         res->params [sig->param_count] = &mono_defaults.int_class->this_arg;
3016         return res;
3017 }
3018
3019 /* Make an indirect call to FSIG passing an additional argument */
3020 static MonoInst*
3021 emit_extra_arg_calli (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **orig_args, int arg_reg, MonoInst *call_target)
3022 {
3023         MonoMethodSignature *csig;
3024         MonoInst *args_buf [16];
3025         MonoInst **args;
3026         int i, pindex, tmp_reg;
3027
3028         /* Make a call with an rgctx/extra arg */
3029         if (fsig->param_count + 2 < 16)
3030                 args = args_buf;
3031         else
3032                 args = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (fsig->param_count + 2));
3033         pindex = 0;
3034         if (fsig->hasthis)
3035                 args [pindex ++] = orig_args [0];
3036         for (i = 0; i < fsig->param_count; ++i)
3037                 args [pindex ++] = orig_args [fsig->hasthis + i];
3038         tmp_reg = alloc_preg (cfg);
3039         EMIT_NEW_UNALU (cfg, args [pindex], OP_MOVE, tmp_reg, arg_reg);
3040         csig = sig_to_rgctx_sig (fsig);
3041         return mono_emit_calli (cfg, csig, args, call_target, NULL, NULL);
3042 }
3043
3044 /* Emit an indirect call to the function descriptor ADDR */
3045 static MonoInst*
3046 emit_llvmonly_calli (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, MonoInst *addr)
3047 {
3048         int addr_reg, arg_reg;
3049         MonoInst *call_target;
3050
3051         g_assert (cfg->llvm_only);
3052
3053         /*
3054          * addr points to a <addr, arg> pair, load both of them, and
3055          * make a call to addr, passing arg as an extra arg.
3056          */
3057         addr_reg = alloc_preg (cfg);
3058         EMIT_NEW_LOAD_MEMBASE (cfg, call_target, OP_LOAD_MEMBASE, addr_reg, addr->dreg, 0);
3059         arg_reg = alloc_preg (cfg);
3060         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, arg_reg, addr->dreg, sizeof (gpointer));
3061
3062         return emit_extra_arg_calli (cfg, fsig, args, arg_reg, call_target);
3063 }
3064
3065 static gboolean
3066 direct_icalls_enabled (MonoCompile *cfg)
3067 {
3068         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
3069 #ifdef TARGET_AMD64
3070         if (cfg->compile_llvm)
3071                 return FALSE;
3072 #endif
3073         if (cfg->gen_sdb_seq_points || cfg->disable_direct_icalls)
3074                 return FALSE;
3075         return TRUE;
3076 }
3077
3078 MonoInst*
3079 mono_emit_jit_icall_by_info (MonoCompile *cfg, MonoJitICallInfo *info, MonoInst **args)
3080 {
3081         /*
3082          * Call the jit icall without a wrapper if possible.
3083          * The wrapper is needed for the following reasons:
3084          * - to handle exceptions thrown using mono_raise_exceptions () from the
3085          *   icall function. The EH code needs the lmf frame pushed by the
3086          *   wrapper to be able to unwind back to managed code.
3087          * - to be able to do stack walks for asynchronously suspended
3088          *   threads when debugging.
3089          */
3090         if (info->no_raise && direct_icalls_enabled (cfg)) {
3091                 char *name;
3092                 int costs;
3093
3094                 if (!info->wrapper_method) {
3095                         name = g_strdup_printf ("__icall_wrapper_%s", info->name);
3096                         info->wrapper_method = mono_marshal_get_icall_wrapper (info->sig, name, info->func, TRUE);
3097                         g_free (name);
3098                         mono_memory_barrier ();
3099                 }
3100
3101                 /*
3102                  * Inline the wrapper method, which is basically a call to the C icall, and
3103                  * an exception check.
3104                  */
3105                 costs = inline_method (cfg, info->wrapper_method, NULL,
3106                                                            args, NULL, cfg->real_offset, TRUE);
3107                 g_assert (costs > 0);
3108                 g_assert (!MONO_TYPE_IS_VOID (info->sig->ret));
3109
3110                 return args [0];
3111         } else {
3112                 return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
3113         }
3114 }
3115  
3116 static MonoInst*
3117 mono_emit_widen_call_res (MonoCompile *cfg, MonoInst *ins, MonoMethodSignature *fsig)
3118 {
3119         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
3120                 if ((fsig->pinvoke || LLVM_ENABLED) && !fsig->ret->byref) {
3121                         int widen_op = -1;
3122
3123                         /* 
3124                          * Native code might return non register sized integers 
3125                          * without initializing the upper bits.
3126                          */
3127                         switch (mono_type_to_load_membase (cfg, fsig->ret)) {
3128                         case OP_LOADI1_MEMBASE:
3129                                 widen_op = OP_ICONV_TO_I1;
3130                                 break;
3131                         case OP_LOADU1_MEMBASE:
3132                                 widen_op = OP_ICONV_TO_U1;
3133                                 break;
3134                         case OP_LOADI2_MEMBASE:
3135                                 widen_op = OP_ICONV_TO_I2;
3136                                 break;
3137                         case OP_LOADU2_MEMBASE:
3138                                 widen_op = OP_ICONV_TO_U2;
3139                                 break;
3140                         default:
3141                                 break;
3142                         }
3143
3144                         if (widen_op != -1) {
3145                                 int dreg = alloc_preg (cfg);
3146                                 MonoInst *widen;
3147
3148                                 EMIT_NEW_UNALU (cfg, widen, widen_op, dreg, ins->dreg);
3149                                 widen->type = ins->type;
3150                                 ins = widen;
3151                         }
3152                 }
3153         }
3154
3155         return ins;
3156 }
3157
3158 static MonoMethod*
3159 get_memcpy_method (void)
3160 {
3161         static MonoMethod *memcpy_method = NULL;
3162         if (!memcpy_method) {
3163                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
3164                 if (!memcpy_method)
3165                         g_error ("Old corlib found. Install a new one");
3166         }
3167         return memcpy_method;
3168 }
3169
3170 static void
3171 create_write_barrier_bitmap (MonoCompile *cfg, MonoClass *klass, unsigned *wb_bitmap, int offset)
3172 {
3173         MonoClassField *field;
3174         gpointer iter = NULL;
3175
3176         while ((field = mono_class_get_fields (klass, &iter))) {
3177                 int foffset;
3178
3179                 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3180                         continue;
3181                 foffset = klass->valuetype ? field->offset - sizeof (MonoObject): field->offset;
3182                 if (mini_type_is_reference (mono_field_get_type (field))) {
3183                         g_assert ((foffset % SIZEOF_VOID_P) == 0);
3184                         *wb_bitmap |= 1 << ((offset + foffset) / SIZEOF_VOID_P);
3185                 } else {
3186                         MonoClass *field_class = mono_class_from_mono_type (field->type);
3187                         if (field_class->has_references)
3188                                 create_write_barrier_bitmap (cfg, field_class, wb_bitmap, offset + foffset);
3189                 }
3190         }
3191 }
3192
3193 static void
3194 emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value)
3195 {
3196         int card_table_shift_bits;
3197         gpointer card_table_mask;
3198         guint8 *card_table;
3199         MonoInst *dummy_use;
3200         int nursery_shift_bits;
3201         size_t nursery_size;
3202
3203         if (!cfg->gen_write_barriers)
3204                 return;
3205
3206         card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
3207
3208         mono_gc_get_nursery (&nursery_shift_bits, &nursery_size);
3209
3210         if (cfg->backend->have_card_table_wb && !cfg->compile_aot && card_table && nursery_shift_bits > 0 && !COMPILE_LLVM (cfg)) {
3211                 MonoInst *wbarrier;
3212
3213                 MONO_INST_NEW (cfg, wbarrier, OP_CARD_TABLE_WBARRIER);
3214                 wbarrier->sreg1 = ptr->dreg;
3215                 wbarrier->sreg2 = value->dreg;
3216                 MONO_ADD_INS (cfg->cbb, wbarrier);
3217         } else if (card_table && !cfg->compile_aot && !mono_gc_card_table_nursery_check ()) {
3218                 int offset_reg = alloc_preg (cfg);
3219                 int card_reg;
3220                 MonoInst *ins;
3221
3222                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, offset_reg, ptr->dreg, card_table_shift_bits);
3223                 if (card_table_mask)
3224                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, offset_reg, offset_reg, card_table_mask);
3225
3226                 /*We can't use PADD_IMM since the cardtable might end up in high addresses and amd64 doesn't support
3227                  * IMM's larger than 32bits.
3228                  */
3229                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
3230                 card_reg = ins->dreg;
3231
3232                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, offset_reg, offset_reg, card_reg);
3233                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, offset_reg, 0, 1);
3234         } else {
3235                 MonoMethod *write_barrier = mono_gc_get_write_barrier ();
3236                 mono_emit_method_call (cfg, write_barrier, &ptr, NULL);
3237         }
3238
3239         EMIT_NEW_DUMMY_USE (cfg, dummy_use, value);
3240 }
3241
3242 static gboolean
3243 mono_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align)
3244 {
3245         int dest_ptr_reg, tmp_reg, destreg, srcreg, offset;
3246         unsigned need_wb = 0;
3247
3248         if (align == 0)
3249                 align = 4;
3250
3251         /*types with references can't have alignment smaller than sizeof(void*) */
3252         if (align < SIZEOF_VOID_P)
3253                 return FALSE;
3254
3255         /*This value cannot be bigger than 32 due to the way we calculate the required wb bitmap.*/
3256         if (size > 32 * SIZEOF_VOID_P)
3257                 return FALSE;
3258
3259         create_write_barrier_bitmap (cfg, klass, &need_wb, 0);
3260
3261         /* We don't unroll more than 5 stores to avoid code bloat. */
3262         if (size > 5 * SIZEOF_VOID_P) {
3263                 /*This is harmless and simplify mono_gc_wbarrier_value_copy_bitmap */
3264                 size += (SIZEOF_VOID_P - 1);
3265                 size &= ~(SIZEOF_VOID_P - 1);
3266
3267                 EMIT_NEW_ICONST (cfg, iargs [2], size);
3268                 EMIT_NEW_ICONST (cfg, iargs [3], need_wb);
3269                 mono_emit_jit_icall (cfg, mono_gc_wbarrier_value_copy_bitmap, iargs);
3270                 return TRUE;
3271         }
3272
3273         destreg = iargs [0]->dreg;
3274         srcreg = iargs [1]->dreg;
3275         offset = 0;
3276
3277         dest_ptr_reg = alloc_preg (cfg);
3278         tmp_reg = alloc_preg (cfg);
3279
3280         /*tmp = dreg*/
3281         EMIT_NEW_UNALU (cfg, iargs [0], OP_MOVE, dest_ptr_reg, destreg);
3282
3283         while (size >= SIZEOF_VOID_P) {
3284                 MonoInst *load_inst;
3285                 MONO_INST_NEW (cfg, load_inst, OP_LOAD_MEMBASE);
3286                 load_inst->dreg = tmp_reg;
3287                 load_inst->inst_basereg = srcreg;
3288                 load_inst->inst_offset = offset;
3289                 MONO_ADD_INS (cfg->cbb, load_inst);
3290
3291                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, dest_ptr_reg, 0, tmp_reg);
3292
3293                 if (need_wb & 0x1)
3294                         emit_write_barrier (cfg, iargs [0], load_inst);
3295
3296                 offset += SIZEOF_VOID_P;
3297                 size -= SIZEOF_VOID_P;
3298                 need_wb >>= 1;
3299
3300                 /*tmp += sizeof (void*)*/
3301                 if (size >= SIZEOF_VOID_P) {
3302                         NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dest_ptr_reg, dest_ptr_reg, SIZEOF_VOID_P);
3303                         MONO_ADD_INS (cfg->cbb, iargs [0]);
3304                 }
3305         }
3306
3307         /* Those cannot be references since size < sizeof (void*) */
3308         while (size >= 4) {
3309                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tmp_reg, srcreg, offset);
3310                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, tmp_reg);
3311                 offset += 4;
3312                 size -= 4;
3313         }
3314
3315         while (size >= 2) {
3316                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmp_reg, srcreg, offset);
3317                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, tmp_reg);
3318                 offset += 2;
3319                 size -= 2;
3320         }
3321
3322         while (size >= 1) {
3323                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmp_reg, srcreg, offset);
3324                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, tmp_reg);
3325                 offset += 1;
3326                 size -= 1;
3327         }
3328
3329         return TRUE;
3330 }
3331
3332 /*
3333  * Emit code to copy a valuetype of type @klass whose address is stored in
3334  * @src->dreg to memory whose address is stored at @dest->dreg.
3335  */
3336 void
3337 mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native)
3338 {
3339         MonoInst *iargs [4];
3340         int n;
3341         guint32 align = 0;
3342         MonoMethod *memcpy_method;
3343         MonoInst *size_ins = NULL;
3344         MonoInst *memcpy_ins = NULL;
3345
3346         g_assert (klass);
3347         if (cfg->gshared)
3348                 klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg));
3349
3350         /*
3351          * This check breaks with spilled vars... need to handle it during verification anyway.
3352          * g_assert (klass && klass == src->klass && klass == dest->klass);
3353          */
3354
3355         if (mini_is_gsharedvt_klass (klass)) {
3356                 g_assert (!native);
3357                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3358                 memcpy_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_MEMCPY);
3359         }
3360
3361         if (native)
3362                 n = mono_class_native_size (klass, &align);
3363         else
3364                 n = mono_class_value_size (klass, &align);
3365
3366         /* if native is true there should be no references in the struct */
3367         if (cfg->gen_write_barriers && (klass->has_references || size_ins) && !native) {
3368                 /* Avoid barriers when storing to the stack */
3369                 if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) ||
3370                           (dest->opcode == OP_LDADDR))) {
3371                         int context_used;
3372
3373                         iargs [0] = dest;
3374                         iargs [1] = src;
3375
3376                         context_used = mini_class_check_context_used (cfg, klass);
3377
3378                         /* It's ok to intrinsify under gsharing since shared code types are layout stable. */
3379                         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && mono_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
3380                                 return;
3381                         } else if (context_used) {
3382                                 iargs [2] = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3383                         }  else {
3384                                 iargs [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
3385                                 if (!cfg->compile_aot)
3386                                         mono_class_compute_gc_descriptor (klass);
3387                         }
3388
3389                         if (size_ins)
3390                                 mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs);
3391                         else
3392                                 mono_emit_jit_icall (cfg, mono_value_copy, iargs);
3393                         return;
3394                 }
3395         }
3396
3397         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 8) {
3398                 /* FIXME: Optimize the case when src/dest is OP_LDADDR */
3399                 mini_emit_memcpy (cfg, dest->dreg, 0, src->dreg, 0, n, align);
3400         } else {
3401                 iargs [0] = dest;
3402                 iargs [1] = src;
3403                 if (size_ins)
3404                         iargs [2] = size_ins;
3405                 else
3406                         EMIT_NEW_ICONST (cfg, iargs [2], n);
3407                 
3408                 memcpy_method = get_memcpy_method ();
3409                 if (memcpy_ins)
3410                         mono_emit_calli (cfg, mono_method_signature (memcpy_method), iargs, memcpy_ins, NULL, NULL);
3411                 else
3412                         mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
3413         }
3414 }
3415
3416 static MonoMethod*
3417 get_memset_method (void)
3418 {
3419         static MonoMethod *memset_method = NULL;
3420         if (!memset_method) {
3421                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
3422                 if (!memset_method)
3423                         g_error ("Old corlib found. Install a new one");
3424         }
3425         return memset_method;
3426 }
3427
3428 void
3429 mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass)
3430 {
3431         MonoInst *iargs [3];
3432         int n;
3433         guint32 align;
3434         MonoMethod *memset_method;
3435         MonoInst *size_ins = NULL;
3436         MonoInst *bzero_ins = NULL;
3437         static MonoMethod *bzero_method;
3438
3439         /* FIXME: Optimize this for the case when dest is an LDADDR */
3440         mono_class_init (klass);
3441         if (mini_is_gsharedvt_klass (klass)) {
3442                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3443                 bzero_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_BZERO);
3444                 if (!bzero_method)
3445                         bzero_method = mono_class_get_method_from_name (mono_defaults.string_class, "bzero_aligned_1", 2);
3446                 g_assert (bzero_method);
3447                 iargs [0] = dest;
3448                 iargs [1] = size_ins;
3449                 mono_emit_calli (cfg, mono_method_signature (bzero_method), iargs, bzero_ins, NULL, NULL);
3450                 return;
3451         }
3452
3453         klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg));
3454
3455         n = mono_class_value_size (klass, &align);
3456
3457         if (n <= sizeof (gpointer) * 8) {
3458                 mini_emit_memset (cfg, dest->dreg, 0, n, 0, align);
3459         }
3460         else {
3461                 memset_method = get_memset_method ();
3462                 iargs [0] = dest;
3463                 EMIT_NEW_ICONST (cfg, iargs [1], 0);
3464                 EMIT_NEW_ICONST (cfg, iargs [2], n);
3465                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
3466         }
3467 }
3468
3469 /*
3470  * emit_get_rgctx:
3471  *
3472  *   Emit IR to return either the this pointer for instance method,
3473  * or the mrgctx for static methods.
3474  */
3475 static MonoInst*
3476 emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used)
3477 {
3478         MonoInst *this_ins = NULL;
3479
3480         g_assert (cfg->gshared);
3481
3482         if (!(method->flags & METHOD_ATTRIBUTE_STATIC) &&
3483                         !(context_used & MONO_GENERIC_CONTEXT_USED_METHOD) &&
3484                         !method->klass->valuetype)
3485                 EMIT_NEW_ARGLOAD (cfg, this_ins, 0);
3486
3487         if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
3488                 MonoInst *mrgctx_loc, *mrgctx_var;
3489
3490                 g_assert (!this_ins);
3491                 g_assert (method->is_inflated && mono_method_get_context (method)->method_inst);
3492
3493                 mrgctx_loc = mono_get_vtable_var (cfg);
3494                 EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
3495
3496                 return mrgctx_var;
3497         } else if (method->flags & METHOD_ATTRIBUTE_STATIC || method->klass->valuetype) {
3498                 MonoInst *vtable_loc, *vtable_var;
3499
3500                 g_assert (!this_ins);
3501
3502                 vtable_loc = mono_get_vtable_var (cfg);
3503                 EMIT_NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
3504
3505                 if (method->is_inflated && mono_method_get_context (method)->method_inst) {
3506                         MonoInst *mrgctx_var = vtable_var;
3507                         int vtable_reg;
3508
3509                         vtable_reg = alloc_preg (cfg);
3510                         EMIT_NEW_LOAD_MEMBASE (cfg, vtable_var, OP_LOAD_MEMBASE, vtable_reg, mrgctx_var->dreg, MONO_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, class_vtable));
3511                         vtable_var->type = STACK_PTR;
3512                 }
3513
3514                 return vtable_var;
3515         } else {
3516                 MonoInst *ins;
3517                 int vtable_reg;
3518         
3519                 vtable_reg = alloc_preg (cfg);
3520                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, vtable_reg, this_ins->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3521                 return ins;
3522         }
3523 }
3524
3525 static MonoJumpInfoRgctxEntry *
3526 mono_patch_info_rgctx_entry_new (MonoMemPool *mp, MonoMethod *method, gboolean in_mrgctx, MonoJumpInfoType patch_type, gconstpointer patch_data, MonoRgctxInfoType info_type)
3527 {
3528         MonoJumpInfoRgctxEntry *res = (MonoJumpInfoRgctxEntry *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoRgctxEntry));
3529         res->method = method;
3530         res->in_mrgctx = in_mrgctx;
3531         res->data = (MonoJumpInfo *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
3532         res->data->type = patch_type;
3533         res->data->data.target = patch_data;
3534         res->info_type = info_type;
3535
3536         return res;
3537 }
3538
3539 static inline MonoInst*
3540 emit_rgctx_fetch_inline (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3541 {
3542         MonoInst *args [16];
3543         MonoInst *call;
3544
3545         // FIXME: No fastpath since the slot is not a compile time constant
3546         args [0] = rgctx;
3547         EMIT_NEW_AOTCONST (cfg, args [1], MONO_PATCH_INFO_RGCTX_SLOT_INDEX, entry);
3548         if (entry->in_mrgctx)
3549                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3550         else
3551                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3552         return call;
3553 #if 0
3554         /*
3555          * FIXME: This can be called during decompose, which is a problem since it creates
3556          * new bblocks.
3557          * Also, the fastpath doesn't work since the slot number is dynamically allocated.
3558          */
3559         int i, slot, depth, index, rgctx_reg, val_reg, res_reg;
3560         gboolean mrgctx;
3561         MonoBasicBlock *is_null_bb, *end_bb;
3562         MonoInst *res, *ins, *call;
3563         MonoInst *args[16];
3564
3565         slot = mini_get_rgctx_entry_slot (entry);
3566
3567         mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot);
3568         index = MONO_RGCTX_SLOT_INDEX (slot);
3569         if (mrgctx)
3570                 index += MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
3571         for (depth = 0; ; ++depth) {
3572                 int size = mono_class_rgctx_get_array_size (depth, mrgctx);
3573
3574                 if (index < size - 1)
3575                         break;
3576                 index -= size - 1;
3577         }
3578
3579         NEW_BBLOCK (cfg, end_bb);
3580         NEW_BBLOCK (cfg, is_null_bb);
3581
3582         if (mrgctx) {
3583                 rgctx_reg = rgctx->dreg;
3584         } else {
3585                 rgctx_reg = alloc_preg (cfg);
3586
3587                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, rgctx_reg, rgctx->dreg, MONO_STRUCT_OFFSET (MonoVTable, runtime_generic_context));
3588                 // FIXME: Avoid this check by allocating the table when the vtable is created etc.
3589                 NEW_BBLOCK (cfg, is_null_bb);
3590
3591                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3592                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3593         }
3594
3595         for (i = 0; i < depth; ++i) {
3596                 int array_reg = alloc_preg (cfg);
3597
3598                 /* load ptr to next array */
3599                 if (mrgctx && i == 0)
3600                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT);
3601                 else
3602                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, 0);
3603                 rgctx_reg = array_reg;
3604                 /* is the ptr null? */
3605                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3606                 /* if yes, jump to actual trampoline */
3607                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3608         }
3609
3610         /* fetch slot */
3611         val_reg = alloc_preg (cfg);
3612         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, val_reg, rgctx_reg, (index + 1) * sizeof (gpointer));
3613         /* is the slot null? */
3614         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, val_reg, 0);
3615         /* if yes, jump to actual trampoline */
3616         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3617
3618         /* Fastpath */
3619         res_reg = alloc_preg (cfg);
3620         MONO_INST_NEW (cfg, ins, OP_MOVE);
3621         ins->dreg = res_reg;
3622         ins->sreg1 = val_reg;
3623         MONO_ADD_INS (cfg->cbb, ins);
3624         res = ins;
3625         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3626
3627         /* Slowpath */
3628         MONO_START_BB (cfg, is_null_bb);
3629         args [0] = rgctx;
3630         EMIT_NEW_ICONST (cfg, args [1], index);
3631         if (mrgctx)
3632                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3633         else
3634                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3635         MONO_INST_NEW (cfg, ins, OP_MOVE);
3636         ins->dreg = res_reg;
3637         ins->sreg1 = call->dreg;
3638         MONO_ADD_INS (cfg->cbb, ins);
3639         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3640
3641         MONO_START_BB (cfg, end_bb);
3642
3643         return res;
3644 #endif
3645 }
3646
3647 /*
3648  * emit_rgctx_fetch:
3649  *
3650  *   Emit IR to load the value of the rgctx entry ENTRY from the rgctx
3651  * given by RGCTX.
3652  */
3653 static inline MonoInst*
3654 emit_rgctx_fetch (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3655 {
3656         if (cfg->llvm_only)
3657                 return emit_rgctx_fetch_inline (cfg, rgctx, entry);
3658         else
3659                 return mono_emit_abs_call (cfg, MONO_PATCH_INFO_RGCTX_FETCH, entry, helper_sig_rgctx_lazy_fetch_trampoline, &rgctx);
3660 }
3661
3662 static MonoInst*
3663 emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
3664                                           MonoClass *klass, MonoRgctxInfoType rgctx_type)
3665 {
3666         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);
3667         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3668
3669         return emit_rgctx_fetch (cfg, rgctx, entry);
3670 }
3671
3672 static MonoInst*
3673 emit_get_rgctx_sig (MonoCompile *cfg, int context_used,
3674                                         MonoMethodSignature *sig, MonoRgctxInfoType rgctx_type)
3675 {
3676         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);
3677         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3678
3679         return emit_rgctx_fetch (cfg, rgctx, entry);
3680 }
3681
3682 static MonoInst*
3683 emit_get_rgctx_gsharedvt_call (MonoCompile *cfg, int context_used,
3684                                                            MonoMethodSignature *sig, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3685 {
3686         MonoJumpInfoGSharedVtCall *call_info;
3687         MonoJumpInfoRgctxEntry *entry;
3688         MonoInst *rgctx;
3689
3690         call_info = (MonoJumpInfoGSharedVtCall *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoGSharedVtCall));
3691         call_info->sig = sig;
3692         call_info->method = cmethod;
3693
3694         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);
3695         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3696
3697         return emit_rgctx_fetch (cfg, rgctx, entry);
3698 }
3699
3700 /*
3701  * emit_get_rgctx_virt_method:
3702  *
3703  *   Return data for method VIRT_METHOD for a receiver of type KLASS.
3704  */
3705 static MonoInst*
3706 emit_get_rgctx_virt_method (MonoCompile *cfg, int context_used,
3707                                                         MonoClass *klass, MonoMethod *virt_method, MonoRgctxInfoType rgctx_type)
3708 {
3709         MonoJumpInfoVirtMethod *info;
3710         MonoJumpInfoRgctxEntry *entry;
3711         MonoInst *rgctx;
3712
3713         info = (MonoJumpInfoVirtMethod *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoVirtMethod));
3714         info->klass = klass;
3715         info->method = virt_method;
3716
3717         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);
3718         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3719
3720         return emit_rgctx_fetch (cfg, rgctx, entry);
3721 }
3722
3723 static MonoInst*
3724 emit_get_rgctx_gsharedvt_method (MonoCompile *cfg, int context_used,
3725                                                                  MonoMethod *cmethod, MonoGSharedVtMethodInfo *info)
3726 {
3727         MonoJumpInfoRgctxEntry *entry;
3728         MonoInst *rgctx;
3729
3730         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);
3731         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3732
3733         return emit_rgctx_fetch (cfg, rgctx, entry);
3734 }
3735
3736 /*
3737  * emit_get_rgctx_method:
3738  *
3739  *   Emit IR to load the property RGCTX_TYPE of CMETHOD. If context_used is 0, emit
3740  * normal constants, else emit a load from the rgctx.
3741  */
3742 static MonoInst*
3743 emit_get_rgctx_method (MonoCompile *cfg, int context_used,
3744                                            MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3745 {
3746         if (!context_used) {
3747                 MonoInst *ins;
3748
3749                 switch (rgctx_type) {
3750                 case MONO_RGCTX_INFO_METHOD:
3751                         EMIT_NEW_METHODCONST (cfg, ins, cmethod);
3752                         return ins;
3753                 case MONO_RGCTX_INFO_METHOD_RGCTX:
3754                         EMIT_NEW_METHOD_RGCTX_CONST (cfg, ins, cmethod);
3755                         return ins;
3756                 default:
3757                         g_assert_not_reached ();
3758                 }
3759         } else {
3760                 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);
3761                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3762
3763                 return emit_rgctx_fetch (cfg, rgctx, entry);
3764         }
3765 }
3766
3767 static MonoInst*
3768 emit_get_rgctx_field (MonoCompile *cfg, int context_used,
3769                                           MonoClassField *field, MonoRgctxInfoType rgctx_type)
3770 {
3771         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);
3772         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3773
3774         return emit_rgctx_fetch (cfg, rgctx, entry);
3775 }
3776
3777 static int
3778 get_gsharedvt_info_slot (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3779 {
3780         MonoGSharedVtMethodInfo *info = cfg->gsharedvt_info;
3781         MonoRuntimeGenericContextInfoTemplate *template_;
3782         int i, idx;
3783
3784         g_assert (info);
3785
3786         for (i = 0; i < info->num_entries; ++i) {
3787                 MonoRuntimeGenericContextInfoTemplate *otemplate = &info->entries [i];
3788
3789                 if (otemplate->info_type == rgctx_type && otemplate->data == data && rgctx_type != MONO_RGCTX_INFO_LOCAL_OFFSET)
3790                         return i;
3791         }
3792
3793         if (info->num_entries == info->count_entries) {
3794                 MonoRuntimeGenericContextInfoTemplate *new_entries;
3795                 int new_count_entries = info->count_entries ? info->count_entries * 2 : 16;
3796
3797                 new_entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * new_count_entries);
3798
3799                 memcpy (new_entries, info->entries, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
3800                 info->entries = new_entries;
3801                 info->count_entries = new_count_entries;
3802         }
3803
3804         idx = info->num_entries;
3805         template_ = &info->entries [idx];
3806         template_->info_type = rgctx_type;
3807         template_->data = data;
3808
3809         info->num_entries ++;
3810
3811         return idx;
3812 }
3813
3814 /*
3815  * emit_get_gsharedvt_info:
3816  *
3817  *   This is similar to emit_get_rgctx_.., but loads the data from the gsharedvt info var instead of calling an rgctx fetch trampoline.
3818  */
3819 static MonoInst*
3820 emit_get_gsharedvt_info (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3821 {
3822         MonoInst *ins;
3823         int idx, dreg;
3824
3825         idx = get_gsharedvt_info_slot (cfg, data, rgctx_type);
3826         /* Load info->entries [idx] */
3827         dreg = alloc_preg (cfg);
3828         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, cfg->gsharedvt_info_var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
3829
3830         return ins;
3831 }
3832
3833 static MonoInst*
3834 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type)
3835 {
3836         return emit_get_gsharedvt_info (cfg, &klass->byval_arg, rgctx_type);
3837 }
3838
3839 /*
3840  * On return the caller must check @klass for load errors.
3841  */
3842 static void
3843 emit_class_init (MonoCompile *cfg, MonoClass *klass)
3844 {
3845         MonoInst *vtable_arg;
3846         int context_used;
3847
3848         context_used = mini_class_check_context_used (cfg, klass);
3849
3850         if (context_used) {
3851                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
3852                                                                                    klass, MONO_RGCTX_INFO_VTABLE);
3853         } else {
3854                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3855
3856                 if (!vtable)
3857                         return;
3858                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
3859         }
3860
3861         if (!COMPILE_LLVM (cfg) && cfg->backend->have_op_generic_class_init) {
3862                 MonoInst *ins;
3863
3864                 /*
3865                  * Using an opcode instead of emitting IR here allows the hiding of the call inside the opcode,
3866                  * so this doesn't have to clobber any regs and it doesn't break basic blocks.
3867                  */
3868                 MONO_INST_NEW (cfg, ins, OP_GENERIC_CLASS_INIT);
3869                 ins->sreg1 = vtable_arg->dreg;
3870                 MONO_ADD_INS (cfg->cbb, ins);
3871         } else {
3872                 static int byte_offset = -1;
3873                 static guint8 bitmask;
3874                 int bits_reg, inited_reg;
3875                 MonoBasicBlock *inited_bb;
3876                 MonoInst *args [16];
3877
3878                 if (byte_offset < 0)
3879                         mono_marshal_find_bitfield_offset (MonoVTable, initialized, &byte_offset, &bitmask);
3880
3881                 bits_reg = alloc_ireg (cfg);
3882                 inited_reg = alloc_ireg (cfg);
3883
3884                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, bits_reg, vtable_arg->dreg, byte_offset);
3885                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, inited_reg, bits_reg, bitmask);
3886
3887                 NEW_BBLOCK (cfg, inited_bb);
3888
3889                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, inited_reg, 0);
3890                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, inited_bb);
3891
3892                 args [0] = vtable_arg;
3893                 mono_emit_jit_icall (cfg, mono_generic_class_init, args);
3894
3895                 MONO_START_BB (cfg, inited_bb);
3896         }
3897 }
3898
3899 static void
3900 emit_seq_point (MonoCompile *cfg, MonoMethod *method, guint8* ip, gboolean intr_loc, gboolean nonempty_stack)
3901 {
3902         MonoInst *ins;
3903
3904         if (cfg->gen_seq_points && cfg->method == method) {
3905                 NEW_SEQ_POINT (cfg, ins, ip - cfg->header->code, intr_loc);
3906                 if (nonempty_stack)
3907                         ins->flags |= MONO_INST_NONEMPTY_STACK;
3908                 MONO_ADD_INS (cfg->cbb, ins);
3909         }
3910 }
3911
3912 static void
3913 save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean null_check)
3914 {
3915         if (mini_get_debug_options ()->better_cast_details) {
3916                 int vtable_reg = alloc_preg (cfg);
3917                 int klass_reg = alloc_preg (cfg);
3918                 MonoBasicBlock *is_null_bb = NULL;
3919                 MonoInst *tls_get;
3920                 int to_klass_reg, context_used;
3921
3922                 if (null_check) {
3923                         NEW_BBLOCK (cfg, is_null_bb);
3924
3925                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3926                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3927                 }
3928
3929                 tls_get = mono_get_jit_tls_intrinsic (cfg);
3930                 if (!tls_get) {
3931                         fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
3932                         exit (1);
3933                 }
3934
3935                 MONO_ADD_INS (cfg->cbb, tls_get);
3936                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3937                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3938
3939                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg);
3940
3941                 context_used = mini_class_check_context_used (cfg, klass);
3942                 if (context_used) {
3943                         MonoInst *class_ins;
3944
3945                         class_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3946                         to_klass_reg = class_ins->dreg;
3947                 } else {
3948                         to_klass_reg = alloc_preg (cfg);
3949                         MONO_EMIT_NEW_CLASSCONST (cfg, to_klass_reg, klass);
3950                 }
3951                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg);
3952
3953                 if (null_check)
3954                         MONO_START_BB (cfg, is_null_bb);
3955         }
3956 }
3957
3958 static void
3959 reset_cast_details (MonoCompile *cfg)
3960 {
3961         /* Reset the variables holding the cast details */
3962         if (mini_get_debug_options ()->better_cast_details) {
3963                 MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
3964
3965                 MONO_ADD_INS (cfg->cbb, tls_get);
3966                 /* It is enough to reset the from field */
3967                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0);
3968         }
3969 }
3970
3971 /*
3972  * On return the caller must check @array_class for load errors
3973  */
3974 static void
3975 mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_class)
3976 {
3977         int vtable_reg = alloc_preg (cfg);
3978         int context_used;
3979
3980         context_used = mini_class_check_context_used (cfg, array_class);
3981
3982         save_cast_details (cfg, array_class, obj->dreg, FALSE);
3983
3984         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3985
3986         if (cfg->opt & MONO_OPT_SHARED) {
3987                 int class_reg = alloc_preg (cfg);
3988                 MonoInst *ins;
3989
3990                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, class_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3991                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, array_class);
3992                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, class_reg, ins->dreg);
3993         } else if (context_used) {
3994                 MonoInst *vtable_ins;
3995
3996                 vtable_ins = emit_get_rgctx_klass (cfg, context_used, array_class, MONO_RGCTX_INFO_VTABLE);
3997                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vtable_ins->dreg);
3998         } else {
3999                 if (cfg->compile_aot) {
4000                         int vt_reg;
4001                         MonoVTable *vtable;
4002
4003                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
4004                                 return;
4005                         vt_reg = alloc_preg (cfg);
4006                         MONO_EMIT_NEW_VTABLECONST (cfg, vt_reg, vtable);
4007                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vt_reg);
4008                 } else {
4009                         MonoVTable *vtable;
4010                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
4011                                 return;
4012                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vtable);
4013                 }
4014         }
4015         
4016         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException");
4017
4018         reset_cast_details (cfg);
4019 }
4020
4021 /**
4022  * Handles unbox of a Nullable<T>. If context_used is non zero, then shared 
4023  * generic code is generated.
4024  */
4025 static MonoInst*
4026 handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int context_used)
4027 {
4028         MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
4029
4030         if (context_used) {
4031                 MonoInst *rgctx, *addr;
4032
4033                 /* FIXME: What if the class is shared?  We might not
4034                    have to get the address of the method from the
4035                    RGCTX. */
4036                 addr = emit_get_rgctx_method (cfg, context_used, method,
4037                                                                           MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4038                 if (cfg->llvm_only && cfg->gsharedvt) {
4039                         return emit_llvmonly_calli (cfg, mono_method_signature (method), &val, addr);
4040                 } else {
4041                         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
4042
4043                         return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
4044                 }
4045         } else {
4046                 gboolean pass_vtable, pass_mrgctx;
4047                 MonoInst *rgctx_arg = NULL;
4048
4049                 check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
4050                 g_assert (!pass_mrgctx);
4051
4052                 if (pass_vtable) {
4053                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4054
4055                         g_assert (vtable);
4056                         EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
4057                 }
4058
4059                 return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4060         }
4061 }
4062
4063 static MonoInst*
4064 handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_used)
4065 {
4066         MonoInst *add;
4067         int obj_reg;
4068         int vtable_reg = alloc_dreg (cfg ,STACK_PTR);
4069         int klass_reg = alloc_dreg (cfg ,STACK_PTR);
4070         int eclass_reg = alloc_dreg (cfg ,STACK_PTR);
4071         int rank_reg = alloc_dreg (cfg ,STACK_I4);
4072
4073         obj_reg = sp [0]->dreg;
4074         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4075         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
4076
4077         /* FIXME: generics */
4078         g_assert (klass->rank == 0);
4079                         
4080         // Check rank == 0
4081         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, 0);
4082         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4083
4084         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4085         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, element_class));
4086
4087         if (context_used) {
4088                 MonoInst *element_class;
4089
4090                 /* This assertion is from the unboxcast insn */
4091                 g_assert (klass->rank == 0);
4092
4093                 element_class = emit_get_rgctx_klass (cfg, context_used,
4094                                 klass, MONO_RGCTX_INFO_ELEMENT_KLASS);
4095
4096                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, eclass_reg, element_class->dreg);
4097                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4098         } else {
4099                 save_cast_details (cfg, klass->element_class, obj_reg, FALSE);
4100                 mini_emit_class_check (cfg, eclass_reg, klass->element_class);
4101                 reset_cast_details (cfg);
4102         }
4103
4104         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), obj_reg, sizeof (MonoObject));
4105         MONO_ADD_INS (cfg->cbb, add);
4106         add->type = STACK_MP;
4107         add->klass = klass;
4108
4109         return add;
4110 }
4111
4112 static MonoInst*
4113 handle_unbox_gsharedvt (MonoCompile *cfg, MonoClass *klass, MonoInst *obj)
4114 {
4115         MonoInst *addr, *klass_inst, *is_ref, *args[16];
4116         MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4117         MonoInst *ins;
4118         int dreg, addr_reg;
4119
4120         klass_inst = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_KLASS);
4121
4122         /* obj */
4123         args [0] = obj;
4124
4125         /* klass */
4126         args [1] = klass_inst;
4127
4128         /* CASTCLASS */
4129         obj = mono_emit_jit_icall (cfg, mono_object_castclass_unbox, args);
4130
4131         NEW_BBLOCK (cfg, is_ref_bb);
4132         NEW_BBLOCK (cfg, is_nullable_bb);
4133         NEW_BBLOCK (cfg, end_bb);
4134         is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4135         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
4136         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4137
4138         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
4139         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4140
4141         /* This will contain either the address of the unboxed vtype, or an address of the temporary where the ref is stored */
4142         addr_reg = alloc_dreg (cfg, STACK_MP);
4143
4144         /* Non-ref case */
4145         /* UNBOX */
4146         NEW_BIALU_IMM (cfg, addr, OP_ADD_IMM, addr_reg, obj->dreg, sizeof (MonoObject));
4147         MONO_ADD_INS (cfg->cbb, addr);
4148
4149         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4150
4151         /* Ref case */
4152         MONO_START_BB (cfg, is_ref_bb);
4153
4154         /* Save the ref to a temporary */
4155         dreg = alloc_ireg (cfg);
4156         EMIT_NEW_VARLOADA_VREG (cfg, addr, dreg, &klass->byval_arg);
4157         addr->dreg = addr_reg;
4158         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, obj->dreg);
4159         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4160
4161         /* Nullable case */
4162         MONO_START_BB (cfg, is_nullable_bb);
4163
4164         {
4165                 MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX);
4166                 MonoInst *unbox_call;
4167                 MonoMethodSignature *unbox_sig;
4168
4169                 unbox_sig = (MonoMethodSignature *)mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4170                 unbox_sig->ret = &klass->byval_arg;
4171                 unbox_sig->param_count = 1;
4172                 unbox_sig->params [0] = &mono_defaults.object_class->byval_arg;
4173
4174                 if (cfg->llvm_only)
4175                         unbox_call = emit_llvmonly_calli (cfg, unbox_sig, &obj, addr);
4176                 else
4177                         unbox_call = mono_emit_calli (cfg, unbox_sig, &obj, addr, NULL, NULL);
4178
4179                 EMIT_NEW_VARLOADA_VREG (cfg, addr, unbox_call->dreg, &klass->byval_arg);
4180                 addr->dreg = addr_reg;
4181         }
4182
4183         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4184
4185         /* End */
4186         MONO_START_BB (cfg, end_bb);
4187
4188         /* LDOBJ */
4189         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr_reg, 0);
4190
4191         return ins;
4192 }
4193
4194 /*
4195  * Returns NULL and set the cfg exception on error.
4196  */
4197 static MonoInst*
4198 handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_used)
4199 {
4200         MonoInst *iargs [2];
4201         void *alloc_ftn;
4202
4203         if (context_used) {
4204                 MonoInst *data;
4205                 MonoRgctxInfoType rgctx_info;
4206                 MonoInst *iargs [2];
4207                 gboolean known_instance_size = !mini_is_gsharedvt_klass (klass);
4208
4209                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (klass, for_box, known_instance_size);
4210
4211                 if (cfg->opt & MONO_OPT_SHARED)
4212                         rgctx_info = MONO_RGCTX_INFO_KLASS;
4213                 else
4214                         rgctx_info = MONO_RGCTX_INFO_VTABLE;
4215                 data = emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
4216
4217                 if (cfg->opt & MONO_OPT_SHARED) {
4218                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4219                         iargs [1] = data;
4220                         alloc_ftn = ves_icall_object_new;
4221                 } else {
4222                         iargs [0] = data;
4223                         alloc_ftn = ves_icall_object_new_specific;
4224                 }
4225
4226                 if (managed_alloc && !(cfg->opt & MONO_OPT_SHARED)) {
4227                         if (known_instance_size) {
4228                                 int size = mono_class_instance_size (klass);
4229                                 if (size < sizeof (MonoObject))
4230                                         g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4231
4232                                 EMIT_NEW_ICONST (cfg, iargs [1], mono_gc_get_aligned_size_for_allocator (size));
4233                         }
4234                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4235                 }
4236
4237                 return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4238         }
4239
4240         if (cfg->opt & MONO_OPT_SHARED) {
4241                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4242                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
4243
4244                 alloc_ftn = ves_icall_object_new;
4245         } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !klass->generic_class) {
4246                 /* This happens often in argument checking code, eg. throw new FooException... */
4247                 /* Avoid relocations and save some space by calling a helper function specialized to mscorlib */
4248                 EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
4249                 return mono_emit_jit_icall (cfg, mono_helper_newobj_mscorlib, iargs);
4250         } else {
4251                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
4252                 MonoMethod *managed_alloc = NULL;
4253                 gboolean pass_lw;
4254
4255                 if (!vtable) {
4256                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4257                         cfg->exception_ptr = klass;
4258                         return NULL;
4259                 }
4260
4261                 managed_alloc = mono_gc_get_managed_allocator (klass, for_box, TRUE);
4262
4263                 if (managed_alloc) {
4264                         int size = mono_class_instance_size (klass);
4265                         if (size < sizeof (MonoObject))
4266                                 g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4267
4268                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4269                         EMIT_NEW_ICONST (cfg, iargs [1], mono_gc_get_aligned_size_for_allocator (size));
4270                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4271                 }
4272                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
4273                 if (pass_lw) {
4274                         guint32 lw = vtable->klass->instance_size;
4275                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
4276                         EMIT_NEW_ICONST (cfg, iargs [0], lw);
4277                         EMIT_NEW_VTABLECONST (cfg, iargs [1], vtable);
4278                 }
4279                 else {
4280                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4281                 }
4282         }
4283
4284         return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4285 }
4286         
4287 /*
4288  * Returns NULL and set the cfg exception on error.
4289  */     
4290 static MonoInst*
4291 handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used)
4292 {
4293         MonoInst *alloc, *ins;
4294
4295         if (mono_class_is_nullable (klass)) {
4296                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
4297
4298                 if (context_used) {
4299                         if (cfg->llvm_only && cfg->gsharedvt) {
4300                                 MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4301                                                                                                                 MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4302                                 return emit_llvmonly_calli (cfg, mono_method_signature (method), &val, addr);
4303                         } else {
4304                                 /* FIXME: What if the class is shared?  We might not
4305                                    have to get the method address from the RGCTX. */
4306                                 MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4307                                                                                                                 MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4308                                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
4309
4310                                 return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
4311                         }
4312                 } else {
4313                         gboolean pass_vtable, pass_mrgctx;
4314                         MonoInst *rgctx_arg = NULL;
4315
4316                         check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
4317                         g_assert (!pass_mrgctx);
4318
4319                         if (pass_vtable) {
4320                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4321
4322                                 g_assert (vtable);
4323                                 EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
4324                         }
4325
4326                         return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4327                 }
4328         }
4329
4330         if (mini_is_gsharedvt_klass (klass)) {
4331                 MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4332                 MonoInst *res, *is_ref, *src_var, *addr;
4333                 int dreg;
4334
4335                 dreg = alloc_ireg (cfg);
4336
4337                 NEW_BBLOCK (cfg, is_ref_bb);
4338                 NEW_BBLOCK (cfg, is_nullable_bb);
4339                 NEW_BBLOCK (cfg, end_bb);
4340                 is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4341                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
4342                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4343
4344                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
4345                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4346
4347                 /* Non-ref case */
4348                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4349                 if (!alloc)
4350                         return NULL;
4351                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4352                 ins->opcode = OP_STOREV_MEMBASE;
4353
4354                 EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, alloc->dreg);
4355                 res->type = STACK_OBJ;
4356                 res->klass = klass;
4357                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4358                 
4359                 /* Ref case */
4360                 MONO_START_BB (cfg, is_ref_bb);
4361
4362                 /* val is a vtype, so has to load the value manually */
4363                 src_var = get_vreg_to_inst (cfg, val->dreg);
4364                 if (!src_var)
4365                         src_var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, val->dreg);
4366                 EMIT_NEW_VARLOADA (cfg, addr, src_var, src_var->inst_vtype);
4367                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, addr->dreg, 0);
4368                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4369
4370                 /* Nullable case */
4371                 MONO_START_BB (cfg, is_nullable_bb);
4372
4373                 {
4374                         MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass,
4375                                                                                                         MONO_RGCTX_INFO_NULLABLE_CLASS_BOX);
4376                         MonoInst *box_call;
4377                         MonoMethodSignature *box_sig;
4378
4379                         /*
4380                          * klass is Nullable<T>, need to call Nullable<T>.Box () using a gsharedvt signature, but we cannot
4381                          * construct that method at JIT time, so have to do things by hand.
4382                          */
4383                         box_sig = (MonoMethodSignature *)mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4384                         box_sig->ret = &mono_defaults.object_class->byval_arg;
4385                         box_sig->param_count = 1;
4386                         box_sig->params [0] = &klass->byval_arg;
4387
4388                         if (cfg->llvm_only)
4389                                 box_call = emit_llvmonly_calli (cfg, box_sig, &val, addr);
4390                         else
4391                                 box_call = mono_emit_calli (cfg, box_sig, &val, addr, NULL, NULL);
4392                         EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, box_call->dreg);
4393                         res->type = STACK_OBJ;
4394                         res->klass = klass;
4395                 }
4396
4397                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4398
4399                 MONO_START_BB (cfg, end_bb);
4400
4401                 return res;
4402         } else {
4403                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4404                 if (!alloc)
4405                         return NULL;
4406
4407                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4408                 return alloc;
4409         }
4410 }
4411
4412 static gboolean
4413 mini_class_has_reference_variant_generic_argument (MonoCompile *cfg, MonoClass *klass, int context_used)
4414 {
4415         int i;
4416         MonoGenericContainer *container;
4417         MonoGenericInst *ginst;
4418
4419         if (klass->generic_class) {
4420                 container = klass->generic_class->container_class->generic_container;
4421                 ginst = klass->generic_class->context.class_inst;
4422         } else if (klass->generic_container && context_used) {
4423                 container = klass->generic_container;
4424                 ginst = container->context.class_inst;
4425         } else {
4426                 return FALSE;
4427         }
4428
4429         for (i = 0; i < container->type_argc; ++i) {
4430                 MonoType *type;
4431                 if (!(mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT)))
4432                         continue;
4433                 type = ginst->type_argv [i];
4434                 if (mini_type_is_reference (type))
4435                         return TRUE;
4436         }
4437         return FALSE;
4438 }
4439
4440 static GHashTable* direct_icall_type_hash;
4441
4442 static gboolean
4443 icall_is_direct_callable (MonoCompile *cfg, MonoMethod *cmethod)
4444 {
4445         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
4446         if (!direct_icalls_enabled (cfg))
4447                 return FALSE;
4448
4449         /*
4450          * An icall is directly callable if it doesn't directly or indirectly call mono_raise_exception ().
4451          * Whitelist a few icalls for now.
4452          */
4453         if (!direct_icall_type_hash) {
4454                 GHashTable *h = g_hash_table_new (g_str_hash, g_str_equal);
4455
4456                 g_hash_table_insert (h, (char*)"Decimal", GUINT_TO_POINTER (1));
4457                 g_hash_table_insert (h, (char*)"Number", GUINT_TO_POINTER (1));
4458                 g_hash_table_insert (h, (char*)"Buffer", GUINT_TO_POINTER (1));
4459                 g_hash_table_insert (h, (char*)"Monitor", GUINT_TO_POINTER (1));
4460                 mono_memory_barrier ();
4461                 direct_icall_type_hash = h;
4462         }
4463
4464         if (cmethod->klass == mono_defaults.math_class)
4465                 return TRUE;
4466         /* No locking needed */
4467         if (cmethod->klass->image == mono_defaults.corlib && g_hash_table_lookup (direct_icall_type_hash, cmethod->klass->name))
4468                 return TRUE;
4469         return FALSE;
4470 }
4471
4472 #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)
4473
4474 static MonoInst*
4475 emit_castclass_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args)
4476 {
4477         MonoMethod *mono_castclass;
4478         MonoInst *res;
4479
4480         mono_castclass = mono_marshal_get_castclass_with_cache ();
4481
4482         save_cast_details (cfg, klass, args [0]->dreg, TRUE);
4483         res = mono_emit_method_call (cfg, mono_castclass, args, NULL);
4484         reset_cast_details (cfg);
4485
4486         return res;
4487 }
4488
4489 static int
4490 get_castclass_cache_idx (MonoCompile *cfg)
4491 {
4492         /* Each CASTCLASS_CACHE patch needs a unique index which identifies the call site */
4493         cfg->castclass_cache_index ++;
4494         return (cfg->method_index << 16) | cfg->castclass_cache_index;
4495 }
4496
4497 static MonoInst*
4498 emit_castclass_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass *klass)
4499 {
4500         MonoInst *args [3];
4501         int idx;
4502
4503         /* obj */
4504         args [0] = obj;
4505
4506         /* klass */
4507         EMIT_NEW_CLASSCONST (cfg, args [1], klass);
4508
4509         /* inline cache*/
4510         idx = get_castclass_cache_idx (cfg);
4511         args [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
4512
4513         /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
4514         return emit_castclass_with_cache (cfg, klass, args);
4515 }
4516
4517 /*
4518  * Returns NULL and set the cfg exception on error.
4519  */
4520 static MonoInst*
4521 handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, guint8 *ip, int *inline_costs)
4522 {
4523         MonoBasicBlock *is_null_bb;
4524         int obj_reg = src->dreg;
4525         int vtable_reg = alloc_preg (cfg);
4526         int context_used;
4527         MonoInst *klass_inst = NULL, *res;
4528
4529         context_used = mini_class_check_context_used (cfg, klass);
4530
4531         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
4532                 res = emit_castclass_with_cache_nonshared (cfg, src, klass);
4533                 (*inline_costs) += 2;
4534                 return res;
4535         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
4536                 MonoMethod *mono_castclass;
4537                 MonoInst *iargs [1];
4538                 int costs;
4539
4540                 mono_castclass = mono_marshal_get_castclass (klass); 
4541                 iargs [0] = src;
4542                                 
4543                 save_cast_details (cfg, klass, src->dreg, TRUE);
4544                 costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
4545                                                            iargs, ip, cfg->real_offset, TRUE);
4546                 reset_cast_details (cfg);
4547                 CHECK_CFG_EXCEPTION;
4548                 g_assert (costs > 0);
4549                                 
4550                 cfg->real_offset += 5;
4551
4552                 (*inline_costs) += costs;
4553
4554                 return src;
4555         }
4556
4557         if (context_used) {
4558                 MonoInst *args [3];
4559
4560                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4561                         MonoInst *cache_ins;
4562
4563                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4564
4565                         /* obj */
4566                         args [0] = src;
4567
4568                         /* klass - it's the second element of the cache entry*/
4569                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4570
4571                         /* cache */
4572                         args [2] = cache_ins;
4573
4574                         return emit_castclass_with_cache (cfg, klass, args);
4575                 }
4576
4577                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4578         }
4579
4580         NEW_BBLOCK (cfg, is_null_bb);
4581
4582         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4583         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
4584
4585         save_cast_details (cfg, klass, obj_reg, FALSE);
4586
4587         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4588                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4589                 mini_emit_iface_cast (cfg, vtable_reg, klass, NULL, NULL);
4590         } else {
4591                 int klass_reg = alloc_preg (cfg);
4592
4593                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4594
4595                 if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4596                         /* the remoting code is broken, access the class for now */
4597                         if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4598                                 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4599                                 if (!vt) {
4600                                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4601                                         cfg->exception_ptr = klass;
4602                                         return NULL;
4603                                 }
4604                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4605                         } else {
4606                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4607                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4608                         }
4609                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4610                 } else {
4611                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4612                         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, klass_inst, is_null_bb);
4613                 }
4614         }
4615
4616         MONO_START_BB (cfg, is_null_bb);
4617
4618         reset_cast_details (cfg);
4619
4620         return src;
4621
4622 exception_exit:
4623         return NULL;
4624 }
4625
4626 /*
4627  * Returns NULL and set the cfg exception on error.
4628  */
4629 static MonoInst*
4630 handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
4631 {
4632         MonoInst *ins;
4633         MonoBasicBlock *is_null_bb, *false_bb, *end_bb;
4634         int obj_reg = src->dreg;
4635         int vtable_reg = alloc_preg (cfg);
4636         int res_reg = alloc_ireg_ref (cfg);
4637         MonoInst *klass_inst = NULL;
4638
4639         if (context_used) {
4640                 MonoInst *args [3];
4641
4642                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4643                         MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
4644                         MonoInst *cache_ins;
4645
4646                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4647
4648                         /* obj */
4649                         args [0] = src;
4650
4651                         /* klass - it's the second element of the cache entry*/
4652                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4653
4654                         /* cache */
4655                         args [2] = cache_ins;
4656
4657                         return mono_emit_method_call (cfg, mono_isinst, args, NULL);
4658                 }
4659
4660                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4661         }
4662
4663         NEW_BBLOCK (cfg, is_null_bb);
4664         NEW_BBLOCK (cfg, false_bb);
4665         NEW_BBLOCK (cfg, end_bb);
4666
4667         /* Do the assignment at the beginning, so the other assignment can be if converted */
4668         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, res_reg, obj_reg);
4669         ins->type = STACK_OBJ;
4670         ins->klass = klass;
4671
4672         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4673         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_null_bb);
4674
4675         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4676
4677         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4678                 g_assert (!context_used);
4679                 /* the is_null_bb target simply copies the input register to the output */
4680                 mini_emit_iface_cast (cfg, vtable_reg, klass, false_bb, is_null_bb);
4681         } else {
4682                 int klass_reg = alloc_preg (cfg);
4683
4684                 if (klass->rank) {
4685                         int rank_reg = alloc_preg (cfg);
4686                         int eclass_reg = alloc_preg (cfg);
4687
4688                         g_assert (!context_used);
4689                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
4690                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
4691                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4692                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4693                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
4694                         if (klass->cast_class == mono_defaults.object_class) {
4695                                 int parent_reg = alloc_preg (cfg);
4696                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
4697                                 mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, is_null_bb);
4698                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4699                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4700                         } else if (klass->cast_class == mono_defaults.enum_class->parent) {
4701                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, is_null_bb);
4702                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);                          
4703                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4704                         } else if (klass->cast_class == mono_defaults.enum_class) {
4705                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4706                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4707                         } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
4708                                 mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4709                         } else {
4710                                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY)) {
4711                                         /* Check that the object is a vector too */
4712                                         int bounds_reg = alloc_preg (cfg);
4713                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
4714                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
4715                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4716                                 }
4717
4718                                 /* the is_null_bb target simply copies the input register to the output */
4719                                 mini_emit_isninst_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4720                         }
4721                 } else if (mono_class_is_nullable (klass)) {
4722                         g_assert (!context_used);
4723                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4724                         /* the is_null_bb target simply copies the input register to the output */
4725                         mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb);
4726                 } else {
4727                         if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4728                                 g_assert (!context_used);
4729                                 /* the remoting code is broken, access the class for now */
4730                                 if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4731                                         MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4732                                         if (!vt) {
4733                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4734                                                 cfg->exception_ptr = klass;
4735                                                 return NULL;
4736                                         }
4737                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4738                                 } else {
4739                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4740                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4741                                 }
4742                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4743                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
4744                         } else {
4745                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4746                                 /* the is_null_bb target simply copies the input register to the output */
4747                                 mini_emit_isninst_cast_inst (cfg, klass_reg, klass, klass_inst, false_bb, is_null_bb);
4748                         }
4749                 }
4750         }
4751
4752         MONO_START_BB (cfg, false_bb);
4753
4754         MONO_EMIT_NEW_PCONST (cfg, res_reg, 0);
4755         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4756
4757         MONO_START_BB (cfg, is_null_bb);
4758
4759         MONO_START_BB (cfg, end_bb);
4760
4761         return ins;
4762 }
4763
4764 static MonoInst*
4765 handle_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4766 {
4767         /* This opcode takes as input an object reference and a class, and returns:
4768         0) if the object is an instance of the class,
4769         1) if the object is not instance of the class,
4770         2) if the object is a proxy whose type cannot be determined */
4771
4772         MonoInst *ins;
4773 #ifndef DISABLE_REMOTING
4774         MonoBasicBlock *true_bb, *false_bb, *false2_bb, *end_bb, *no_proxy_bb, *interface_fail_bb;
4775 #else
4776         MonoBasicBlock *true_bb, *false_bb, *end_bb;
4777 #endif
4778         int obj_reg = src->dreg;
4779         int dreg = alloc_ireg (cfg);
4780         int tmp_reg;
4781 #ifndef DISABLE_REMOTING
4782         int klass_reg = alloc_preg (cfg);
4783 #endif
4784
4785         NEW_BBLOCK (cfg, true_bb);
4786         NEW_BBLOCK (cfg, false_bb);
4787         NEW_BBLOCK (cfg, end_bb);
4788 #ifndef DISABLE_REMOTING
4789         NEW_BBLOCK (cfg, false2_bb);
4790         NEW_BBLOCK (cfg, no_proxy_bb);
4791 #endif
4792
4793         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4794         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
4795
4796         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4797 #ifndef DISABLE_REMOTING
4798                 NEW_BBLOCK (cfg, interface_fail_bb);
4799 #endif
4800
4801                 tmp_reg = alloc_preg (cfg);
4802                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4803 #ifndef DISABLE_REMOTING
4804                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, true_bb);
4805                 MONO_START_BB (cfg, interface_fail_bb);
4806                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4807                 
4808                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, false_bb);
4809
4810                 tmp_reg = alloc_preg (cfg);
4811                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4812                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4813                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false2_bb);                
4814 #else
4815                 mini_emit_iface_cast (cfg, tmp_reg, klass, false_bb, true_bb);
4816 #endif
4817         } else {
4818 #ifndef DISABLE_REMOTING
4819                 tmp_reg = alloc_preg (cfg);
4820                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4821                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4822
4823                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4824                 tmp_reg = alloc_preg (cfg);
4825                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4826                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4827
4828                 tmp_reg = alloc_preg (cfg);             
4829                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4830                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4831                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4832                 
4833                 mini_emit_isninst_cast (cfg, klass_reg, klass, false2_bb, true_bb);
4834                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false2_bb);
4835
4836                 MONO_START_BB (cfg, no_proxy_bb);
4837
4838                 mini_emit_isninst_cast (cfg, klass_reg, klass, false_bb, true_bb);
4839 #else
4840                 g_error ("transparent proxy support is disabled while trying to JIT code that uses it");
4841 #endif
4842         }
4843
4844         MONO_START_BB (cfg, false_bb);
4845
4846         MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4847         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4848
4849 #ifndef DISABLE_REMOTING
4850         MONO_START_BB (cfg, false2_bb);
4851
4852         MONO_EMIT_NEW_ICONST (cfg, dreg, 2);
4853         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4854 #endif
4855
4856         MONO_START_BB (cfg, true_bb);
4857
4858         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4859
4860         MONO_START_BB (cfg, end_bb);
4861
4862         /* FIXME: */
4863         MONO_INST_NEW (cfg, ins, OP_ICONST);
4864         ins->dreg = dreg;
4865         ins->type = STACK_I4;
4866
4867         return ins;
4868 }
4869
4870 static MonoInst*
4871 handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4872 {
4873         /* This opcode takes as input an object reference and a class, and returns:
4874         0) if the object is an instance of the class,
4875         1) if the object is a proxy whose type cannot be determined
4876         an InvalidCastException exception is thrown otherwhise*/
4877         
4878         MonoInst *ins;
4879 #ifndef DISABLE_REMOTING
4880         MonoBasicBlock *end_bb, *ok_result_bb, *no_proxy_bb, *interface_fail_bb, *fail_1_bb;
4881 #else
4882         MonoBasicBlock *ok_result_bb;
4883 #endif
4884         int obj_reg = src->dreg;
4885         int dreg = alloc_ireg (cfg);
4886         int tmp_reg = alloc_preg (cfg);
4887
4888 #ifndef DISABLE_REMOTING
4889         int klass_reg = alloc_preg (cfg);
4890         NEW_BBLOCK (cfg, end_bb);
4891 #endif
4892
4893         NEW_BBLOCK (cfg, ok_result_bb);
4894
4895         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4896         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, ok_result_bb);
4897
4898         save_cast_details (cfg, klass, obj_reg, FALSE);
4899
4900         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4901 #ifndef DISABLE_REMOTING
4902                 NEW_BBLOCK (cfg, interface_fail_bb);
4903         
4904                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4905                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, ok_result_bb);
4906                 MONO_START_BB (cfg, interface_fail_bb);
4907                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4908
4909                 mini_emit_class_check (cfg, klass_reg, mono_defaults.transparent_proxy_class);
4910
4911                 tmp_reg = alloc_preg (cfg);             
4912                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4913                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4914                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
4915                 
4916                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4917                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4918 #else
4919                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4920                 mini_emit_iface_cast (cfg, tmp_reg, klass, NULL, NULL);
4921                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, ok_result_bb);
4922 #endif
4923         } else {
4924 #ifndef DISABLE_REMOTING
4925                 NEW_BBLOCK (cfg, no_proxy_bb);
4926
4927                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4928                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4929                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4930
4931                 tmp_reg = alloc_preg (cfg);
4932                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4933                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4934
4935                 tmp_reg = alloc_preg (cfg);
4936                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4937                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4938                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4939
4940                 NEW_BBLOCK (cfg, fail_1_bb);
4941                 
4942                 mini_emit_isninst_cast (cfg, klass_reg, klass, fail_1_bb, ok_result_bb);
4943
4944                 MONO_START_BB (cfg, fail_1_bb);
4945
4946                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4947                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4948
4949                 MONO_START_BB (cfg, no_proxy_bb);
4950
4951                 mini_emit_castclass (cfg, obj_reg, klass_reg, klass, ok_result_bb);
4952 #else
4953                 g_error ("Transparent proxy support is disabled while trying to JIT code that uses it");
4954 #endif
4955         }
4956
4957         MONO_START_BB (cfg, ok_result_bb);
4958
4959         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4960
4961 #ifndef DISABLE_REMOTING
4962         MONO_START_BB (cfg, end_bb);
4963 #endif
4964
4965         /* FIXME: */
4966         MONO_INST_NEW (cfg, ins, OP_ICONST);
4967         ins->dreg = dreg;
4968         ins->type = STACK_I4;
4969
4970         return ins;
4971 }
4972
4973 static G_GNUC_UNUSED MonoInst*
4974 handle_enum_has_flag (MonoCompile *cfg, MonoClass *klass, MonoInst *enum_this, MonoInst *enum_flag)
4975 {
4976         MonoType *enum_type = mono_type_get_underlying_type (&klass->byval_arg);
4977         guint32 load_opc = mono_type_to_load_membase (cfg, enum_type);
4978         gboolean is_i4;
4979
4980         switch (enum_type->type) {
4981         case MONO_TYPE_I8:
4982         case MONO_TYPE_U8:
4983 #if SIZEOF_REGISTER == 8
4984         case MONO_TYPE_I:
4985         case MONO_TYPE_U:
4986 #endif
4987                 is_i4 = FALSE;
4988                 break;
4989         default:
4990                 is_i4 = TRUE;
4991                 break;
4992         }
4993
4994         {
4995                 MonoInst *load, *and_, *cmp, *ceq;
4996                 int enum_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4997                 int and_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4998                 int dest_reg = alloc_ireg (cfg);
4999
5000                 EMIT_NEW_LOAD_MEMBASE (cfg, load, load_opc, enum_reg, enum_this->dreg, 0);
5001                 EMIT_NEW_BIALU (cfg, and_, is_i4 ? OP_IAND : OP_LAND, and_reg, enum_reg, enum_flag->dreg);
5002                 EMIT_NEW_BIALU (cfg, cmp, is_i4 ? OP_ICOMPARE : OP_LCOMPARE, -1, and_reg, enum_flag->dreg);
5003                 EMIT_NEW_UNALU (cfg, ceq, is_i4 ? OP_ICEQ : OP_LCEQ, dest_reg, -1);
5004
5005                 ceq->type = STACK_I4;
5006
5007                 if (!is_i4) {
5008                         load = mono_decompose_opcode (cfg, load);
5009                         and_ = mono_decompose_opcode (cfg, and_);
5010                         cmp = mono_decompose_opcode (cfg, cmp);
5011                         ceq = mono_decompose_opcode (cfg, ceq);
5012                 }
5013
5014                 return ceq;
5015         }
5016 }
5017
5018 /*
5019  * Returns NULL and set the cfg exception on error.
5020  */
5021 static G_GNUC_UNUSED MonoInst*
5022 handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method, int context_used, gboolean virtual_)
5023 {
5024         MonoInst *ptr;
5025         int dreg;
5026         gpointer trampoline;
5027         MonoInst *obj, *method_ins, *tramp_ins;
5028         MonoDomain *domain;
5029         guint8 **code_slot;
5030
5031         if (virtual_ && !cfg->llvm_only) {
5032                 MonoMethod *invoke = mono_get_delegate_invoke (klass);
5033                 g_assert (invoke);
5034
5035                 if (!mono_get_delegate_virtual_invoke_impl (mono_method_signature (invoke), context_used ? NULL : method))
5036                         return NULL;
5037         }
5038
5039         obj = handle_alloc (cfg, klass, FALSE, mono_class_check_context_used (klass));
5040         if (!obj)
5041                 return NULL;
5042
5043         /* Inline the contents of mono_delegate_ctor */
5044
5045         /* Set target field */
5046         /* Optimize away setting of NULL target */
5047         if (!(target->opcode == OP_PCONST && target->inst_p0 == 0)) {
5048                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
5049                 if (cfg->gen_write_barriers) {
5050                         dreg = alloc_preg (cfg);
5051                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target));
5052                         emit_write_barrier (cfg, ptr, target);
5053                 }
5054         }
5055
5056         /* Set method field */
5057         method_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
5058         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg);
5059
5060         /* 
5061          * To avoid looking up the compiled code belonging to the target method
5062          * in mono_delegate_trampoline (), we allocate a per-domain memory slot to
5063          * store it, and we fill it after the method has been compiled.
5064          */
5065         if (!method->dynamic && !(cfg->opt & MONO_OPT_SHARED)) {
5066                 MonoInst *code_slot_ins;
5067
5068                 if (context_used) {
5069                         code_slot_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD_DELEGATE_CODE);
5070                 } else {
5071                         domain = mono_domain_get ();
5072                         mono_domain_lock (domain);
5073                         if (!domain_jit_info (domain)->method_code_hash)
5074                                 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
5075                         code_slot = (guint8 **)g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, method);
5076                         if (!code_slot) {
5077                                 code_slot = (guint8 **)mono_domain_alloc0 (domain, sizeof (gpointer));
5078                                 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, method, code_slot);
5079                         }
5080                         mono_domain_unlock (domain);
5081
5082                         code_slot_ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHOD_CODE_SLOT, method);
5083                 }
5084                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);                
5085         }
5086
5087         if (cfg->llvm_only) {
5088                 MonoInst *args [16];
5089
5090                 if (virtual_) {
5091                         args [0] = obj;
5092                         args [1] = target;
5093                         args [2] = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
5094                         mono_emit_jit_icall (cfg, mono_llvmonly_init_delegate_virtual, args);
5095                 } else {
5096                         args [0] = obj;
5097                         mono_emit_jit_icall (cfg, mono_llvmonly_init_delegate, args);
5098                 }
5099
5100                 return obj;
5101         }
5102
5103         if (cfg->compile_aot) {
5104                 MonoDelegateClassMethodPair *del_tramp;
5105
5106                 del_tramp = (MonoDelegateClassMethodPair *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoDelegateClassMethodPair));
5107                 del_tramp->klass = klass;
5108                 del_tramp->method = context_used ? NULL : method;
5109                 del_tramp->is_virtual = virtual_;
5110                 EMIT_NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_DELEGATE_TRAMPOLINE, del_tramp);
5111         } else {
5112                 if (virtual_)
5113                         trampoline = mono_create_delegate_virtual_trampoline (cfg->domain, klass, context_used ? NULL : method);
5114                 else
5115                         trampoline = mono_create_delegate_trampoline_info (cfg->domain, klass, context_used ? NULL : method);
5116                 EMIT_NEW_PCONST (cfg, tramp_ins, trampoline);
5117         }
5118
5119         /* Set invoke_impl field */
5120         if (virtual_) {
5121                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), tramp_ins->dreg);
5122         } else {
5123                 dreg = alloc_preg (cfg);
5124                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, invoke_impl));
5125                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), dreg);
5126
5127                 dreg = alloc_preg (cfg);
5128                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, method_ptr));
5129                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr), dreg);
5130         }
5131
5132         dreg = alloc_preg (cfg);
5133         MONO_EMIT_NEW_ICONST (cfg, dreg, virtual_ ? 1 : 0);
5134         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_is_virtual), dreg);
5135
5136         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
5137
5138         return obj;
5139 }
5140
5141 static MonoInst*
5142 handle_array_new (MonoCompile *cfg, int rank, MonoInst **sp, unsigned char *ip)
5143 {
5144         MonoJitICallInfo *info;
5145
5146         /* Need to register the icall so it gets an icall wrapper */
5147         info = mono_get_array_new_va_icall (rank);
5148
5149         cfg->flags |= MONO_CFG_HAS_VARARGS;
5150
5151         /* mono_array_new_va () needs a vararg calling convention */
5152         cfg->exception_message = g_strdup ("array-new");
5153         cfg->disable_llvm = TRUE;
5154
5155         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
5156         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, sp);
5157 }
5158
5159 /*
5160  * handle_constrained_gsharedvt_call:
5161  *
5162  *   Handle constrained calls where the receiver is a gsharedvt type.
5163  * Return the instruction representing the call. Set the cfg exception on failure.
5164  */
5165 static MonoInst*
5166 handle_constrained_gsharedvt_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp, MonoClass *constrained_class,
5167                                                                    gboolean *ref_emit_widen)
5168 {
5169         MonoInst *ins = NULL;
5170         gboolean emit_widen = *ref_emit_widen;
5171
5172         /*
5173          * Constrained calls need to behave differently at runtime dependending on whenever the receiver is instantiated as ref type or as a vtype.
5174          * 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
5175          * pack the arguments into an array, and do the rest of the work in in an icall.
5176          */
5177         if (((cmethod->klass == mono_defaults.object_class) || (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) &&
5178                 (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)) &&
5179                 (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]))))) {
5180                 MonoInst *args [16];
5181
5182                 /*
5183                  * This case handles calls to
5184                  * - object:ToString()/Equals()/GetHashCode(),
5185                  * - System.IComparable<T>:CompareTo()
5186                  * - System.IEquatable<T>:Equals ()
5187                  * plus some simple interface calls enough to support AsyncTaskMethodBuilder.
5188                  */
5189
5190                 args [0] = sp [0];
5191                 if (mono_method_check_context_used (cmethod))
5192                         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cmethod), cmethod, MONO_RGCTX_INFO_METHOD);
5193                 else
5194                         EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
5195                 args [2] = emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_class), constrained_class, MONO_RGCTX_INFO_KLASS);
5196
5197                 /* !fsig->hasthis is for the wrapper for the Object.GetType () icall */
5198                 if (fsig->hasthis && fsig->param_count) {
5199                         /* Pass the arguments using a localloc-ed array using the format expected by runtime_invoke () */
5200                         MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
5201                         ins->dreg = alloc_preg (cfg);
5202                         ins->inst_imm = fsig->param_count * sizeof (mgreg_t);
5203                         MONO_ADD_INS (cfg->cbb, ins);
5204                         args [4] = ins;
5205
5206                         if (mini_is_gsharedvt_type (fsig->params [0])) {
5207                                 int addr_reg, deref_arg_reg;
5208
5209                                 ins = emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type (fsig->params [0]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
5210                                 deref_arg_reg = alloc_preg (cfg);
5211                                 /* deref_arg = BOX_TYPE != MONO_GSHAREDVT_BOX_TYPE_VTYPE */
5212                                 EMIT_NEW_BIALU_IMM (cfg, args [3], OP_ISUB_IMM, deref_arg_reg, ins->dreg, 1);
5213
5214                                 EMIT_NEW_VARLOADA_VREG (cfg, ins, sp [1]->dreg, fsig->params [0]);
5215                                 addr_reg = ins->dreg;
5216                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, addr_reg);
5217                         } else {
5218                                 EMIT_NEW_ICONST (cfg, args [3], 0);
5219                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, sp [1]->dreg);
5220                         }
5221                 } else {
5222                         EMIT_NEW_ICONST (cfg, args [3], 0);
5223                         EMIT_NEW_ICONST (cfg, args [4], 0);
5224                 }
5225                 ins = mono_emit_jit_icall (cfg, mono_gsharedvt_constrained_call, args);
5226                 emit_widen = FALSE;
5227
5228                 if (mini_is_gsharedvt_type (fsig->ret)) {
5229                         ins = handle_unbox_gsharedvt (cfg, mono_class_from_mono_type (fsig->ret), ins);
5230                 } else if (MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret)) {
5231                         MonoInst *add;
5232
5233                         /* Unbox */
5234                         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), ins->dreg, sizeof (MonoObject));
5235                         MONO_ADD_INS (cfg->cbb, add);
5236                         /* Load value */
5237                         NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, add->dreg, 0);
5238                         MONO_ADD_INS (cfg->cbb, ins);
5239                         /* ins represents the call result */
5240                 }
5241         } else {
5242                 GSHAREDVT_FAILURE (CEE_CALLVIRT);
5243         }
5244
5245         *ref_emit_widen = emit_widen;
5246
5247         return ins;
5248
5249  exception_exit:
5250         return NULL;
5251 }
5252
5253 static void
5254 mono_emit_load_got_addr (MonoCompile *cfg)
5255 {
5256         MonoInst *getaddr, *dummy_use;
5257
5258         if (!cfg->got_var || cfg->got_var_allocated)
5259                 return;
5260
5261         MONO_INST_NEW (cfg, getaddr, OP_LOAD_GOTADDR);
5262         getaddr->cil_code = cfg->header->code;
5263         getaddr->dreg = cfg->got_var->dreg;
5264
5265         /* Add it to the start of the first bblock */
5266         if (cfg->bb_entry->code) {
5267                 getaddr->next = cfg->bb_entry->code;
5268                 cfg->bb_entry->code = getaddr;
5269         }
5270         else
5271                 MONO_ADD_INS (cfg->bb_entry, getaddr);
5272
5273         cfg->got_var_allocated = TRUE;
5274
5275         /* 
5276          * Add a dummy use to keep the got_var alive, since real uses might
5277          * only be generated by the back ends.
5278          * Add it to end_bblock, so the variable's lifetime covers the whole
5279          * method.
5280          * It would be better to make the usage of the got var explicit in all
5281          * cases when the backend needs it (i.e. calls, throw etc.), so this
5282          * wouldn't be needed.
5283          */
5284         NEW_DUMMY_USE (cfg, dummy_use, cfg->got_var);
5285         MONO_ADD_INS (cfg->bb_exit, dummy_use);
5286 }
5287
5288 static int inline_limit;
5289 static gboolean inline_limit_inited;
5290
5291 static gboolean
5292 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
5293 {
5294         MonoMethodHeaderSummary header;
5295         MonoVTable *vtable;
5296 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5297         MonoMethodSignature *sig = mono_method_signature (method);
5298         int i;
5299 #endif
5300
5301         if (cfg->disable_inline)
5302                 return FALSE;
5303         if (cfg->gshared)
5304                 return FALSE;
5305
5306         if (cfg->inline_depth > 10)
5307                 return FALSE;
5308
5309         if (!mono_method_get_header_summary (method, &header))
5310                 return FALSE;
5311
5312         /*runtime, icall and pinvoke are checked by summary call*/
5313         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
5314             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
5315             (mono_class_is_marshalbyref (method->klass)) ||
5316             header.has_clauses)
5317                 return FALSE;
5318
5319         /* also consider num_locals? */
5320         /* Do the size check early to avoid creating vtables */
5321         if (!inline_limit_inited) {
5322                 if (g_getenv ("MONO_INLINELIMIT"))
5323                         inline_limit = atoi (g_getenv ("MONO_INLINELIMIT"));
5324                 else
5325                         inline_limit = INLINE_LENGTH_LIMIT;
5326                 inline_limit_inited = TRUE;
5327         }
5328         if (header.code_size >= inline_limit && !(method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
5329                 return FALSE;
5330
5331         /*
5332          * if we can initialize the class of the method right away, we do,
5333          * otherwise we don't allow inlining if the class needs initialization,
5334          * since it would mean inserting a call to mono_runtime_class_init()
5335          * inside the inlined code
5336          */
5337         if (!(cfg->opt & MONO_OPT_SHARED)) {
5338                 /* The AggressiveInlining hint is a good excuse to force that cctor to run. */
5339                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING) {
5340                         vtable = mono_class_vtable (cfg->domain, method->klass);
5341                         if (!vtable)
5342                                 return FALSE;
5343                         if (!cfg->compile_aot) {
5344                                 MonoError error;
5345                                 if (!mono_runtime_class_init_full (vtable, &error))
5346                                         mono_error_raise_exception (&error); /* FIXME don't raise here */
5347                         }
5348                 } else if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5349                         if (cfg->run_cctors && method->klass->has_cctor) {
5350                                 /*FIXME it would easier and lazier to just use mono_class_try_get_vtable */
5351                                 if (!method->klass->runtime_info)
5352                                         /* No vtable created yet */
5353                                         return FALSE;
5354                                 vtable = mono_class_vtable (cfg->domain, method->klass);
5355                                 if (!vtable)
5356                                         return FALSE;
5357                                 /* This makes so that inline cannot trigger */
5358                                 /* .cctors: too many apps depend on them */
5359                                 /* running with a specific order... */
5360                                 if (! vtable->initialized)
5361                                         return FALSE;
5362                                 MonoError error;
5363                                 if (!mono_runtime_class_init_full (vtable, &error))
5364                                         mono_error_raise_exception (&error); /* FIXME don't raise here */
5365                         }
5366                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
5367                         if (!method->klass->runtime_info)
5368                                 /* No vtable created yet */
5369                                 return FALSE;
5370                         vtable = mono_class_vtable (cfg->domain, method->klass);
5371                         if (!vtable)
5372                                 return FALSE;
5373                         if (!vtable->initialized)
5374                                 return FALSE;
5375                 }
5376         } else {
5377                 /* 
5378                  * If we're compiling for shared code
5379                  * the cctor will need to be run at aot method load time, for example,
5380                  * or at the end of the compilation of the inlining method.
5381                  */
5382                 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
5383                         return FALSE;
5384         }
5385
5386 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5387         if (mono_arch_is_soft_float ()) {
5388                 /* FIXME: */
5389                 if (sig->ret && sig->ret->type == MONO_TYPE_R4)
5390                         return FALSE;
5391                 for (i = 0; i < sig->param_count; ++i)
5392                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4)
5393                                 return FALSE;
5394         }
5395 #endif
5396
5397         if (g_list_find (cfg->dont_inline, method))
5398                 return FALSE;
5399
5400         return TRUE;
5401 }
5402
5403 static gboolean
5404 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoClass *klass, MonoVTable *vtable)
5405 {
5406         if (!cfg->compile_aot) {
5407                 g_assert (vtable);
5408                 if (vtable->initialized)
5409                         return FALSE;
5410         }
5411
5412         if (klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5413                 if (cfg->method == method)
5414                         return FALSE;
5415         }
5416
5417         if (!mono_class_needs_cctor_run (klass, method))
5418                 return FALSE;
5419
5420         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (klass == method->klass))
5421                 /* The initialization is already done before the method is called */
5422                 return FALSE;
5423
5424         return TRUE;
5425 }
5426
5427 static MonoInst*
5428 mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck)
5429 {
5430         MonoInst *ins;
5431         guint32 size;
5432         int mult_reg, add_reg, array_reg, index_reg, index2_reg;
5433         int context_used;
5434
5435         if (mini_is_gsharedvt_variable_klass (klass)) {
5436                 size = -1;
5437         } else {
5438                 mono_class_init (klass);
5439                 size = mono_class_array_element_size (klass);
5440         }
5441
5442         mult_reg = alloc_preg (cfg);
5443         array_reg = arr->dreg;
5444         index_reg = index->dreg;
5445
5446 #if SIZEOF_REGISTER == 8
5447         /* The array reg is 64 bits but the index reg is only 32 */
5448         if (COMPILE_LLVM (cfg)) {
5449                 /* Not needed */
5450                 index2_reg = index_reg;
5451         } else {
5452                 index2_reg = alloc_preg (cfg);
5453                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
5454         }
5455 #else
5456         if (index->type == STACK_I8) {
5457                 index2_reg = alloc_preg (cfg);
5458                 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I4, index2_reg, index_reg);
5459         } else {
5460                 index2_reg = index_reg;
5461         }
5462 #endif
5463
5464         if (bcheck)
5465                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
5466
5467 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5468         if (size == 1 || size == 2 || size == 4 || size == 8) {
5469                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
5470
5471                 EMIT_NEW_X86_LEA (cfg, ins, array_reg, index2_reg, fast_log2 [size], MONO_STRUCT_OFFSET (MonoArray, vector));
5472                 ins->klass = mono_class_get_element_class (klass);
5473                 ins->type = STACK_MP;
5474
5475                 return ins;
5476         }
5477 #endif          
5478
5479         add_reg = alloc_ireg_mp (cfg);
5480
5481         if (size == -1) {
5482                 MonoInst *rgctx_ins;
5483
5484                 /* gsharedvt */
5485                 g_assert (cfg->gshared);
5486                 context_used = mini_class_check_context_used (cfg, klass);
5487                 g_assert (context_used);
5488                 rgctx_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE);
5489                 MONO_EMIT_NEW_BIALU (cfg, OP_IMUL, mult_reg, index2_reg, rgctx_ins->dreg);
5490         } else {
5491                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
5492         }
5493         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg);
5494         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5495         ins->klass = mono_class_get_element_class (klass);
5496         ins->type = STACK_MP;
5497         MONO_ADD_INS (cfg->cbb, ins);
5498
5499         return ins;
5500 }
5501
5502 static MonoInst*
5503 mini_emit_ldelema_2_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index_ins1, MonoInst *index_ins2)
5504 {
5505         int bounds_reg = alloc_preg (cfg);
5506         int add_reg = alloc_ireg_mp (cfg);
5507         int mult_reg = alloc_preg (cfg);
5508         int mult2_reg = alloc_preg (cfg);
5509         int low1_reg = alloc_preg (cfg);
5510         int low2_reg = alloc_preg (cfg);
5511         int high1_reg = alloc_preg (cfg);
5512         int high2_reg = alloc_preg (cfg);
5513         int realidx1_reg = alloc_preg (cfg);
5514         int realidx2_reg = alloc_preg (cfg);
5515         int sum_reg = alloc_preg (cfg);
5516         int index1, index2, tmpreg;
5517         MonoInst *ins;
5518         guint32 size;
5519
5520         mono_class_init (klass);
5521         size = mono_class_array_element_size (klass);
5522
5523         index1 = index_ins1->dreg;
5524         index2 = index_ins2->dreg;
5525
5526 #if SIZEOF_REGISTER == 8
5527         /* The array reg is 64 bits but the index reg is only 32 */
5528         if (COMPILE_LLVM (cfg)) {
5529                 /* Not needed */
5530         } else {
5531                 tmpreg = alloc_preg (cfg);
5532                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index1);
5533                 index1 = tmpreg;
5534                 tmpreg = alloc_preg (cfg);
5535                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index2);
5536                 index2 = tmpreg;
5537         }
5538 #else
5539         // FIXME: Do we need to do something here for i8 indexes, like in ldelema_1_ins ?
5540         tmpreg = -1;
5541 #endif
5542
5543         /* range checking */
5544         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, 
5545                                        arr->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5546
5547         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low1_reg, 
5548                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5549         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx1_reg, index1, low1_reg);
5550         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high1_reg, 
5551                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5552         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high1_reg, realidx1_reg);
5553         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5554
5555         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low2_reg, 
5556                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5557         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx2_reg, index2, low2_reg);
5558         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high2_reg, 
5559                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5560         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high2_reg, realidx2_reg);
5561         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5562
5563         MONO_EMIT_NEW_BIALU (cfg, OP_PMUL, mult_reg, high2_reg, realidx1_reg);
5564         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, mult_reg, realidx2_reg);
5565         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PMUL_IMM, mult2_reg, sum_reg, size);
5566         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult2_reg, arr->dreg);
5567         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5568
5569         ins->type = STACK_MP;
5570         ins->klass = klass;
5571         MONO_ADD_INS (cfg->cbb, ins);
5572
5573         return ins;
5574 }
5575
5576 static MonoInst*
5577 mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
5578 {
5579         int rank;
5580         MonoInst *addr;
5581         MonoMethod *addr_method;
5582         int element_size;
5583         MonoClass *eclass = cmethod->klass->element_class;
5584
5585         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
5586
5587         if (rank == 1)
5588                 return mini_emit_ldelema_1_ins (cfg, eclass, sp [0], sp [1], TRUE);
5589
5590         /* emit_ldelema_2 depends on OP_LMUL */
5591         if (!cfg->backend->emulate_mul_div && rank == 2 && (cfg->opt & MONO_OPT_INTRINS) && !mini_is_gsharedvt_variable_klass (eclass)) {
5592                 return mini_emit_ldelema_2_ins (cfg, eclass, sp [0], sp [1], sp [2]);
5593         }
5594
5595         if (mini_is_gsharedvt_variable_klass (eclass))
5596                 element_size = 0;
5597         else
5598                 element_size = mono_class_array_element_size (eclass);
5599         addr_method = mono_marshal_get_array_address (rank, element_size);
5600         addr = mono_emit_method_call (cfg, addr_method, sp, NULL);
5601
5602         return addr;
5603 }
5604
5605 static MonoBreakPolicy
5606 always_insert_breakpoint (MonoMethod *method)
5607 {
5608         return MONO_BREAK_POLICY_ALWAYS;
5609 }
5610
5611 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
5612
5613 /**
5614  * mono_set_break_policy:
5615  * policy_callback: the new callback function
5616  *
5617  * Allow embedders to decide wherther to actually obey breakpoint instructions
5618  * (both break IL instructions and Debugger.Break () method calls), for example
5619  * to not allow an app to be aborted by a perfectly valid IL opcode when executing
5620  * untrusted or semi-trusted code.
5621  *
5622  * @policy_callback will be called every time a break point instruction needs to
5623  * be inserted with the method argument being the method that calls Debugger.Break()
5624  * or has the IL break instruction. The callback should return #MONO_BREAK_POLICY_NEVER
5625  * if it wants the breakpoint to not be effective in the given method.
5626  * #MONO_BREAK_POLICY_ALWAYS is the default.
5627  */
5628 void
5629 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
5630 {
5631         if (policy_callback)
5632                 break_policy_func = policy_callback;
5633         else
5634                 break_policy_func = always_insert_breakpoint;
5635 }
5636
5637 static gboolean
5638 should_insert_brekpoint (MonoMethod *method) {
5639         switch (break_policy_func (method)) {
5640         case MONO_BREAK_POLICY_ALWAYS:
5641                 return TRUE;
5642         case MONO_BREAK_POLICY_NEVER:
5643                 return FALSE;
5644         case MONO_BREAK_POLICY_ON_DBG:
5645                 g_warning ("mdb no longer supported");
5646                 return FALSE;
5647         default:
5648                 g_warning ("Incorrect value returned from break policy callback");
5649                 return FALSE;
5650         }
5651 }
5652
5653 /* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */
5654 static MonoInst*
5655 emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5656 {
5657         MonoInst *addr, *store, *load;
5658         MonoClass *eklass = mono_class_from_mono_type (fsig->params [2]);
5659
5660         /* the bounds check is already done by the callers */
5661         addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5662         if (is_set) {
5663                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
5664                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
5665                 if (mini_type_is_reference (fsig->params [2]))
5666                         emit_write_barrier (cfg, addr, load);
5667         } else {
5668                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
5669                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
5670         }
5671         return store;
5672 }
5673
5674
5675 static gboolean
5676 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
5677 {
5678         return mini_type_is_reference (&klass->byval_arg);
5679 }
5680
5681 static MonoInst*
5682 emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboolean safety_checks)
5683 {
5684         if (safety_checks && generic_class_is_reference_type (cfg, klass) &&
5685                 !(sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL)) {
5686                 MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
5687                 MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
5688                 MonoInst *iargs [3];
5689
5690                 if (!helper->slot)
5691                         mono_class_setup_vtable (obj_array);
5692                 g_assert (helper->slot);
5693
5694                 if (sp [0]->type != STACK_OBJ)
5695                         return NULL;
5696                 if (sp [2]->type != STACK_OBJ)
5697                         return NULL;
5698
5699                 iargs [2] = sp [2];
5700                 iargs [1] = sp [1];
5701                 iargs [0] = sp [0];
5702
5703                 return mono_emit_method_call (cfg, helper, iargs, sp [0]);
5704         } else {
5705                 MonoInst *ins;
5706
5707                 if (mini_is_gsharedvt_variable_klass (klass)) {
5708                         MonoInst *addr;
5709
5710                         // FIXME-VT: OP_ICONST optimization
5711                         addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
5712                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5713                         ins->opcode = OP_STOREV_MEMBASE;
5714                 } else if (sp [1]->opcode == OP_ICONST) {
5715                         int array_reg = sp [0]->dreg;
5716                         int index_reg = sp [1]->dreg;
5717                         int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
5718
5719                         if (SIZEOF_REGISTER == 8 && COMPILE_LLVM (cfg))
5720                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, index_reg);
5721
5722                         if (safety_checks)
5723                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
5724                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
5725                 } else {
5726                         MonoInst *addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], safety_checks);
5727                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5728                         if (generic_class_is_reference_type (cfg, klass))
5729                                 emit_write_barrier (cfg, addr, sp [2]);
5730                 }
5731                 return ins;
5732         }
5733 }
5734
5735 static MonoInst*
5736 emit_array_unsafe_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5737 {
5738         MonoClass *eklass;
5739         
5740         if (is_set)
5741                 eklass = mono_class_from_mono_type (fsig->params [2]);
5742         else
5743                 eklass = mono_class_from_mono_type (fsig->ret);
5744
5745         if (is_set) {
5746                 return emit_array_store (cfg, eklass, args, FALSE);
5747         } else {
5748                 MonoInst *ins, *addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5749                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &eklass->byval_arg, addr->dreg, 0);
5750                 return ins;
5751         }
5752 }
5753
5754 static gboolean
5755 is_unsafe_mov_compatible (MonoCompile *cfg, MonoClass *param_klass, MonoClass *return_klass)
5756 {
5757         uint32_t align;
5758         int param_size, return_size;
5759
5760         param_klass = mono_class_from_mono_type (mini_get_underlying_type (&param_klass->byval_arg));
5761         return_klass = mono_class_from_mono_type (mini_get_underlying_type (&return_klass->byval_arg));
5762
5763         if (cfg->verbose_level > 3)
5764                 printf ("[UNSAFE-MOV-INTRISIC] %s <- %s\n", return_klass->name, param_klass->name);
5765
5766         //Don't allow mixing reference types with value types
5767         if (param_klass->valuetype != return_klass->valuetype) {
5768                 if (cfg->verbose_level > 3)
5769                         printf ("[UNSAFE-MOV-INTRISIC]\tone of the args is a valuetype and the other is not\n");
5770                 return FALSE;
5771         }
5772
5773         if (!param_klass->valuetype) {
5774                 if (cfg->verbose_level > 3)
5775                         printf ("[UNSAFE-MOV-INTRISIC]\targs are reference types\n");
5776                 return TRUE;
5777         }
5778
5779         //That are blitable
5780         if (param_klass->has_references || return_klass->has_references)
5781                 return FALSE;
5782
5783         /* Avoid mixing structs and primitive types/enums, they need to be handled differently in the JIT */
5784         if ((MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && !MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)) ||
5785                 (!MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && MONO_TYPE_ISSTRUCT (&return_klass->byval_arg))) {
5786                         if (cfg->verbose_level > 3)
5787                                 printf ("[UNSAFE-MOV-INTRISIC]\tmixing structs and scalars\n");
5788                 return FALSE;
5789         }
5790
5791         if (param_klass->byval_arg.type == MONO_TYPE_R4 || param_klass->byval_arg.type == MONO_TYPE_R8 ||
5792                 return_klass->byval_arg.type == MONO_TYPE_R4 || return_klass->byval_arg.type == MONO_TYPE_R8) {
5793                 if (cfg->verbose_level > 3)
5794                         printf ("[UNSAFE-MOV-INTRISIC]\tfloat or double are not supported\n");
5795                 return FALSE;
5796         }
5797
5798         param_size = mono_class_value_size (param_klass, &align);
5799         return_size = mono_class_value_size (return_klass, &align);
5800
5801         //We can do it if sizes match
5802         if (param_size == return_size) {
5803                 if (cfg->verbose_level > 3)
5804                         printf ("[UNSAFE-MOV-INTRISIC]\tsame size\n");
5805                 return TRUE;
5806         }
5807
5808         //No simple way to handle struct if sizes don't match
5809         if (MONO_TYPE_ISSTRUCT (&param_klass->byval_arg)) {
5810                 if (cfg->verbose_level > 3)
5811                         printf ("[UNSAFE-MOV-INTRISIC]\tsize mismatch and type is a struct\n");
5812                 return FALSE;
5813         }
5814
5815         /*
5816          * Same reg size category.
5817          * A quick note on why we don't require widening here.
5818          * The intrinsic is "R Array.UnsafeMov<S,R> (S s)".
5819          *
5820          * Since the source value comes from a function argument, the JIT will already have
5821          * the value in a VREG and performed any widening needed before (say, when loading from a field).
5822          */
5823         if (param_size <= 4 && return_size <= 4) {
5824                 if (cfg->verbose_level > 3)
5825                         printf ("[UNSAFE-MOV-INTRISIC]\tsize mismatch but both are of the same reg class\n");
5826                 return TRUE;
5827         }
5828
5829         return FALSE;
5830 }
5831
5832 static MonoInst*
5833 emit_array_unsafe_mov (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args)
5834 {
5835         MonoClass *param_klass = mono_class_from_mono_type (fsig->params [0]);
5836         MonoClass *return_klass = mono_class_from_mono_type (fsig->ret);
5837
5838         if (mini_is_gsharedvt_variable_type (fsig->ret))
5839                 return NULL;
5840
5841         //Valuetypes that are semantically equivalent or numbers than can be widened to
5842         if (is_unsafe_mov_compatible (cfg, param_klass, return_klass))
5843                 return args [0];
5844
5845         //Arrays of valuetypes that are semantically equivalent
5846         if (param_klass->rank == 1 && return_klass->rank == 1 && is_unsafe_mov_compatible (cfg, param_klass->element_class, return_klass->element_class))
5847                 return args [0];
5848
5849         return NULL;
5850 }
5851
5852 static MonoInst*
5853 mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5854 {
5855 #ifdef MONO_ARCH_SIMD_INTRINSICS
5856         MonoInst *ins = NULL;
5857
5858         if (cfg->opt & MONO_OPT_SIMD) {
5859                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5860                 if (ins)
5861                         return ins;
5862         }
5863 #endif
5864
5865         return mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
5866 }
5867
5868 static MonoInst*
5869 emit_memory_barrier (MonoCompile *cfg, int kind)
5870 {
5871         MonoInst *ins = NULL;
5872         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
5873         MONO_ADD_INS (cfg->cbb, ins);
5874         ins->backend.memory_barrier_kind = kind;
5875
5876         return ins;
5877 }
5878
5879 static MonoInst*
5880 llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5881 {
5882         MonoInst *ins = NULL;
5883         int opcode = 0;
5884
5885         /* The LLVM backend supports these intrinsics */
5886         if (cmethod->klass == mono_defaults.math_class) {
5887                 if (strcmp (cmethod->name, "Sin") == 0) {
5888                         opcode = OP_SIN;
5889                 } else if (strcmp (cmethod->name, "Cos") == 0) {
5890                         opcode = OP_COS;
5891                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
5892                         opcode = OP_SQRT;
5893                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
5894                         opcode = OP_ABS;
5895                 }
5896
5897                 if (opcode && fsig->param_count == 1) {
5898                         MONO_INST_NEW (cfg, ins, opcode);
5899                         ins->type = STACK_R8;
5900                         ins->dreg = mono_alloc_freg (cfg);
5901                         ins->sreg1 = args [0]->dreg;
5902                         MONO_ADD_INS (cfg->cbb, ins);
5903                 }
5904
5905                 opcode = 0;
5906                 if (cfg->opt & MONO_OPT_CMOV) {
5907                         if (strcmp (cmethod->name, "Min") == 0) {
5908                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5909                                         opcode = OP_IMIN;
5910                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5911                                         opcode = OP_IMIN_UN;
5912                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5913                                         opcode = OP_LMIN;
5914                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5915                                         opcode = OP_LMIN_UN;
5916                         } else if (strcmp (cmethod->name, "Max") == 0) {
5917                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5918                                         opcode = OP_IMAX;
5919                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5920                                         opcode = OP_IMAX_UN;
5921                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5922                                         opcode = OP_LMAX;
5923                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5924                                         opcode = OP_LMAX_UN;
5925                         }
5926                 }
5927
5928                 if (opcode && fsig->param_count == 2) {
5929                         MONO_INST_NEW (cfg, ins, opcode);
5930                         ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
5931                         ins->dreg = mono_alloc_ireg (cfg);
5932                         ins->sreg1 = args [0]->dreg;
5933                         ins->sreg2 = args [1]->dreg;
5934                         MONO_ADD_INS (cfg->cbb, ins);
5935                 }
5936         }
5937
5938         return ins;
5939 }
5940
5941 static MonoInst*
5942 mini_emit_inst_for_sharable_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5943 {
5944         if (cmethod->klass == mono_defaults.array_class) {
5945                 if (strcmp (cmethod->name, "UnsafeStore") == 0)
5946                         return emit_array_unsafe_access (cfg, fsig, args, TRUE);
5947                 else if (strcmp (cmethod->name, "UnsafeLoad") == 0)
5948                         return emit_array_unsafe_access (cfg, fsig, args, FALSE);
5949                 else if (strcmp (cmethod->name, "UnsafeMov") == 0)
5950                         return emit_array_unsafe_mov (cfg, fsig, args);
5951         }
5952
5953         return NULL;
5954 }
5955
5956 static MonoInst*
5957 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5958 {
5959         MonoInst *ins = NULL;
5960
5961          MonoClass *runtime_helpers_class = mono_class_get_runtime_helpers_class ();
5962
5963         if (cmethod->klass == mono_defaults.string_class) {
5964                 if (strcmp (cmethod->name, "get_Chars") == 0 && fsig->param_count + fsig->hasthis == 2) {
5965                         int dreg = alloc_ireg (cfg);
5966                         int index_reg = alloc_preg (cfg);
5967                         int add_reg = alloc_preg (cfg);
5968
5969 #if SIZEOF_REGISTER == 8
5970                         if (COMPILE_LLVM (cfg)) {
5971                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, args [1]->dreg);
5972                         } else {
5973                                 /* The array reg is 64 bits but the index reg is only 32 */
5974                                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index_reg, args [1]->dreg);
5975                         }
5976 #else
5977                         index_reg = args [1]->dreg;
5978 #endif  
5979                         MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
5980
5981 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5982                         EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, MONO_STRUCT_OFFSET (MonoString, chars));
5983                         add_reg = ins->dreg;
5984                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5985                                                                    add_reg, 0);
5986 #else
5987                         int mult_reg = alloc_preg (cfg);
5988                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1);
5989                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5990                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5991                                                                    add_reg, MONO_STRUCT_OFFSET (MonoString, chars));
5992 #endif
5993                         type_from_op (cfg, ins, NULL, NULL);
5994                         return ins;
5995                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
5996                         int dreg = alloc_ireg (cfg);
5997                         /* Decompose later to allow more optimizations */
5998                         EMIT_NEW_UNALU (cfg, ins, OP_STRLEN, dreg, args [0]->dreg);
5999                         ins->type = STACK_I4;
6000                         ins->flags |= MONO_INST_FAULT;
6001                         cfg->cbb->has_array_access = TRUE;
6002                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
6003
6004                         return ins;
6005                 } else 
6006                         return NULL;
6007         } else if (cmethod->klass == mono_defaults.object_class) {
6008                 if (strcmp (cmethod->name, "GetType") == 0 && fsig->param_count + fsig->hasthis == 1) {
6009                         int dreg = alloc_ireg_ref (cfg);
6010                         int vt_reg = alloc_preg (cfg);
6011                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
6012                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, MONO_STRUCT_OFFSET (MonoVTable, type));
6013                         type_from_op (cfg, ins, NULL, NULL);
6014
6015                         return ins;
6016                 } else if (!cfg->backend->emulate_mul_div && strcmp (cmethod->name, "InternalGetHashCode") == 0 && fsig->param_count == 1 && !mono_gc_is_moving ()) {
6017                         int dreg = alloc_ireg (cfg);
6018                         int t1 = alloc_ireg (cfg);
6019         
6020                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, t1, args [0]->dreg, 3);
6021                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_MUL_IMM, dreg, t1, 2654435761u);
6022                         ins->type = STACK_I4;
6023
6024                         return ins;
6025                 } else if (strcmp (cmethod->name, ".ctor") == 0 && fsig->param_count == 0) {
6026                         MONO_INST_NEW (cfg, ins, OP_NOP);
6027                         MONO_ADD_INS (cfg->cbb, ins);
6028                         return ins;
6029                 } else
6030                         return NULL;
6031         } else if (cmethod->klass == mono_defaults.array_class) {
6032                 if (strcmp (cmethod->name, "GetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
6033                         return emit_array_generic_access (cfg, fsig, args, FALSE);
6034                 else if (strcmp (cmethod->name, "SetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
6035                         return emit_array_generic_access (cfg, fsig, args, TRUE);
6036
6037 #ifndef MONO_BIG_ARRAYS
6038                 /*
6039                  * This is an inline version of GetLength/GetLowerBound(0) used frequently in
6040                  * Array methods.
6041                  */
6042                 else if (((strcmp (cmethod->name, "GetLength") == 0 && fsig->param_count + fsig->hasthis == 2) ||
6043                          (strcmp (cmethod->name, "GetLowerBound") == 0 && fsig->param_count + fsig->hasthis == 2)) &&
6044                          args [1]->opcode == OP_ICONST && args [1]->inst_c0 == 0) {
6045                         int dreg = alloc_ireg (cfg);
6046                         int bounds_reg = alloc_ireg_mp (cfg);
6047                         MonoBasicBlock *end_bb, *szarray_bb;
6048                         gboolean get_length = strcmp (cmethod->name, "GetLength") == 0;
6049
6050                         NEW_BBLOCK (cfg, end_bb);
6051                         NEW_BBLOCK (cfg, szarray_bb);
6052
6053                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOAD_MEMBASE, bounds_reg,
6054                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
6055                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
6056                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, szarray_bb);
6057                         /* Non-szarray case */
6058                         if (get_length)
6059                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
6060                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
6061                         else
6062                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
6063                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
6064                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
6065                         MONO_START_BB (cfg, szarray_bb);
6066                         /* Szarray case */
6067                         if (get_length)
6068                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
6069                                                                            args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
6070                         else
6071                                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
6072                         MONO_START_BB (cfg, end_bb);
6073
6074                         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, dreg, dreg);
6075                         ins->type = STACK_I4;
6076                         
6077                         return ins;
6078                 }
6079 #endif
6080
6081                 if (cmethod->name [0] != 'g')
6082                         return NULL;
6083
6084                 if (strcmp (cmethod->name, "get_Rank") == 0 && fsig->param_count + fsig->hasthis == 1) {
6085                         int dreg = alloc_ireg (cfg);
6086                         int vtable_reg = alloc_preg (cfg);
6087                         MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, 
6088                                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
6089                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
6090                                                                    vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
6091                         type_from_op (cfg, ins, NULL, NULL);
6092
6093                         return ins;
6094                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
6095                         int dreg = alloc_ireg (cfg);
6096
6097                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
6098                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
6099                         type_from_op (cfg, ins, NULL, NULL);
6100
6101                         return ins;
6102                 } else
6103                         return NULL;
6104         } else if (cmethod->klass == runtime_helpers_class) {
6105                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0 && fsig->param_count == 0) {
6106                         EMIT_NEW_ICONST (cfg, ins, MONO_STRUCT_OFFSET (MonoString, chars));
6107                         return ins;
6108                 } else
6109                         return NULL;
6110         } else if (cmethod->klass == mono_defaults.monitor_class) {
6111                 gboolean is_enter = FALSE;
6112                 gboolean is_v4 = FALSE;
6113
6114                 if (!strcmp (cmethod->name, "enter_with_atomic_var") && mono_method_signature (cmethod)->param_count == 2) {
6115                         is_enter = TRUE;
6116                         is_v4 = TRUE;
6117                 }
6118                 if (!strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1)
6119                         is_enter = TRUE;
6120
6121                 if (is_enter) {
6122                         /*
6123                          * To make async stack traces work, icalls which can block should have a wrapper.
6124                          * For Monitor.Enter, emit two calls: a fastpath which doesn't have a wrapper, and a slowpath, which does.
6125                          */
6126                         MonoBasicBlock *end_bb;
6127
6128                         NEW_BBLOCK (cfg, end_bb);
6129
6130                         ins = mono_emit_jit_icall (cfg, is_v4 ? (gpointer)mono_monitor_enter_v4_fast : (gpointer)mono_monitor_enter_fast, args);
6131                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, ins->dreg, 0);
6132                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, end_bb);
6133                         ins = mono_emit_jit_icall (cfg, is_v4 ? (gpointer)mono_monitor_enter_v4 : (gpointer)mono_monitor_enter, args);
6134                         MONO_START_BB (cfg, end_bb);
6135                         return ins;
6136                 }
6137         } else if (cmethod->klass == mono_defaults.thread_class) {
6138                 if (strcmp (cmethod->name, "SpinWait_nop") == 0 && fsig->param_count == 0) {
6139                         MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
6140                         MONO_ADD_INS (cfg->cbb, ins);
6141                         return ins;
6142                 } else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0) {
6143                         return emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6144                 } else if (!strcmp (cmethod->name, "VolatileRead") && fsig->param_count == 1) {
6145                         guint32 opcode = 0;
6146                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6147
6148                         if (fsig->params [0]->type == MONO_TYPE_I1)
6149                                 opcode = OP_LOADI1_MEMBASE;
6150                         else if (fsig->params [0]->type == MONO_TYPE_U1)
6151                                 opcode = OP_LOADU1_MEMBASE;
6152                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6153                                 opcode = OP_LOADI2_MEMBASE;
6154                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6155                                 opcode = OP_LOADU2_MEMBASE;
6156                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6157                                 opcode = OP_LOADI4_MEMBASE;
6158                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6159                                 opcode = OP_LOADU4_MEMBASE;
6160                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
6161                                 opcode = OP_LOADI8_MEMBASE;
6162                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6163                                 opcode = OP_LOADR4_MEMBASE;
6164                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6165                                 opcode = OP_LOADR8_MEMBASE;
6166                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
6167                                 opcode = OP_LOAD_MEMBASE;
6168
6169                         if (opcode) {
6170                                 MONO_INST_NEW (cfg, ins, opcode);
6171                                 ins->inst_basereg = args [0]->dreg;
6172                                 ins->inst_offset = 0;
6173                                 MONO_ADD_INS (cfg->cbb, ins);
6174
6175                                 switch (fsig->params [0]->type) {
6176                                 case MONO_TYPE_I1:
6177                                 case MONO_TYPE_U1:
6178                                 case MONO_TYPE_I2:
6179                                 case MONO_TYPE_U2:
6180                                 case MONO_TYPE_I4:
6181                                 case MONO_TYPE_U4:
6182                                         ins->dreg = mono_alloc_ireg (cfg);
6183                                         ins->type = STACK_I4;
6184                                         break;
6185                                 case MONO_TYPE_I8:
6186                                 case MONO_TYPE_U8:
6187                                         ins->dreg = mono_alloc_lreg (cfg);
6188                                         ins->type = STACK_I8;
6189                                         break;
6190                                 case MONO_TYPE_I:
6191                                 case MONO_TYPE_U:
6192                                         ins->dreg = mono_alloc_ireg (cfg);
6193 #if SIZEOF_REGISTER == 8
6194                                         ins->type = STACK_I8;
6195 #else
6196                                         ins->type = STACK_I4;
6197 #endif
6198                                         break;
6199                                 case MONO_TYPE_R4:
6200                                 case MONO_TYPE_R8:
6201                                         ins->dreg = mono_alloc_freg (cfg);
6202                                         ins->type = STACK_R8;
6203                                         break;
6204                                 default:
6205                                         g_assert (mini_type_is_reference (fsig->params [0]));
6206                                         ins->dreg = mono_alloc_ireg_ref (cfg);
6207                                         ins->type = STACK_OBJ;
6208                                         break;
6209                                 }
6210
6211                                 if (opcode == OP_LOADI8_MEMBASE)
6212                                         ins = mono_decompose_opcode (cfg, ins);
6213
6214                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6215
6216                                 return ins;
6217                         }
6218                 } else if (!strcmp (cmethod->name, "VolatileWrite") && fsig->param_count == 2) {
6219                         guint32 opcode = 0;
6220                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6221
6222                         if (fsig->params [0]->type == MONO_TYPE_I1 || fsig->params [0]->type == MONO_TYPE_U1)
6223                                 opcode = OP_STOREI1_MEMBASE_REG;
6224                         else if (fsig->params [0]->type == MONO_TYPE_I2 || fsig->params [0]->type == MONO_TYPE_U2)
6225                                 opcode = OP_STOREI2_MEMBASE_REG;
6226                         else if (fsig->params [0]->type == MONO_TYPE_I4 || fsig->params [0]->type == MONO_TYPE_U4)
6227                                 opcode = OP_STOREI4_MEMBASE_REG;
6228                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
6229                                 opcode = OP_STOREI8_MEMBASE_REG;
6230                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6231                                 opcode = OP_STORER4_MEMBASE_REG;
6232                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6233                                 opcode = OP_STORER8_MEMBASE_REG;
6234                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
6235                                 opcode = OP_STORE_MEMBASE_REG;
6236
6237                         if (opcode) {
6238                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6239
6240                                 MONO_INST_NEW (cfg, ins, opcode);
6241                                 ins->sreg1 = args [1]->dreg;
6242                                 ins->inst_destbasereg = args [0]->dreg;
6243                                 ins->inst_offset = 0;
6244                                 MONO_ADD_INS (cfg->cbb, ins);
6245
6246                                 if (opcode == OP_STOREI8_MEMBASE_REG)
6247                                         ins = mono_decompose_opcode (cfg, ins);
6248
6249                                 return ins;
6250                         }
6251                 }
6252         } else if (cmethod->klass->image == mono_defaults.corlib &&
6253                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6254                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
6255                 ins = NULL;
6256
6257 #if SIZEOF_REGISTER == 8
6258                 if (!cfg->llvm_only && strcmp (cmethod->name, "Read") == 0 && fsig->param_count == 1 && (fsig->params [0]->type == MONO_TYPE_I8)) {
6259                         if (!cfg->llvm_only && mono_arch_opcode_supported (OP_ATOMIC_LOAD_I8)) {
6260                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_LOAD_I8);
6261                                 ins->dreg = mono_alloc_preg (cfg);
6262                                 ins->sreg1 = args [0]->dreg;
6263                                 ins->type = STACK_I8;
6264                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_SEQ;
6265                                 MONO_ADD_INS (cfg->cbb, ins);
6266                         } else {
6267                                 MonoInst *load_ins;
6268
6269                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6270
6271                                 /* 64 bit reads are already atomic */
6272                                 MONO_INST_NEW (cfg, load_ins, OP_LOADI8_MEMBASE);
6273                                 load_ins->dreg = mono_alloc_preg (cfg);
6274                                 load_ins->inst_basereg = args [0]->dreg;
6275                                 load_ins->inst_offset = 0;
6276                                 load_ins->type = STACK_I8;
6277                                 MONO_ADD_INS (cfg->cbb, load_ins);
6278
6279                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6280
6281                                 ins = load_ins;
6282                         }
6283                 }
6284 #endif
6285
6286                 if (strcmp (cmethod->name, "Increment") == 0 && fsig->param_count == 1) {
6287                         MonoInst *ins_iconst;
6288                         guint32 opcode = 0;
6289
6290                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6291                                 opcode = OP_ATOMIC_ADD_I4;
6292                                 cfg->has_atomic_add_i4 = TRUE;
6293                         }
6294 #if SIZEOF_REGISTER == 8
6295                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6296                                 opcode = OP_ATOMIC_ADD_I8;
6297 #endif
6298                         if (opcode) {
6299                                 if (!mono_arch_opcode_supported (opcode))
6300                                         return NULL;
6301                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6302                                 ins_iconst->inst_c0 = 1;
6303                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6304                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6305
6306                                 MONO_INST_NEW (cfg, ins, opcode);
6307                                 ins->dreg = mono_alloc_ireg (cfg);
6308                                 ins->inst_basereg = args [0]->dreg;
6309                                 ins->inst_offset = 0;
6310                                 ins->sreg2 = ins_iconst->dreg;
6311                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6312                                 MONO_ADD_INS (cfg->cbb, ins);
6313                         }
6314                 } else if (strcmp (cmethod->name, "Decrement") == 0 && fsig->param_count == 1) {
6315                         MonoInst *ins_iconst;
6316                         guint32 opcode = 0;
6317
6318                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6319                                 opcode = OP_ATOMIC_ADD_I4;
6320                                 cfg->has_atomic_add_i4 = TRUE;
6321                         }
6322 #if SIZEOF_REGISTER == 8
6323                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6324                                 opcode = OP_ATOMIC_ADD_I8;
6325 #endif
6326                         if (opcode) {
6327                                 if (!mono_arch_opcode_supported (opcode))
6328                                         return NULL;
6329                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6330                                 ins_iconst->inst_c0 = -1;
6331                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6332                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6333
6334                                 MONO_INST_NEW (cfg, ins, opcode);
6335                                 ins->dreg = mono_alloc_ireg (cfg);
6336                                 ins->inst_basereg = args [0]->dreg;
6337                                 ins->inst_offset = 0;
6338                                 ins->sreg2 = ins_iconst->dreg;
6339                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6340                                 MONO_ADD_INS (cfg->cbb, ins);
6341                         }
6342                 } else if (strcmp (cmethod->name, "Add") == 0 && fsig->param_count == 2) {
6343                         guint32 opcode = 0;
6344
6345                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6346                                 opcode = OP_ATOMIC_ADD_I4;
6347                                 cfg->has_atomic_add_i4 = TRUE;
6348                         }
6349 #if SIZEOF_REGISTER == 8
6350                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6351                                 opcode = OP_ATOMIC_ADD_I8;
6352 #endif
6353                         if (opcode) {
6354                                 if (!mono_arch_opcode_supported (opcode))
6355                                         return NULL;
6356                                 MONO_INST_NEW (cfg, ins, opcode);
6357                                 ins->dreg = mono_alloc_ireg (cfg);
6358                                 ins->inst_basereg = args [0]->dreg;
6359                                 ins->inst_offset = 0;
6360                                 ins->sreg2 = args [1]->dreg;
6361                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6362                                 MONO_ADD_INS (cfg->cbb, ins);
6363                         }
6364                 }
6365                 else if (strcmp (cmethod->name, "Exchange") == 0 && fsig->param_count == 2) {
6366                         MonoInst *f2i = NULL, *i2f;
6367                         guint32 opcode, f2i_opcode, i2f_opcode;
6368                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6369                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
6370
6371                         if (fsig->params [0]->type == MONO_TYPE_I4 ||
6372                             fsig->params [0]->type == MONO_TYPE_R4) {
6373                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6374                                 f2i_opcode = OP_MOVE_F_TO_I4;
6375                                 i2f_opcode = OP_MOVE_I4_TO_F;
6376                                 cfg->has_atomic_exchange_i4 = TRUE;
6377                         }
6378 #if SIZEOF_REGISTER == 8
6379                         else if (is_ref ||
6380                                  fsig->params [0]->type == MONO_TYPE_I8 ||
6381                                  fsig->params [0]->type == MONO_TYPE_R8 ||
6382                                  fsig->params [0]->type == MONO_TYPE_I) {
6383                                 opcode = OP_ATOMIC_EXCHANGE_I8;
6384                                 f2i_opcode = OP_MOVE_F_TO_I8;
6385                                 i2f_opcode = OP_MOVE_I8_TO_F;
6386                         }
6387 #else
6388                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I) {
6389                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6390                                 cfg->has_atomic_exchange_i4 = TRUE;
6391                         }
6392 #endif
6393                         else
6394                                 return NULL;
6395
6396                         if (!mono_arch_opcode_supported (opcode))
6397                                 return NULL;
6398
6399                         if (is_float) {
6400                                 /* TODO: Decompose these opcodes instead of bailing here. */
6401                                 if (COMPILE_SOFT_FLOAT (cfg))
6402                                         return NULL;
6403
6404                                 MONO_INST_NEW (cfg, f2i, f2i_opcode);
6405                                 f2i->dreg = mono_alloc_ireg (cfg);
6406                                 f2i->sreg1 = args [1]->dreg;
6407                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6408                                         f2i->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6409                                 MONO_ADD_INS (cfg->cbb, f2i);
6410                         }
6411
6412                         MONO_INST_NEW (cfg, ins, opcode);
6413                         ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : mono_alloc_ireg (cfg);
6414                         ins->inst_basereg = args [0]->dreg;
6415                         ins->inst_offset = 0;
6416                         ins->sreg2 = is_float ? f2i->dreg : args [1]->dreg;
6417                         MONO_ADD_INS (cfg->cbb, ins);
6418
6419                         switch (fsig->params [0]->type) {
6420                         case MONO_TYPE_I4:
6421                                 ins->type = STACK_I4;
6422                                 break;
6423                         case MONO_TYPE_I8:
6424                                 ins->type = STACK_I8;
6425                                 break;
6426                         case MONO_TYPE_I:
6427 #if SIZEOF_REGISTER == 8
6428                                 ins->type = STACK_I8;
6429 #else
6430                                 ins->type = STACK_I4;
6431 #endif
6432                                 break;
6433                         case MONO_TYPE_R4:
6434                         case MONO_TYPE_R8:
6435                                 ins->type = STACK_R8;
6436                                 break;
6437                         default:
6438                                 g_assert (mini_type_is_reference (fsig->params [0]));
6439                                 ins->type = STACK_OBJ;
6440                                 break;
6441                         }
6442
6443                         if (is_float) {
6444                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6445                                 i2f->dreg = mono_alloc_freg (cfg);
6446                                 i2f->sreg1 = ins->dreg;
6447                                 i2f->type = STACK_R8;
6448                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6449                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6450                                 MONO_ADD_INS (cfg->cbb, i2f);
6451
6452                                 ins = i2f;
6453                         }
6454
6455                         if (cfg->gen_write_barriers && is_ref)
6456                                 emit_write_barrier (cfg, args [0], args [1]);
6457                 }
6458                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 3) {
6459                         MonoInst *f2i_new = NULL, *f2i_cmp = NULL, *i2f;
6460                         guint32 opcode, f2i_opcode, i2f_opcode;
6461                         gboolean is_ref = mini_type_is_reference (fsig->params [1]);
6462                         gboolean is_float = fsig->params [1]->type == MONO_TYPE_R4 || fsig->params [1]->type == MONO_TYPE_R8;
6463
6464                         if (fsig->params [1]->type == MONO_TYPE_I4 ||
6465                             fsig->params [1]->type == MONO_TYPE_R4) {
6466                                 opcode = OP_ATOMIC_CAS_I4;
6467                                 f2i_opcode = OP_MOVE_F_TO_I4;
6468                                 i2f_opcode = OP_MOVE_I4_TO_F;
6469                                 cfg->has_atomic_cas_i4 = TRUE;
6470                         }
6471 #if SIZEOF_REGISTER == 8
6472                         else if (is_ref ||
6473                                  fsig->params [1]->type == MONO_TYPE_I8 ||
6474                                  fsig->params [1]->type == MONO_TYPE_R8 ||
6475                                  fsig->params [1]->type == MONO_TYPE_I) {
6476                                 opcode = OP_ATOMIC_CAS_I8;
6477                                 f2i_opcode = OP_MOVE_F_TO_I8;
6478                                 i2f_opcode = OP_MOVE_I8_TO_F;
6479                         }
6480 #else
6481                         else if (is_ref || fsig->params [1]->type == MONO_TYPE_I) {
6482                                 opcode = OP_ATOMIC_CAS_I4;
6483                                 cfg->has_atomic_cas_i4 = TRUE;
6484                         }
6485 #endif
6486                         else
6487                                 return NULL;
6488
6489                         if (!mono_arch_opcode_supported (opcode))
6490                                 return NULL;
6491
6492                         if (is_float) {
6493                                 /* TODO: Decompose these opcodes instead of bailing here. */
6494                                 if (COMPILE_SOFT_FLOAT (cfg))
6495                                         return NULL;
6496
6497                                 MONO_INST_NEW (cfg, f2i_new, f2i_opcode);
6498                                 f2i_new->dreg = mono_alloc_ireg (cfg);
6499                                 f2i_new->sreg1 = args [1]->dreg;
6500                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6501                                         f2i_new->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6502                                 MONO_ADD_INS (cfg->cbb, f2i_new);
6503
6504                                 MONO_INST_NEW (cfg, f2i_cmp, f2i_opcode);
6505                                 f2i_cmp->dreg = mono_alloc_ireg (cfg);
6506                                 f2i_cmp->sreg1 = args [2]->dreg;
6507                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6508                                         f2i_cmp->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6509                                 MONO_ADD_INS (cfg->cbb, f2i_cmp);
6510                         }
6511
6512                         MONO_INST_NEW (cfg, ins, opcode);
6513                         ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
6514                         ins->sreg1 = args [0]->dreg;
6515                         ins->sreg2 = is_float ? f2i_new->dreg : args [1]->dreg;
6516                         ins->sreg3 = is_float ? f2i_cmp->dreg : args [2]->dreg;
6517                         MONO_ADD_INS (cfg->cbb, ins);
6518
6519                         switch (fsig->params [1]->type) {
6520                         case MONO_TYPE_I4:
6521                                 ins->type = STACK_I4;
6522                                 break;
6523                         case MONO_TYPE_I8:
6524                                 ins->type = STACK_I8;
6525                                 break;
6526                         case MONO_TYPE_I:
6527 #if SIZEOF_REGISTER == 8
6528                                 ins->type = STACK_I8;
6529 #else
6530                                 ins->type = STACK_I4;
6531 #endif
6532                                 break;
6533                         case MONO_TYPE_R4:
6534                                 ins->type = cfg->r4_stack_type;
6535                                 break;
6536                         case MONO_TYPE_R8:
6537                                 ins->type = STACK_R8;
6538                                 break;
6539                         default:
6540                                 g_assert (mini_type_is_reference (fsig->params [1]));
6541                                 ins->type = STACK_OBJ;
6542                                 break;
6543                         }
6544
6545                         if (is_float) {
6546                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6547                                 i2f->dreg = mono_alloc_freg (cfg);
6548                                 i2f->sreg1 = ins->dreg;
6549                                 i2f->type = STACK_R8;
6550                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6551                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6552                                 MONO_ADD_INS (cfg->cbb, i2f);
6553
6554                                 ins = i2f;
6555                         }
6556
6557                         if (cfg->gen_write_barriers && is_ref)
6558                                 emit_write_barrier (cfg, args [0], args [1]);
6559                 }
6560                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 4 &&
6561                          fsig->params [1]->type == MONO_TYPE_I4) {
6562                         MonoInst *cmp, *ceq;
6563
6564                         if (!mono_arch_opcode_supported (OP_ATOMIC_CAS_I4))
6565                                 return NULL;
6566
6567                         /* int32 r = CAS (location, value, comparand); */
6568                         MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
6569                         ins->dreg = alloc_ireg (cfg);
6570                         ins->sreg1 = args [0]->dreg;
6571                         ins->sreg2 = args [1]->dreg;
6572                         ins->sreg3 = args [2]->dreg;
6573                         ins->type = STACK_I4;
6574                         MONO_ADD_INS (cfg->cbb, ins);
6575
6576                         /* bool result = r == comparand; */
6577                         MONO_INST_NEW (cfg, cmp, OP_ICOMPARE);
6578                         cmp->sreg1 = ins->dreg;
6579                         cmp->sreg2 = args [2]->dreg;
6580                         cmp->type = STACK_I4;
6581                         MONO_ADD_INS (cfg->cbb, cmp);
6582
6583                         MONO_INST_NEW (cfg, ceq, OP_ICEQ);
6584                         ceq->dreg = alloc_ireg (cfg);
6585                         ceq->type = STACK_I4;
6586                         MONO_ADD_INS (cfg->cbb, ceq);
6587
6588                         /* *success = result; */
6589                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, args [3]->dreg, 0, ceq->dreg);
6590
6591                         cfg->has_atomic_cas_i4 = TRUE;
6592                 }
6593                 else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0)
6594                         ins = emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6595
6596                 if (ins)
6597                         return ins;
6598         } else if (cmethod->klass->image == mono_defaults.corlib &&
6599                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6600                            (strcmp (cmethod->klass->name, "Volatile") == 0)) {
6601                 ins = NULL;
6602
6603                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Read") && fsig->param_count == 1) {
6604                         guint32 opcode = 0;
6605                         MonoType *t = fsig->params [0];
6606                         gboolean is_ref;
6607                         gboolean is_float = t->type == MONO_TYPE_R4 || t->type == MONO_TYPE_R8;
6608
6609                         g_assert (t->byref);
6610                         /* t is a byref type, so the reference check is more complicated */
6611                         is_ref = mini_type_is_reference (&mono_class_from_mono_type (t)->byval_arg);
6612                         if (t->type == MONO_TYPE_I1)
6613                                 opcode = OP_ATOMIC_LOAD_I1;
6614                         else if (t->type == MONO_TYPE_U1 || t->type == MONO_TYPE_BOOLEAN)
6615                                 opcode = OP_ATOMIC_LOAD_U1;
6616                         else if (t->type == MONO_TYPE_I2)
6617                                 opcode = OP_ATOMIC_LOAD_I2;
6618                         else if (t->type == MONO_TYPE_U2)
6619                                 opcode = OP_ATOMIC_LOAD_U2;
6620                         else if (t->type == MONO_TYPE_I4)
6621                                 opcode = OP_ATOMIC_LOAD_I4;
6622                         else if (t->type == MONO_TYPE_U4)
6623                                 opcode = OP_ATOMIC_LOAD_U4;
6624                         else if (t->type == MONO_TYPE_R4)
6625                                 opcode = OP_ATOMIC_LOAD_R4;
6626                         else if (t->type == MONO_TYPE_R8)
6627                                 opcode = OP_ATOMIC_LOAD_R8;
6628 #if SIZEOF_REGISTER == 8
6629                         else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_I)
6630                                 opcode = OP_ATOMIC_LOAD_I8;
6631                         else if (is_ref || t->type == MONO_TYPE_U8 || t->type == MONO_TYPE_U)
6632                                 opcode = OP_ATOMIC_LOAD_U8;
6633 #else
6634                         else if (t->type == MONO_TYPE_I)
6635                                 opcode = OP_ATOMIC_LOAD_I4;
6636                         else if (is_ref || t->type == MONO_TYPE_U)
6637                                 opcode = OP_ATOMIC_LOAD_U4;
6638 #endif
6639
6640                         if (opcode) {
6641                                 if (!mono_arch_opcode_supported (opcode))
6642                                         return NULL;
6643
6644                                 MONO_INST_NEW (cfg, ins, opcode);
6645                                 ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : (is_float ? mono_alloc_freg (cfg) : mono_alloc_ireg (cfg));
6646                                 ins->sreg1 = args [0]->dreg;
6647                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_ACQ;
6648                                 MONO_ADD_INS (cfg->cbb, ins);
6649
6650                                 switch (t->type) {
6651                                 case MONO_TYPE_BOOLEAN:
6652                                 case MONO_TYPE_I1:
6653                                 case MONO_TYPE_U1:
6654                                 case MONO_TYPE_I2:
6655                                 case MONO_TYPE_U2:
6656                                 case MONO_TYPE_I4:
6657                                 case MONO_TYPE_U4:
6658                                         ins->type = STACK_I4;
6659                                         break;
6660                                 case MONO_TYPE_I8:
6661                                 case MONO_TYPE_U8:
6662                                         ins->type = STACK_I8;
6663                                         break;
6664                                 case MONO_TYPE_I:
6665                                 case MONO_TYPE_U:
6666 #if SIZEOF_REGISTER == 8
6667                                         ins->type = STACK_I8;
6668 #else
6669                                         ins->type = STACK_I4;
6670 #endif
6671                                         break;
6672                                 case MONO_TYPE_R4:
6673                                         ins->type = cfg->r4_stack_type;
6674                                         break;
6675                                 case MONO_TYPE_R8:
6676                                         ins->type = STACK_R8;
6677                                         break;
6678                                 default:
6679                                         g_assert (is_ref);
6680                                         ins->type = STACK_OBJ;
6681                                         break;
6682                                 }
6683                         }
6684                 }
6685
6686                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Write") && fsig->param_count == 2) {
6687                         guint32 opcode = 0;
6688                         MonoType *t = fsig->params [0];
6689                         gboolean is_ref;
6690
6691                         g_assert (t->byref);
6692                         is_ref = mini_type_is_reference (&mono_class_from_mono_type (t)->byval_arg);
6693                         if (t->type == MONO_TYPE_I1)
6694                                 opcode = OP_ATOMIC_STORE_I1;
6695                         else if (t->type == MONO_TYPE_U1 || t->type == MONO_TYPE_BOOLEAN)
6696                                 opcode = OP_ATOMIC_STORE_U1;
6697                         else if (t->type == MONO_TYPE_I2)
6698                                 opcode = OP_ATOMIC_STORE_I2;
6699                         else if (t->type == MONO_TYPE_U2)
6700                                 opcode = OP_ATOMIC_STORE_U2;
6701                         else if (t->type == MONO_TYPE_I4)
6702                                 opcode = OP_ATOMIC_STORE_I4;
6703                         else if (t->type == MONO_TYPE_U4)
6704                                 opcode = OP_ATOMIC_STORE_U4;
6705                         else if (t->type == MONO_TYPE_R4)
6706                                 opcode = OP_ATOMIC_STORE_R4;
6707                         else if (t->type == MONO_TYPE_R8)
6708                                 opcode = OP_ATOMIC_STORE_R8;
6709 #if SIZEOF_REGISTER == 8
6710                         else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_I)
6711                                 opcode = OP_ATOMIC_STORE_I8;
6712                         else if (is_ref || t->type == MONO_TYPE_U8 || t->type == MONO_TYPE_U)
6713                                 opcode = OP_ATOMIC_STORE_U8;
6714 #else
6715                         else if (t->type == MONO_TYPE_I)
6716                                 opcode = OP_ATOMIC_STORE_I4;
6717                         else if (is_ref || t->type == MONO_TYPE_U)
6718                                 opcode = OP_ATOMIC_STORE_U4;
6719 #endif
6720
6721                         if (opcode) {
6722                                 if (!mono_arch_opcode_supported (opcode))
6723                                         return NULL;
6724
6725                                 MONO_INST_NEW (cfg, ins, opcode);
6726                                 ins->dreg = args [0]->dreg;
6727                                 ins->sreg1 = args [1]->dreg;
6728                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_REL;
6729                                 MONO_ADD_INS (cfg->cbb, ins);
6730
6731                                 if (cfg->gen_write_barriers && is_ref)
6732                                         emit_write_barrier (cfg, args [0], args [1]);
6733                         }
6734                 }
6735
6736                 if (ins)
6737                         return ins;
6738         } else if (cmethod->klass->image == mono_defaults.corlib &&
6739                            (strcmp (cmethod->klass->name_space, "System.Diagnostics") == 0) &&
6740                            (strcmp (cmethod->klass->name, "Debugger") == 0)) {
6741                 if (!strcmp (cmethod->name, "Break") && fsig->param_count == 0) {
6742                         if (should_insert_brekpoint (cfg->method)) {
6743                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
6744                         } else {
6745                                 MONO_INST_NEW (cfg, ins, OP_NOP);
6746                                 MONO_ADD_INS (cfg->cbb, ins);
6747                         }
6748                         return ins;
6749                 }
6750         } else if (cmethod->klass->image == mono_defaults.corlib &&
6751                    (strcmp (cmethod->klass->name_space, "System") == 0) &&
6752                    (strcmp (cmethod->klass->name, "Environment") == 0)) {
6753                 if (!strcmp (cmethod->name, "get_IsRunningOnWindows") && fsig->param_count == 0) {
6754 #ifdef TARGET_WIN32
6755                         EMIT_NEW_ICONST (cfg, ins, 1);
6756 #else
6757                         EMIT_NEW_ICONST (cfg, ins, 0);
6758 #endif
6759                 }
6760         } else if (cmethod->klass->image == mono_defaults.corlib &&
6761                            (strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
6762                            (strcmp (cmethod->klass->name, "Assembly") == 0)) {
6763                 if (cfg->llvm_only && !strcmp (cmethod->name, "GetExecutingAssembly")) {
6764                         /* No stack walks are currently available, so implement this as an intrinsic */
6765                         MonoInst *assembly_ins;
6766
6767                         EMIT_NEW_AOTCONST (cfg, assembly_ins, MONO_PATCH_INFO_IMAGE, cfg->method->klass->image);
6768                         ins = mono_emit_jit_icall (cfg, mono_get_assembly_object, &assembly_ins);
6769                         return ins;
6770                 }
6771         } else if (cmethod->klass->image == mono_defaults.corlib &&
6772                            (strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
6773                            (strcmp (cmethod->klass->name, "MethodBase") == 0)) {
6774                 if (cfg->llvm_only && !strcmp (cmethod->name, "GetCurrentMethod")) {
6775                         /* No stack walks are currently available, so implement this as an intrinsic */
6776                         MonoInst *method_ins;
6777                         MonoMethod *declaring = cfg->method;
6778
6779                         /* This returns the declaring generic method */
6780                         if (declaring->is_inflated)
6781                                 declaring = ((MonoMethodInflated*)cfg->method)->declaring;
6782                         EMIT_NEW_AOTCONST (cfg, method_ins, MONO_PATCH_INFO_METHODCONST, declaring);
6783                         ins = mono_emit_jit_icall (cfg, mono_get_method_object, &method_ins);
6784                         cfg->no_inline = TRUE;
6785                         if (cfg->method != cfg->current_method)
6786                                 inline_failure (cfg, "MethodBase:GetCurrentMethod ()");
6787                         return ins;
6788                 }
6789         } else if (cmethod->klass == mono_defaults.math_class) {
6790                 /* 
6791                  * There is general branchless code for Min/Max, but it does not work for 
6792                  * all inputs:
6793                  * http://everything2.com/?node_id=1051618
6794                  */
6795         } else if (((!strcmp (cmethod->klass->image->assembly->aname.name, "MonoMac") ||
6796                     !strcmp (cmethod->klass->image->assembly->aname.name, "monotouch")) &&
6797                                 !strcmp (cmethod->klass->name_space, "XamCore.ObjCRuntime") &&
6798                                 !strcmp (cmethod->klass->name, "Selector")) ||
6799                            (!strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.iOS") &&
6800                                 !strcmp (cmethod->klass->name_space, "ObjCRuntime") &&
6801                                 !strcmp (cmethod->klass->name, "Selector"))
6802                            ) {
6803                 if (cfg->backend->have_objc_get_selector &&
6804                         !strcmp (cmethod->name, "GetHandle") && fsig->param_count == 1 &&
6805                     (args [0]->opcode == OP_GOT_ENTRY || args [0]->opcode == OP_AOTCONST) &&
6806                     cfg->compile_aot && !cfg->llvm_only) {
6807                         MonoInst *pi;
6808                         MonoJumpInfoToken *ji;
6809                         MonoString *s;
6810
6811                         // FIXME: llvmonly
6812
6813                         cfg->exception_message = g_strdup ("GetHandle");
6814                         cfg->disable_llvm = TRUE;
6815
6816                         if (args [0]->opcode == OP_GOT_ENTRY) {
6817                                 pi = (MonoInst *)args [0]->inst_p1;
6818                                 g_assert (pi->opcode == OP_PATCH_INFO);
6819                                 g_assert (GPOINTER_TO_INT (pi->inst_p1) == MONO_PATCH_INFO_LDSTR);
6820                                 ji = (MonoJumpInfoToken *)pi->inst_p0;
6821                         } else {
6822                                 g_assert (GPOINTER_TO_INT (args [0]->inst_p1) == MONO_PATCH_INFO_LDSTR);
6823                                 ji = (MonoJumpInfoToken *)args [0]->inst_p0;
6824                         }
6825
6826                         NULLIFY_INS (args [0]);
6827
6828                         // FIXME: Ugly
6829                         s = mono_ldstr (cfg->domain, ji->image, mono_metadata_token_index (ji->token));
6830                         MONO_INST_NEW (cfg, ins, OP_OBJC_GET_SELECTOR);
6831                         ins->dreg = mono_alloc_ireg (cfg);
6832                         // FIXME: Leaks
6833                         ins->inst_p0 = mono_string_to_utf8 (s);
6834                         MONO_ADD_INS (cfg->cbb, ins);
6835                         return ins;
6836                 }
6837         }
6838
6839 #ifdef MONO_ARCH_SIMD_INTRINSICS
6840         if (cfg->opt & MONO_OPT_SIMD) {
6841                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
6842                 if (ins)
6843                         return ins;
6844         }
6845 #endif
6846
6847         ins = mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
6848         if (ins)
6849                 return ins;
6850
6851         if (COMPILE_LLVM (cfg)) {
6852                 ins = llvm_emit_inst_for_method (cfg, cmethod, fsig, args);
6853                 if (ins)
6854                         return ins;
6855         }
6856
6857         return mono_arch_emit_inst_for_method (cfg, cmethod, fsig, args);
6858 }
6859
6860 /*
6861  * This entry point could be used later for arbitrary method
6862  * redirection.
6863  */
6864 inline static MonoInst*
6865 mini_redirect_call (MonoCompile *cfg, MonoMethod *method,  
6866                                         MonoMethodSignature *signature, MonoInst **args, MonoInst *this_ins)
6867 {
6868         if (method->klass == mono_defaults.string_class) {
6869                 /* managed string allocation support */
6870                 if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && !(cfg->opt & MONO_OPT_SHARED)) {
6871                         MonoInst *iargs [2];
6872                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
6873                         MonoMethod *managed_alloc = NULL;
6874
6875                         g_assert (vtable); /*Should not fail since it System.String*/
6876 #ifndef MONO_CROSS_COMPILE
6877                         managed_alloc = mono_gc_get_managed_allocator (method->klass, FALSE, FALSE);
6878 #endif
6879                         if (!managed_alloc)
6880                                 return NULL;
6881                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
6882                         iargs [1] = args [0];
6883                         return mono_emit_method_call (cfg, managed_alloc, iargs, this_ins);
6884                 }
6885         }
6886         return NULL;
6887 }
6888
6889 static void
6890 mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp)
6891 {
6892         MonoInst *store, *temp;
6893         int i;
6894
6895         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
6896                 MonoType *argtype = (sig->hasthis && (i == 0)) ? type_from_stack_type (*sp) : sig->params [i - sig->hasthis];
6897
6898                 /*
6899                  * FIXME: We should use *args++ = sp [0], but that would mean the arg
6900                  * would be different than the MonoInst's used to represent arguments, and
6901                  * the ldelema implementation can't deal with that.
6902                  * Solution: When ldelema is used on an inline argument, create a var for 
6903                  * it, emit ldelema on that var, and emit the saving code below in
6904                  * inline_method () if needed.
6905                  */
6906                 temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
6907                 cfg->args [i] = temp;
6908                 /* This uses cfg->args [i] which is set by the preceeding line */
6909                 EMIT_NEW_ARGSTORE (cfg, store, i, *sp);
6910                 store->cil_code = sp [0]->cil_code;
6911                 sp++;
6912         }
6913 }
6914
6915 #define MONO_INLINE_CALLED_LIMITED_METHODS 1
6916 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
6917
6918 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6919 static gboolean
6920 check_inline_called_method_name_limit (MonoMethod *called_method)
6921 {
6922         int strncmp_result;
6923         static const char *limit = NULL;
6924         
6925         if (limit == NULL) {
6926                 const char *limit_string = g_getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
6927
6928                 if (limit_string != NULL)
6929                         limit = limit_string;
6930                 else
6931                         limit = "";
6932         }
6933
6934         if (limit [0] != '\0') {
6935                 char *called_method_name = mono_method_full_name (called_method, TRUE);
6936
6937                 strncmp_result = strncmp (called_method_name, limit, strlen (limit));
6938                 g_free (called_method_name);
6939         
6940                 //return (strncmp_result <= 0);
6941                 return (strncmp_result == 0);
6942         } else {
6943                 return TRUE;
6944         }
6945 }
6946 #endif
6947
6948 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6949 static gboolean
6950 check_inline_caller_method_name_limit (MonoMethod *caller_method)
6951 {
6952         int strncmp_result;
6953         static const char *limit = NULL;
6954         
6955         if (limit == NULL) {
6956                 const char *limit_string = g_getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
6957                 if (limit_string != NULL) {
6958                         limit = limit_string;
6959                 } else {
6960                         limit = "";
6961                 }
6962         }
6963
6964         if (limit [0] != '\0') {
6965                 char *caller_method_name = mono_method_full_name (caller_method, TRUE);
6966
6967                 strncmp_result = strncmp (caller_method_name, limit, strlen (limit));
6968                 g_free (caller_method_name);
6969         
6970                 //return (strncmp_result <= 0);
6971                 return (strncmp_result == 0);
6972         } else {
6973                 return TRUE;
6974         }
6975 }
6976 #endif
6977
6978 static void
6979 emit_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6980 {
6981         static double r8_0 = 0.0;
6982         static float r4_0 = 0.0;
6983         MonoInst *ins;
6984         int t;
6985
6986         rtype = mini_get_underlying_type (rtype);
6987         t = rtype->type;
6988
6989         if (rtype->byref) {
6990                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6991         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6992                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
6993         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6994                 MONO_EMIT_NEW_I8CONST (cfg, dreg, 0);
6995         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6996                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
6997                 ins->type = STACK_R4;
6998                 ins->inst_p0 = (void*)&r4_0;
6999                 ins->dreg = dreg;
7000                 MONO_ADD_INS (cfg->cbb, ins);
7001         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
7002                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
7003                 ins->type = STACK_R8;
7004                 ins->inst_p0 = (void*)&r8_0;
7005                 ins->dreg = dreg;
7006                 MONO_ADD_INS (cfg->cbb, ins);
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_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
7010         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
7011                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
7012         } else {
7013                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
7014         }
7015 }
7016
7017 static void
7018 emit_dummy_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
7019 {
7020         int t;
7021
7022         rtype = mini_get_underlying_type (rtype);
7023         t = rtype->type;
7024
7025         if (rtype->byref) {
7026                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_PCONST);
7027         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
7028                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_ICONST);
7029         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
7030                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_I8CONST);
7031         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
7032                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R4CONST);
7033         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
7034                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R8CONST);
7035         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
7036                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
7037                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
7038         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
7039                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
7040         } else {
7041                 emit_init_rvar (cfg, dreg, rtype);
7042         }
7043 }
7044
7045 /* If INIT is FALSE, emit dummy initialization statements to keep the IR valid */
7046 static void
7047 emit_init_local (MonoCompile *cfg, int local, MonoType *type, gboolean init)
7048 {
7049         MonoInst *var = cfg->locals [local];
7050         if (COMPILE_SOFT_FLOAT (cfg)) {
7051                 MonoInst *store;
7052                 int reg = alloc_dreg (cfg, (MonoStackType)var->type);
7053                 emit_init_rvar (cfg, reg, type);
7054                 EMIT_NEW_LOCSTORE (cfg, store, local, cfg->cbb->last_ins);
7055         } else {
7056                 if (init)
7057                         emit_init_rvar (cfg, var->dreg, type);
7058                 else
7059                         emit_dummy_init_rvar (cfg, var->dreg, type);
7060         }
7061 }
7062
7063 /*
7064  * inline_method:
7065  *
7066  *   Return the cost of inlining CMETHOD.
7067  */
7068 static int
7069 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
7070                            guchar *ip, guint real_offset, gboolean inline_always)
7071 {
7072         MonoError error;
7073         MonoInst *ins, *rvar = NULL;
7074         MonoMethodHeader *cheader;
7075         MonoBasicBlock *ebblock, *sbblock;
7076         int i, costs;
7077         MonoMethod *prev_inlined_method;
7078         MonoInst **prev_locals, **prev_args;
7079         MonoType **prev_arg_types;
7080         guint prev_real_offset;
7081         GHashTable *prev_cbb_hash;
7082         MonoBasicBlock **prev_cil_offset_to_bb;
7083         MonoBasicBlock *prev_cbb;
7084         unsigned char* prev_cil_start;
7085         guint32 prev_cil_offset_to_bb_len;
7086         MonoMethod *prev_current_method;
7087         MonoGenericContext *prev_generic_context;
7088         gboolean ret_var_set, prev_ret_var_set, prev_disable_inline, virtual_ = FALSE;
7089
7090         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
7091
7092 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
7093         if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod))
7094                 return 0;
7095 #endif
7096 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
7097         if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method))
7098                 return 0;
7099 #endif
7100
7101         if (!fsig)
7102                 fsig = mono_method_signature (cmethod);
7103
7104         if (cfg->verbose_level > 2)
7105                 printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
7106
7107         if (!cmethod->inline_info) {
7108                 cfg->stat_inlineable_methods++;
7109                 cmethod->inline_info = 1;
7110         }
7111
7112         /* allocate local variables */
7113         cheader = mono_method_get_header_checked (cmethod, &error);
7114         if (!cheader) {
7115                 if (inline_always) {
7116                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
7117                         mono_error_move (&cfg->error, &error);
7118                 } else {
7119                         mono_error_cleanup (&error);
7120                 }
7121                 return 0;
7122         }
7123
7124         /*Must verify before creating locals as it can cause the JIT to assert.*/
7125         if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
7126                 mono_metadata_free_mh (cheader);
7127                 return 0;
7128         }
7129
7130         /* allocate space to store the return value */
7131         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
7132                 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
7133         }
7134
7135         prev_locals = cfg->locals;
7136         cfg->locals = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));
7137         for (i = 0; i < cheader->num_locals; ++i)
7138                 cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
7139
7140         /* allocate start and end blocks */
7141         /* This is needed so if the inline is aborted, we can clean up */
7142         NEW_BBLOCK (cfg, sbblock);
7143         sbblock->real_offset = real_offset;
7144
7145         NEW_BBLOCK (cfg, ebblock);
7146         ebblock->block_num = cfg->num_bblocks++;
7147         ebblock->real_offset = real_offset;
7148
7149         prev_args = cfg->args;
7150         prev_arg_types = cfg->arg_types;
7151         prev_inlined_method = cfg->inlined_method;
7152         cfg->inlined_method = cmethod;
7153         cfg->ret_var_set = FALSE;
7154         cfg->inline_depth ++;
7155         prev_real_offset = cfg->real_offset;
7156         prev_cbb_hash = cfg->cbb_hash;
7157         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
7158         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
7159         prev_cil_start = cfg->cil_start;
7160         prev_cbb = cfg->cbb;
7161         prev_current_method = cfg->current_method;
7162         prev_generic_context = cfg->generic_context;
7163         prev_ret_var_set = cfg->ret_var_set;
7164         prev_disable_inline = cfg->disable_inline;
7165
7166         if (ip && *ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
7167                 virtual_ = TRUE;
7168
7169         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, sp, real_offset, virtual_);
7170
7171         ret_var_set = cfg->ret_var_set;
7172
7173         cfg->inlined_method = prev_inlined_method;
7174         cfg->real_offset = prev_real_offset;
7175         cfg->cbb_hash = prev_cbb_hash;
7176         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
7177         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
7178         cfg->cil_start = prev_cil_start;
7179         cfg->locals = prev_locals;
7180         cfg->args = prev_args;
7181         cfg->arg_types = prev_arg_types;
7182         cfg->current_method = prev_current_method;
7183         cfg->generic_context = prev_generic_context;
7184         cfg->ret_var_set = prev_ret_var_set;
7185         cfg->disable_inline = prev_disable_inline;
7186         cfg->inline_depth --;
7187
7188         if ((costs >= 0 && costs < 60) || inline_always || (costs >= 0 && (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))) {
7189                 if (cfg->verbose_level > 2)
7190                         printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
7191                 
7192                 cfg->stat_inlined_methods++;
7193
7194                 /* always add some code to avoid block split failures */
7195                 MONO_INST_NEW (cfg, ins, OP_NOP);
7196                 MONO_ADD_INS (prev_cbb, ins);
7197
7198                 prev_cbb->next_bb = sbblock;
7199                 link_bblock (cfg, prev_cbb, sbblock);
7200
7201                 /* 
7202                  * Get rid of the begin and end bblocks if possible to aid local
7203                  * optimizations.
7204                  */
7205                 mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
7206
7207                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
7208                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
7209
7210                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
7211                         MonoBasicBlock *prev = ebblock->in_bb [0];
7212
7213                         if (prev->next_bb == ebblock) {
7214                                 mono_merge_basic_blocks (cfg, prev, ebblock);
7215                                 cfg->cbb = prev;
7216                                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
7217                                         mono_merge_basic_blocks (cfg, prev_cbb, prev);
7218                                         cfg->cbb = prev_cbb;
7219                                 }
7220                         } else {
7221                                 /* There could be a bblock after 'prev', and making 'prev' the current bb could cause problems */
7222                                 cfg->cbb = ebblock;
7223                         }
7224                 } else {
7225                         /* 
7226                          * Its possible that the rvar is set in some prev bblock, but not in others.
7227                          * (#1835).
7228                          */
7229                         if (rvar) {
7230                                 MonoBasicBlock *bb;
7231
7232                                 for (i = 0; i < ebblock->in_count; ++i) {
7233                                         bb = ebblock->in_bb [i];
7234
7235                                         if (bb->last_ins && bb->last_ins->opcode == OP_NOT_REACHED) {
7236                                                 cfg->cbb = bb;
7237
7238                                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
7239                                         }
7240                                 }
7241                         }
7242
7243                         cfg->cbb = ebblock;
7244                 }
7245
7246                 if (rvar) {
7247                         /*
7248                          * If the inlined method contains only a throw, then the ret var is not 
7249                          * set, so set it to a dummy value.
7250                          */
7251                         if (!ret_var_set)
7252                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
7253
7254                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
7255                         *sp++ = ins;
7256                 }
7257                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
7258                 return costs + 1;
7259         } else {
7260                 if (cfg->verbose_level > 2)
7261                         printf ("INLINE ABORTED %s (cost %d)\n", mono_method_full_name (cmethod, TRUE), costs);
7262                 cfg->exception_type = MONO_EXCEPTION_NONE;
7263                 mono_loader_clear_error ();
7264
7265                 /* This gets rid of the newly added bblocks */
7266                 cfg->cbb = prev_cbb;
7267         }
7268         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
7269         return 0;
7270 }
7271
7272 /*
7273  * Some of these comments may well be out-of-date.
7274  * Design decisions: we do a single pass over the IL code (and we do bblock 
7275  * splitting/merging in the few cases when it's required: a back jump to an IL
7276  * address that was not already seen as bblock starting point).
7277  * Code is validated as we go (full verification is still better left to metadata/verify.c).
7278  * Complex operations are decomposed in simpler ones right away. We need to let the 
7279  * arch-specific code peek and poke inside this process somehow (except when the 
7280  * optimizations can take advantage of the full semantic info of coarse opcodes).
7281  * All the opcodes of the form opcode.s are 'normalized' to opcode.
7282  * MonoInst->opcode initially is the IL opcode or some simplification of that 
7283  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
7284  * opcode with value bigger than OP_LAST.
7285  * At this point the IR can be handed over to an interpreter, a dumb code generator
7286  * or to the optimizing code generator that will translate it to SSA form.
7287  *
7288  * Profiling directed optimizations.
7289  * We may compile by default with few or no optimizations and instrument the code
7290  * or the user may indicate what methods to optimize the most either in a config file
7291  * or through repeated runs where the compiler applies offline the optimizations to 
7292  * each method and then decides if it was worth it.
7293  */
7294
7295 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
7296 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
7297 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
7298 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
7299 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
7300 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
7301 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
7302 #define CHECK_TYPELOAD(klass) if (!(klass) || mono_class_has_failure (klass)) TYPE_LOAD_ERROR ((klass))
7303
7304 /* offset from br.s -> br like opcodes */
7305 #define BIG_BRANCH_OFFSET 13
7306
7307 static gboolean
7308 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
7309 {
7310         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
7311
7312         return b == NULL || b == bb;
7313 }
7314
7315 static int
7316 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
7317 {
7318         unsigned char *ip = start;
7319         unsigned char *target;
7320         int i;
7321         guint cli_addr;
7322         MonoBasicBlock *bblock;
7323         const MonoOpcode *opcode;
7324
7325         while (ip < end) {
7326                 cli_addr = ip - start;
7327                 i = mono_opcode_value ((const guint8 **)&ip, end);
7328                 if (i < 0)
7329                         UNVERIFIED;
7330                 opcode = &mono_opcodes [i];
7331                 switch (opcode->argument) {
7332                 case MonoInlineNone:
7333                         ip++; 
7334                         break;
7335                 case MonoInlineString:
7336                 case MonoInlineType:
7337                 case MonoInlineField:
7338                 case MonoInlineMethod:
7339                 case MonoInlineTok:
7340                 case MonoInlineSig:
7341                 case MonoShortInlineR:
7342                 case MonoInlineI:
7343                         ip += 5;
7344                         break;
7345                 case MonoInlineVar:
7346                         ip += 3;
7347                         break;
7348                 case MonoShortInlineVar:
7349                 case MonoShortInlineI:
7350                         ip += 2;
7351                         break;
7352                 case MonoShortInlineBrTarget:
7353                         target = start + cli_addr + 2 + (signed char)ip [1];
7354                         GET_BBLOCK (cfg, bblock, target);
7355                         ip += 2;
7356                         if (ip < end)
7357                                 GET_BBLOCK (cfg, bblock, ip);
7358                         break;
7359                 case MonoInlineBrTarget:
7360                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
7361                         GET_BBLOCK (cfg, bblock, target);
7362                         ip += 5;
7363                         if (ip < end)
7364                                 GET_BBLOCK (cfg, bblock, ip);
7365                         break;
7366                 case MonoInlineSwitch: {
7367                         guint32 n = read32 (ip + 1);
7368                         guint32 j;
7369                         ip += 5;
7370                         cli_addr += 5 + 4 * n;
7371                         target = start + cli_addr;
7372                         GET_BBLOCK (cfg, bblock, target);
7373                         
7374                         for (j = 0; j < n; ++j) {
7375                                 target = start + cli_addr + (gint32)read32 (ip);
7376                                 GET_BBLOCK (cfg, bblock, target);
7377                                 ip += 4;
7378                         }
7379                         break;
7380                 }
7381                 case MonoInlineR:
7382                 case MonoInlineI8:
7383                         ip += 9;
7384                         break;
7385                 default:
7386                         g_assert_not_reached ();
7387                 }
7388
7389                 if (i == CEE_THROW) {
7390                         unsigned char *bb_start = ip - 1;
7391                         
7392                         /* Find the start of the bblock containing the throw */
7393                         bblock = NULL;
7394                         while ((bb_start >= start) && !bblock) {
7395                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
7396                                 bb_start --;
7397                         }
7398                         if (bblock)
7399                                 bblock->out_of_line = 1;
7400                 }
7401         }
7402         return 0;
7403 unverified:
7404 exception_exit:
7405         *pos = ip;
7406         return 1;
7407 }
7408
7409 static inline MonoMethod *
7410 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context, MonoError *error)
7411 {
7412         MonoMethod *method;
7413
7414         mono_error_init (error);
7415
7416         if (m->wrapper_type != MONO_WRAPPER_NONE) {
7417                 method = (MonoMethod *)mono_method_get_wrapper_data (m, token);
7418                 if (context) {
7419                         method = mono_class_inflate_generic_method_checked (method, context, error);
7420                 }
7421         } else {
7422                 method = mono_get_method_checked (m->klass->image, token, klass, context, error);
7423         }
7424
7425         return method;
7426 }
7427
7428 static inline MonoMethod *
7429 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
7430 {
7431         MonoError error;
7432         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context, cfg ? &cfg->error : &error);
7433
7434         if (method && cfg && !cfg->gshared && mono_class_is_open_constructed_type (&method->klass->byval_arg)) {
7435                 mono_error_set_bad_image (&cfg->error, cfg->method->klass->image, "Method with open type while not compiling gshared");
7436                 method = NULL;
7437         }
7438
7439         if (!method && !cfg)
7440                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
7441
7442         return method;
7443 }
7444
7445 static inline MonoClass*
7446 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
7447 {
7448         MonoError error;
7449         MonoClass *klass;
7450
7451         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7452                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
7453                 if (context) {
7454                         klass = mono_class_inflate_generic_class_checked (klass, context, &error);
7455                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7456                 }
7457         } else {
7458                 klass = mono_class_get_and_inflate_typespec_checked (method->klass->image, token, context, &error);
7459                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
7460         }
7461         if (klass)
7462                 mono_class_init (klass);
7463         return klass;
7464 }
7465
7466 static inline MonoMethodSignature*
7467 mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context)
7468 {
7469         MonoMethodSignature *fsig;
7470
7471         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7472                 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
7473         } else {
7474                 fsig = mono_metadata_parse_signature (method->klass->image, token);
7475         }
7476         if (context) {
7477                 MonoError error;
7478                 fsig = mono_inflate_generic_signature(fsig, context, &error);
7479                 // FIXME:
7480                 g_assert(mono_error_ok(&error));
7481         }
7482         return fsig;
7483 }
7484
7485 static MonoMethod*
7486 throw_exception (void)
7487 {
7488         static MonoMethod *method = NULL;
7489
7490         if (!method) {
7491                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
7492                 method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
7493         }
7494         g_assert (method);
7495         return method;
7496 }
7497
7498 static void
7499 emit_throw_exception (MonoCompile *cfg, MonoException *ex)
7500 {
7501         MonoMethod *thrower = throw_exception ();
7502         MonoInst *args [1];
7503
7504         EMIT_NEW_PCONST (cfg, args [0], ex);
7505         mono_emit_method_call (cfg, thrower, args, NULL);
7506 }
7507
7508 /*
7509  * Return the original method is a wrapper is specified. We can only access 
7510  * the custom attributes from the original method.
7511  */
7512 static MonoMethod*
7513 get_original_method (MonoMethod *method)
7514 {
7515         if (method->wrapper_type == MONO_WRAPPER_NONE)
7516                 return method;
7517
7518         /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
7519         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
7520                 return NULL;
7521
7522         /* in other cases we need to find the original method */
7523         return mono_marshal_method_from_wrapper (method);
7524 }
7525
7526 static void
7527 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field)
7528 {
7529         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7530         MonoException *ex = mono_security_core_clr_is_field_access_allowed (get_original_method (caller), field);
7531         if (ex)
7532                 emit_throw_exception (cfg, ex);
7533 }
7534
7535 static void
7536 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
7537 {
7538         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7539         MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
7540         if (ex)
7541                 emit_throw_exception (cfg, ex);
7542 }
7543
7544 /*
7545  * Check that the IL instructions at ip are the array initialization
7546  * sequence and return the pointer to the data and the size.
7547  */
7548 static const char*
7549 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
7550 {
7551         /*
7552          * newarr[System.Int32]
7553          * dup
7554          * ldtoken field valuetype ...
7555          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
7556          */
7557         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
7558                 MonoError error;
7559                 guint32 token = read32 (ip + 7);
7560                 guint32 field_token = read32 (ip + 2);
7561                 guint32 field_index = field_token & 0xffffff;
7562                 guint32 rva;
7563                 const char *data_ptr;
7564                 int size = 0;
7565                 MonoMethod *cmethod;
7566                 MonoClass *dummy_class;
7567                 MonoClassField *field = mono_field_from_token_checked (method->klass->image, field_token, &dummy_class, NULL, &error);
7568                 int dummy_align;
7569
7570                 if (!field) {
7571                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7572                         return NULL;
7573                 }
7574
7575                 *out_field_token = field_token;
7576
7577                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
7578                 if (!cmethod)
7579                         return NULL;
7580                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
7581                         return NULL;
7582                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
7583                 case MONO_TYPE_BOOLEAN:
7584                 case MONO_TYPE_I1:
7585                 case MONO_TYPE_U1:
7586                         size = 1; break;
7587                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
7588 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
7589                 case MONO_TYPE_CHAR:
7590                 case MONO_TYPE_I2:
7591                 case MONO_TYPE_U2:
7592                         size = 2; break;
7593                 case MONO_TYPE_I4:
7594                 case MONO_TYPE_U4:
7595                 case MONO_TYPE_R4:
7596                         size = 4; break;
7597                 case MONO_TYPE_R8:
7598                 case MONO_TYPE_I8:
7599                 case MONO_TYPE_U8:
7600                         size = 8; break;
7601 #endif
7602                 default:
7603                         return NULL;
7604                 }
7605                 size *= len;
7606                 if (size > mono_type_size (field->type, &dummy_align))
7607                     return NULL;
7608                 *out_size = size;
7609                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
7610                 if (!image_is_dynamic (method->klass->image)) {
7611                         field_index = read32 (ip + 2) & 0xffffff;
7612                         mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
7613                         data_ptr = mono_image_rva_map (method->klass->image, rva);
7614                         /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
7615                         /* for aot code we do the lookup on load */
7616                         if (aot && data_ptr)
7617                                 return (const char *)GUINT_TO_POINTER (rva);
7618                 } else {
7619                         /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
7620                         g_assert (!aot);
7621                         data_ptr = mono_field_get_data (field);
7622                 }
7623                 return data_ptr;
7624         }
7625         return NULL;
7626 }
7627
7628 static void
7629 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
7630 {
7631         MonoError error;
7632         char *method_fname = mono_method_full_name (method, TRUE);
7633         char *method_code;
7634         MonoMethodHeader *header = mono_method_get_header_checked (method, &error);
7635
7636         if (!header) {
7637                 method_code = g_strdup_printf ("could not parse method body due to %s", mono_error_get_message (&error));
7638                 mono_error_cleanup (&error);
7639         } else if (header->code_size == 0)
7640                 method_code = g_strdup ("method body is empty.");
7641         else
7642                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
7643         mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code));
7644         g_free (method_fname);
7645         g_free (method_code);
7646         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
7647 }
7648
7649 static void
7650 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
7651 {
7652         MonoInst *ins;
7653         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
7654         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
7655                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
7656                 /* Optimize reg-reg moves away */
7657                 /* 
7658                  * Can't optimize other opcodes, since sp[0] might point to
7659                  * the last ins of a decomposed opcode.
7660                  */
7661                 sp [0]->dreg = (cfg)->locals [n]->dreg;
7662         } else {
7663                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
7664         }
7665 }
7666
7667 /*
7668  * ldloca inhibits many optimizations so try to get rid of it in common
7669  * cases.
7670  */
7671 static inline unsigned char *
7672 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
7673 {
7674         int local, token;
7675         MonoClass *klass;
7676         MonoType *type;
7677
7678         if (size == 1) {
7679                 local = ip [1];
7680                 ip += 2;
7681         } else {
7682                 local = read16 (ip + 2);
7683                 ip += 4;
7684         }
7685         
7686         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
7687                 /* From the INITOBJ case */
7688                 token = read32 (ip + 2);
7689                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
7690                 CHECK_TYPELOAD (klass);
7691                 type = mini_get_underlying_type (&klass->byval_arg);
7692                 emit_init_local (cfg, local, type, TRUE);
7693                 return ip + 6;
7694         }
7695  exception_exit:
7696         return NULL;
7697 }
7698
7699 static MonoInst*
7700 emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used, MonoInst **sp)
7701 {
7702         MonoInst *icall_args [16];
7703         MonoInst *call_target, *ins, *vtable_ins;
7704         int arg_reg, this_reg, vtable_reg;
7705         gboolean is_iface = cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE;
7706         gboolean is_gsharedvt = cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig);
7707         gboolean variant_iface = FALSE;
7708         guint32 slot;
7709         int offset;
7710
7711         /*
7712          * In llvm-only mode, vtables contain function descriptors instead of
7713          * method addresses/trampolines.
7714          */
7715         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
7716
7717         if (is_iface)
7718                 slot = mono_method_get_imt_slot (cmethod);
7719         else
7720                 slot = mono_method_get_vtable_index (cmethod);
7721
7722         this_reg = sp [0]->dreg;
7723
7724         if (is_iface && mono_class_has_variant_generic_params (cmethod->klass))
7725                 variant_iface = TRUE;
7726
7727         if (!fsig->generic_param_count && !is_iface && !is_gsharedvt) {
7728                 /*
7729                  * The simplest case, a normal virtual call.
7730                  */
7731                 int slot_reg = alloc_preg (cfg);
7732                 int addr_reg = alloc_preg (cfg);
7733                 int arg_reg = alloc_preg (cfg);
7734                 MonoBasicBlock *non_null_bb;
7735
7736                 vtable_reg = alloc_preg (cfg);
7737                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7738                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) + (slot * SIZEOF_VOID_P);
7739
7740                 /* Load the vtable slot, which contains a function descriptor. */
7741                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7742
7743                 NEW_BBLOCK (cfg, non_null_bb);
7744
7745                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, slot_reg, 0);
7746                 cfg->cbb->last_ins->flags |= MONO_INST_LIKELY;
7747                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, non_null_bb);
7748
7749                 /* Slow path */
7750                 // FIXME: Make the wrapper use the preserveall cconv
7751                 // FIXME: Use one icall per slot for small slot numbers ?
7752                 icall_args [0] = vtable_ins;
7753                 EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7754                 /* Make the icall return the vtable slot value to save some code space */
7755                 ins = mono_emit_jit_icall (cfg, mono_init_vtable_slot, icall_args);
7756                 ins->dreg = slot_reg;
7757                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, non_null_bb);
7758
7759                 /* Fastpath */
7760                 MONO_START_BB (cfg, non_null_bb);
7761                 /* Load the address + arg from the vtable slot */
7762                 EMIT_NEW_LOAD_MEMBASE (cfg, call_target, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7763                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, arg_reg, slot_reg, SIZEOF_VOID_P);
7764
7765                 return emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
7766         }
7767
7768         if (!fsig->generic_param_count && is_iface && !variant_iface && !is_gsharedvt) {
7769                 /*
7770                  * A simple interface call
7771                  *
7772                  * We make a call through an imt slot to obtain the function descriptor we need to call.
7773                  * The imt slot contains a function descriptor for a runtime function + arg.
7774                  */
7775                 int slot_reg = alloc_preg (cfg);
7776                 int addr_reg = alloc_preg (cfg);
7777                 int arg_reg = alloc_preg (cfg);
7778                 MonoInst *thunk_addr_ins, *thunk_arg_ins, *ftndesc_ins;
7779
7780                 vtable_reg = alloc_preg (cfg);
7781                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7782                 offset = ((gint32)slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
7783
7784                 /*
7785                  * The slot is already initialized when the vtable is created so there is no need
7786                  * to check it here.
7787                  */
7788
7789                 /* Load the imt slot, which contains a function descriptor. */
7790                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7791
7792                 /* Load the address + arg of the imt thunk from the imt slot */
7793                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_addr_ins, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7794                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_arg_ins, OP_LOAD_MEMBASE, arg_reg, slot_reg, SIZEOF_VOID_P);
7795                 /*
7796                  * IMT thunks in llvm-only mode are C functions which take an info argument
7797                  * plus the imt method and return the ftndesc to call.
7798                  */
7799                 icall_args [0] = thunk_arg_ins;
7800                 icall_args [1] = emit_get_rgctx_method (cfg, context_used,
7801                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7802                 ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_thunk, icall_args, thunk_addr_ins, NULL, NULL);
7803
7804                 return emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
7805         }
7806
7807         if ((fsig->generic_param_count || variant_iface) && !is_gsharedvt) {
7808                 /*
7809                  * This is similar to the interface case, the vtable slot points to an imt thunk which is
7810                  * dynamically extended as more instantiations are discovered.
7811                  * This handles generic virtual methods both on classes and interfaces.
7812                  */
7813                 int slot_reg = alloc_preg (cfg);
7814                 int addr_reg = alloc_preg (cfg);
7815                 int arg_reg = alloc_preg (cfg);
7816                 int ftndesc_reg = alloc_preg (cfg);
7817                 MonoInst *thunk_addr_ins, *thunk_arg_ins, *ftndesc_ins;
7818                 MonoBasicBlock *slowpath_bb, *end_bb;
7819
7820                 NEW_BBLOCK (cfg, slowpath_bb);
7821                 NEW_BBLOCK (cfg, end_bb);
7822
7823                 vtable_reg = alloc_preg (cfg);
7824                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7825                 if (is_iface)
7826                         offset = ((gint32)slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
7827                 else
7828                         offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) + (slot * SIZEOF_VOID_P);
7829
7830                 /* Load the slot, which contains a function descriptor. */
7831                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7832
7833                 /* These slots are not initialized, so fall back to the slow path until they are initialized */
7834                 /* That happens when mono_method_add_generic_virtual_invocation () creates an IMT thunk */
7835                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, slot_reg, 0);
7836                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, slowpath_bb);
7837
7838                 /* Fastpath */
7839                 /* Same as with iface calls */
7840                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_addr_ins, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7841                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_arg_ins, OP_LOAD_MEMBASE, arg_reg, slot_reg, SIZEOF_VOID_P);
7842                 icall_args [0] = thunk_arg_ins;
7843                 icall_args [1] = emit_get_rgctx_method (cfg, context_used,
7844                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7845                 ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_thunk, icall_args, thunk_addr_ins, NULL, NULL);
7846                 ftndesc_ins->dreg = ftndesc_reg;
7847                 /*
7848                  * Unlike normal iface calls, these imt thunks can return NULL, i.e. when they are passed an instantiation
7849                  * they don't know about yet. Fall back to the slowpath in that case.
7850                  */
7851                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ftndesc_reg, 0);
7852                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, slowpath_bb);
7853
7854                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
7855
7856                 /* Slowpath */
7857                 MONO_START_BB (cfg, slowpath_bb);
7858                 icall_args [0] = vtable_ins;
7859                 EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7860                 icall_args [2] = emit_get_rgctx_method (cfg, context_used,
7861                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7862                 if (is_iface)
7863                         ftndesc_ins = mono_emit_jit_icall (cfg, mono_resolve_generic_virtual_iface_call, icall_args);
7864                 else
7865                         ftndesc_ins = mono_emit_jit_icall (cfg, mono_resolve_generic_virtual_call, icall_args);
7866                 ftndesc_ins->dreg = ftndesc_reg;
7867                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
7868
7869                 /* Common case */
7870                 MONO_START_BB (cfg, end_bb);
7871                 return emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
7872         }
7873
7874         /*
7875          * Non-optimized cases
7876          */
7877         icall_args [0] = sp [0];
7878         EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7879
7880         icall_args [2] = emit_get_rgctx_method (cfg, context_used,
7881                                                                                         cmethod, MONO_RGCTX_INFO_METHOD);
7882
7883         arg_reg = alloc_preg (cfg);
7884         MONO_EMIT_NEW_PCONST (cfg, arg_reg, NULL);
7885         EMIT_NEW_VARLOADA_VREG (cfg, icall_args [3], arg_reg, &mono_defaults.int_class->byval_arg);
7886
7887         g_assert (is_gsharedvt);
7888         if (is_iface)
7889                 call_target = mono_emit_jit_icall (cfg, mono_resolve_iface_call_gsharedvt, icall_args);
7890         else
7891                 call_target = mono_emit_jit_icall (cfg, mono_resolve_vcall_gsharedvt, icall_args);
7892
7893         /*
7894          * Pass the extra argument even if the callee doesn't receive it, most
7895          * calling conventions allow this.
7896          */
7897         return emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
7898 }
7899
7900 static gboolean
7901 is_exception_class (MonoClass *klass)
7902 {
7903         while (klass) {
7904                 if (klass == mono_defaults.exception_class)
7905                         return TRUE;
7906                 klass = klass->parent;
7907         }
7908         return FALSE;
7909 }
7910
7911 /*
7912  * is_jit_optimizer_disabled:
7913  *
7914  *   Determine whenever M's assembly has a DebuggableAttribute with the
7915  * IsJITOptimizerDisabled flag set.
7916  */
7917 static gboolean
7918 is_jit_optimizer_disabled (MonoMethod *m)
7919 {
7920         MonoError error;
7921         MonoAssembly *ass = m->klass->image->assembly;
7922         MonoCustomAttrInfo* attrs;
7923         MonoClass *klass;
7924         int i;
7925         gboolean val = FALSE;
7926
7927         g_assert (ass);
7928         if (ass->jit_optimizer_disabled_inited)
7929                 return ass->jit_optimizer_disabled;
7930
7931         klass = mono_class_try_get_debuggable_attribute_class ();
7932
7933         if (!klass) {
7934                 /* Linked away */
7935                 ass->jit_optimizer_disabled = FALSE;
7936                 mono_memory_barrier ();
7937                 ass->jit_optimizer_disabled_inited = TRUE;
7938                 return FALSE;
7939         }
7940
7941         attrs = mono_custom_attrs_from_assembly_checked (ass, &error);
7942         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7943         if (attrs) {
7944                 for (i = 0; i < attrs->num_attrs; ++i) {
7945                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
7946                         const gchar *p;
7947                         MonoMethodSignature *sig;
7948
7949                         if (!attr->ctor || attr->ctor->klass != klass)
7950                                 continue;
7951                         /* Decode the attribute. See reflection.c */
7952                         p = (const char*)attr->data;
7953                         g_assert (read16 (p) == 0x0001);
7954                         p += 2;
7955
7956                         // FIXME: Support named parameters
7957                         sig = mono_method_signature (attr->ctor);
7958                         if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
7959                                 continue;
7960                         /* Two boolean arguments */
7961                         p ++;
7962                         val = *p;
7963                 }
7964                 mono_custom_attrs_free (attrs);
7965         }
7966
7967         ass->jit_optimizer_disabled = val;
7968         mono_memory_barrier ();
7969         ass->jit_optimizer_disabled_inited = TRUE;
7970
7971         return val;
7972 }
7973
7974 static gboolean
7975 is_supported_tail_call (MonoCompile *cfg, MonoMethod *method, MonoMethod *cmethod, MonoMethodSignature *fsig, int call_opcode)
7976 {
7977         gboolean supported_tail_call;
7978         int i;
7979
7980         supported_tail_call = mono_arch_tail_call_supported (cfg, mono_method_signature (method), mono_method_signature (cmethod));
7981
7982         for (i = 0; i < fsig->param_count; ++i) {
7983                 if (fsig->params [i]->byref || fsig->params [i]->type == MONO_TYPE_PTR || fsig->params [i]->type == MONO_TYPE_FNPTR)
7984                         /* These can point to the current method's stack */
7985                         supported_tail_call = FALSE;
7986         }
7987         if (fsig->hasthis && cmethod->klass->valuetype)
7988                 /* this might point to the current method's stack */
7989                 supported_tail_call = FALSE;
7990         if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
7991                 supported_tail_call = FALSE;
7992         if (cfg->method->save_lmf)
7993                 supported_tail_call = FALSE;
7994         if (cmethod->wrapper_type && cmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
7995                 supported_tail_call = FALSE;
7996         if (call_opcode != CEE_CALL)
7997                 supported_tail_call = FALSE;
7998
7999         /* Debugging support */
8000 #if 0
8001         if (supported_tail_call) {
8002                 if (!mono_debug_count ())
8003                         supported_tail_call = FALSE;
8004         }
8005 #endif
8006
8007         return supported_tail_call;
8008 }
8009
8010 /*
8011  * handle_ctor_call:
8012  *
8013  *   Handle calls made to ctors from NEWOBJ opcodes.
8014  */
8015 static void
8016 handle_ctor_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used,
8017                                   MonoInst **sp, guint8 *ip, int *inline_costs)
8018 {
8019         MonoInst *vtable_arg = NULL, *callvirt_this_arg = NULL, *ins;
8020
8021         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
8022                                         mono_method_is_generic_sharable (cmethod, TRUE)) {
8023                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
8024                         mono_class_vtable (cfg->domain, cmethod->klass);
8025                         CHECK_TYPELOAD (cmethod->klass);
8026
8027                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
8028                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
8029                 } else {
8030                         if (context_used) {
8031                                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
8032                                                                                                    cmethod->klass, MONO_RGCTX_INFO_VTABLE);
8033                         } else {
8034                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
8035
8036                                 CHECK_TYPELOAD (cmethod->klass);
8037                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
8038                         }
8039                 }
8040         }
8041
8042         /* Avoid virtual calls to ctors if possible */
8043         if (mono_class_is_marshalbyref (cmethod->klass))
8044                 callvirt_this_arg = sp [0];
8045
8046         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
8047                 g_assert (MONO_TYPE_IS_VOID (fsig->ret));
8048                 CHECK_CFG_EXCEPTION;
8049         } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
8050                            mono_method_check_inlining (cfg, cmethod) &&
8051                            !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE)) {
8052                 int costs;
8053
8054                 if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, FALSE))) {
8055                         cfg->real_offset += 5;
8056
8057                         *inline_costs += costs - 5;
8058                 } else {
8059                         INLINE_FAILURE ("inline failure");
8060                         // FIXME-VT: Clean this up
8061                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
8062                                 GSHAREDVT_FAILURE(*ip);
8063                         mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, callvirt_this_arg, NULL, NULL);
8064                 }
8065         } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
8066                 MonoInst *addr;
8067
8068                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
8069
8070                 if (cfg->llvm_only) {
8071                         // FIXME: Avoid initializing vtable_arg
8072                         emit_llvmonly_calli (cfg, fsig, sp, addr);
8073                 } else {
8074                         mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
8075                 }
8076         } else if (context_used &&
8077                            ((!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
8078                                  !mono_class_generic_sharing_enabled (cmethod->klass)) || cfg->gsharedvt)) {
8079                 MonoInst *cmethod_addr;
8080
8081                 /* Generic calls made out of gsharedvt methods cannot be patched, so use an indirect call */
8082
8083                 if (cfg->llvm_only) {
8084                         MonoInst *addr = emit_get_rgctx_method (cfg, context_used, cmethod,
8085                                                                                                         MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
8086                         emit_llvmonly_calli (cfg, fsig, sp, addr);
8087                 } else {
8088                         cmethod_addr = emit_get_rgctx_method (cfg, context_used,
8089                                                                                                   cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
8090
8091                         mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
8092                 }
8093         } else {
8094                 INLINE_FAILURE ("ctor call");
8095                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
8096                                                                                   callvirt_this_arg, NULL, vtable_arg);
8097         }
8098  exception_exit:
8099         return;
8100 }
8101
8102 static void
8103 emit_setret (MonoCompile *cfg, MonoInst *val)
8104 {
8105         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (cfg->method)->ret);
8106         MonoInst *ins;
8107
8108         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
8109                 MonoInst *ret_addr;
8110
8111                 if (!cfg->vret_addr) {
8112                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, val);
8113                 } else {
8114                         EMIT_NEW_RETLOADA (cfg, ret_addr);
8115
8116                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, val->dreg);
8117                         ins->klass = mono_class_from_mono_type (ret_type);
8118                 }
8119         } else {
8120 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
8121                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
8122                         MonoInst *iargs [1];
8123                         MonoInst *conv;
8124
8125                         iargs [0] = val;
8126                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
8127                         mono_arch_emit_setret (cfg, cfg->method, conv);
8128                 } else {
8129                         mono_arch_emit_setret (cfg, cfg->method, val);
8130                 }
8131 #else
8132                 mono_arch_emit_setret (cfg, cfg->method, val);
8133 #endif
8134         }
8135 }
8136
8137 /*
8138  * mono_method_to_ir:
8139  *
8140  *   Translate the .net IL into linear IR.
8141  */
8142 int
8143 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
8144                    MonoInst *return_var, MonoInst **inline_args, 
8145                    guint inline_offset, gboolean is_virtual_call)
8146 {
8147         MonoError error;
8148         MonoInst *ins, **sp, **stack_start;
8149         MonoBasicBlock *tblock = NULL, *init_localsbb = NULL;
8150         MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
8151         MonoMethod *cmethod, *method_definition;
8152         MonoInst **arg_array;
8153         MonoMethodHeader *header;
8154         MonoImage *image;
8155         guint32 token, ins_flag;
8156         MonoClass *klass;
8157         MonoClass *constrained_class = NULL;
8158         unsigned char *ip, *end, *target, *err_pos;
8159         MonoMethodSignature *sig;
8160         MonoGenericContext *generic_context = NULL;
8161         MonoGenericContainer *generic_container = NULL;
8162         MonoType **param_types;
8163         int i, n, start_new_bblock, dreg;
8164         int num_calls = 0, inline_costs = 0;
8165         int breakpoint_id = 0;
8166         guint num_args;
8167         GSList *class_inits = NULL;
8168         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
8169         int context_used;
8170         gboolean init_locals, seq_points, skip_dead_blocks;
8171         gboolean sym_seq_points = FALSE;
8172         MonoDebugMethodInfo *minfo;
8173         MonoBitSet *seq_point_locs = NULL;
8174         MonoBitSet *seq_point_set_locs = NULL;
8175
8176         cfg->disable_inline = is_jit_optimizer_disabled (method);
8177
8178         /* serialization and xdomain stuff may need access to private fields and methods */
8179         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
8180         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
8181         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
8182         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
8183         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
8184         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
8185
8186         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
8187         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
8188         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
8189         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
8190         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF;
8191
8192         image = method->klass->image;
8193         header = mono_method_get_header_checked (method, &cfg->error);
8194         if (!header) {
8195                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
8196                 goto exception_exit;
8197         }
8198         generic_container = mono_method_get_generic_container (method);
8199         sig = mono_method_signature (method);
8200         num_args = sig->hasthis + sig->param_count;
8201         ip = (unsigned char*)header->code;
8202         cfg->cil_start = ip;
8203         end = ip + header->code_size;
8204         cfg->stat_cil_code_size += header->code_size;
8205
8206         seq_points = cfg->gen_seq_points && cfg->method == method;
8207
8208         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
8209                 /* We could hit a seq point before attaching to the JIT (#8338) */
8210                 seq_points = FALSE;
8211         }
8212
8213         if (cfg->gen_sdb_seq_points && cfg->method == method) {
8214                 minfo = mono_debug_lookup_method (method);
8215                 if (minfo) {
8216                         MonoSymSeqPoint *sps;
8217                         int i, n_il_offsets;
8218
8219                         mono_debug_get_seq_points (minfo, NULL, NULL, NULL, &sps, &n_il_offsets);
8220                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
8221                         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);
8222                         sym_seq_points = TRUE;
8223                         for (i = 0; i < n_il_offsets; ++i) {
8224                                 if (sps [i].il_offset < header->code_size)
8225                                         mono_bitset_set_fast (seq_point_locs, sps [i].il_offset);
8226                         }
8227                         g_free (sps);
8228                 } else if (!method->wrapper_type && !method->dynamic && mono_debug_image_has_debug_info (method->klass->image)) {
8229                         /* Methods without line number info like auto-generated property accessors */
8230                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
8231                         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);
8232                         sym_seq_points = TRUE;
8233                 }
8234         }
8235
8236         /* 
8237          * Methods without init_locals set could cause asserts in various passes
8238          * (#497220). To work around this, we emit dummy initialization opcodes
8239          * (OP_DUMMY_ICONST etc.) which generate no code. These are only supported
8240          * on some platforms.
8241          */
8242         if ((cfg->opt & MONO_OPT_UNSAFE) && cfg->backend->have_dummy_init)
8243                 init_locals = header->init_locals;
8244         else
8245                 init_locals = TRUE;
8246
8247         method_definition = method;
8248         while (method_definition->is_inflated) {
8249                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
8250                 method_definition = imethod->declaring;
8251         }
8252
8253         /* SkipVerification is not allowed if core-clr is enabled */
8254         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
8255                 dont_verify = TRUE;
8256                 dont_verify_stloc = TRUE;
8257         }
8258
8259         if (sig->is_inflated)
8260                 generic_context = mono_method_get_context (method);
8261         else if (generic_container)
8262                 generic_context = &generic_container->context;
8263         cfg->generic_context = generic_context;
8264
8265         if (!cfg->gshared)
8266                 g_assert (!sig->has_type_parameters);
8267
8268         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
8269                 g_assert (method->is_inflated);
8270                 g_assert (mono_method_get_context (method)->method_inst);
8271         }
8272         if (method->is_inflated && mono_method_get_context (method)->method_inst)
8273                 g_assert (sig->generic_param_count);
8274
8275         if (cfg->method == method) {
8276                 cfg->real_offset = 0;
8277         } else {
8278                 cfg->real_offset = inline_offset;
8279         }
8280
8281         cfg->cil_offset_to_bb = (MonoBasicBlock **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
8282         cfg->cil_offset_to_bb_len = header->code_size;
8283
8284         cfg->current_method = method;
8285
8286         if (cfg->verbose_level > 2)
8287                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
8288
8289         param_types = (MonoType **)mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
8290         if (sig->hasthis)
8291                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
8292         for (n = 0; n < sig->param_count; ++n)
8293                 param_types [n + sig->hasthis] = sig->params [n];
8294         cfg->arg_types = param_types;
8295
8296         cfg->dont_inline = g_list_prepend (cfg->dont_inline, method);
8297         if (cfg->method == method) {
8298
8299                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
8300                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
8301
8302                 /* ENTRY BLOCK */
8303                 NEW_BBLOCK (cfg, start_bblock);
8304                 cfg->bb_entry = start_bblock;
8305                 start_bblock->cil_code = NULL;
8306                 start_bblock->cil_length = 0;
8307
8308                 /* EXIT BLOCK */
8309                 NEW_BBLOCK (cfg, end_bblock);
8310                 cfg->bb_exit = end_bblock;
8311                 end_bblock->cil_code = NULL;
8312                 end_bblock->cil_length = 0;
8313                 end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
8314                 g_assert (cfg->num_bblocks == 2);
8315
8316                 arg_array = cfg->args;
8317
8318                 if (header->num_clauses) {
8319                         cfg->spvars = g_hash_table_new (NULL, NULL);
8320                         cfg->exvars = g_hash_table_new (NULL, NULL);
8321                 }
8322                 /* handle exception clauses */
8323                 for (i = 0; i < header->num_clauses; ++i) {
8324                         MonoBasicBlock *try_bb;
8325                         MonoExceptionClause *clause = &header->clauses [i];
8326                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
8327
8328                         try_bb->real_offset = clause->try_offset;
8329                         try_bb->try_start = TRUE;
8330                         try_bb->region = ((i + 1) << 8) | clause->flags;
8331                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
8332                         tblock->real_offset = clause->handler_offset;
8333                         tblock->flags |= BB_EXCEPTION_HANDLER;
8334
8335                         /*
8336                          * Linking the try block with the EH block hinders inlining as we won't be able to 
8337                          * merge the bblocks from inlining and produce an artificial hole for no good reason.
8338                          */
8339                         if (COMPILE_LLVM (cfg))
8340                                 link_bblock (cfg, try_bb, tblock);
8341
8342                         if (*(ip + clause->handler_offset) == CEE_POP)
8343                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
8344
8345                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
8346                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
8347                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
8348                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
8349                                 MONO_ADD_INS (tblock, ins);
8350
8351                                 if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FILTER) {
8352                                         /* finally clauses already have a seq point */
8353                                         /* seq points for filter clauses are emitted below */
8354                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
8355                                         MONO_ADD_INS (tblock, ins);
8356                                 }
8357
8358                                 /* todo: is a fault block unsafe to optimize? */
8359                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
8360                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
8361                         }
8362
8363                         /*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);
8364                           while (p < end) {
8365                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
8366                           }*/
8367                         /* catch and filter blocks get the exception object on the stack */
8368                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
8369                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8370
8371                                 /* mostly like handle_stack_args (), but just sets the input args */
8372                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
8373                                 tblock->in_scount = 1;
8374                                 tblock->in_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
8375                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
8376
8377                                 cfg->cbb = tblock;
8378
8379 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
8380                                 /* The EH code passes in the exception in a register to both JITted and LLVM compiled code */
8381                                 if (!cfg->compile_llvm) {
8382                                         MONO_INST_NEW (cfg, ins, OP_GET_EX_OBJ);
8383                                         ins->dreg = tblock->in_stack [0]->dreg;
8384                                         MONO_ADD_INS (tblock, ins);
8385                                 }
8386 #else
8387                                 MonoInst *dummy_use;
8388
8389                                 /* 
8390                                  * Add a dummy use for the exvar so its liveness info will be
8391                                  * correct.
8392                                  */
8393                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
8394 #endif
8395
8396                                 if (seq_points && clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8397                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
8398                                         MONO_ADD_INS (tblock, ins);
8399                                 }
8400                                 
8401                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8402                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
8403                                         tblock->flags |= BB_EXCEPTION_HANDLER;
8404                                         tblock->real_offset = clause->data.filter_offset;
8405                                         tblock->in_scount = 1;
8406                                         tblock->in_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
8407                                         /* The filter block shares the exvar with the handler block */
8408                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
8409                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
8410                                         MONO_ADD_INS (tblock, ins);
8411                                 }
8412                         }
8413
8414                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
8415                                         clause->data.catch_class &&
8416                                         cfg->gshared &&
8417                                         mono_class_check_context_used (clause->data.catch_class)) {
8418                                 /*
8419                                  * In shared generic code with catch
8420                                  * clauses containing type variables
8421                                  * the exception handling code has to
8422                                  * be able to get to the rgctx.
8423                                  * Therefore we have to make sure that
8424                                  * the vtable/mrgctx argument (for
8425                                  * static or generic methods) or the
8426                                  * "this" argument (for non-static
8427                                  * methods) are live.
8428                                  */
8429                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8430                                                 mini_method_get_context (method)->method_inst ||
8431                                                 method->klass->valuetype) {
8432                                         mono_get_vtable_var (cfg);
8433                                 } else {
8434                                         MonoInst *dummy_use;
8435
8436                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
8437                                 }
8438                         }
8439                 }
8440         } else {
8441                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
8442                 cfg->cbb = start_bblock;
8443                 cfg->args = arg_array;
8444                 mono_save_args (cfg, sig, inline_args);
8445         }
8446
8447         /* FIRST CODE BLOCK */
8448         NEW_BBLOCK (cfg, tblock);
8449         tblock->cil_code = ip;
8450         cfg->cbb = tblock;
8451         cfg->ip = ip;
8452
8453         ADD_BBLOCK (cfg, tblock);
8454
8455         if (cfg->method == method) {
8456                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
8457                 if (breakpoint_id) {
8458                         MONO_INST_NEW (cfg, ins, OP_BREAK);
8459                         MONO_ADD_INS (cfg->cbb, ins);
8460                 }
8461         }
8462
8463         /* we use a separate basic block for the initialization code */
8464         NEW_BBLOCK (cfg, init_localsbb);
8465         cfg->bb_init = init_localsbb;
8466         init_localsbb->real_offset = cfg->real_offset;
8467         start_bblock->next_bb = init_localsbb;
8468         init_localsbb->next_bb = cfg->cbb;
8469         link_bblock (cfg, start_bblock, init_localsbb);
8470         link_bblock (cfg, init_localsbb, cfg->cbb);
8471                 
8472         cfg->cbb = init_localsbb;
8473
8474         if (cfg->gsharedvt && cfg->method == method) {
8475                 MonoGSharedVtMethodInfo *info;
8476                 MonoInst *var, *locals_var;
8477                 int dreg;
8478
8479                 info = (MonoGSharedVtMethodInfo *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoGSharedVtMethodInfo));
8480                 info->method = cfg->method;
8481                 info->count_entries = 16;
8482                 info->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
8483                 cfg->gsharedvt_info = info;
8484
8485                 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8486                 /* prevent it from being register allocated */
8487                 //var->flags |= MONO_INST_VOLATILE;
8488                 cfg->gsharedvt_info_var = var;
8489
8490                 ins = emit_get_rgctx_gsharedvt_method (cfg, mini_method_check_context_used (cfg, method), method, info);
8491                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, var->dreg, ins->dreg);
8492
8493                 /* Allocate locals */
8494                 locals_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8495                 /* prevent it from being register allocated */
8496                 //locals_var->flags |= MONO_INST_VOLATILE;
8497                 cfg->gsharedvt_locals_var = locals_var;
8498
8499                 dreg = alloc_ireg (cfg);
8500                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, dreg, var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, locals_size));
8501
8502                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
8503                 ins->dreg = locals_var->dreg;
8504                 ins->sreg1 = dreg;
8505                 MONO_ADD_INS (cfg->cbb, ins);
8506                 cfg->gsharedvt_locals_var_ins = ins;
8507                 
8508                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
8509                 /*
8510                 if (init_locals)
8511                         ins->flags |= MONO_INST_INIT;
8512                 */
8513         }
8514
8515         if (mono_security_core_clr_enabled ()) {
8516                 /* check if this is native code, e.g. an icall or a p/invoke */
8517                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
8518                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
8519                         if (wrapped) {
8520                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
8521                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
8522
8523                                 /* if this ia a native call then it can only be JITted from platform code */
8524                                 if ((icall || pinvk) && method->klass && method->klass->image) {
8525                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
8526                                                 MonoException *ex = icall ? mono_get_exception_security () : 
8527                                                         mono_get_exception_method_access ();
8528                                                 emit_throw_exception (cfg, ex);
8529                                         }
8530                                 }
8531                         }
8532                 }
8533         }
8534
8535         CHECK_CFG_EXCEPTION;
8536
8537         if (header->code_size == 0)
8538                 UNVERIFIED;
8539
8540         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
8541                 ip = err_pos;
8542                 UNVERIFIED;
8543         }
8544
8545         if (cfg->method == method)
8546                 mono_debug_init_method (cfg, cfg->cbb, breakpoint_id);
8547
8548         for (n = 0; n < header->num_locals; ++n) {
8549                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
8550                         UNVERIFIED;
8551         }
8552         class_inits = NULL;
8553
8554         /* We force the vtable variable here for all shared methods
8555            for the possibility that they might show up in a stack
8556            trace where their exact instantiation is needed. */
8557         if (cfg->gshared && method == cfg->method) {
8558                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8559                                 mini_method_get_context (method)->method_inst ||
8560                                 method->klass->valuetype) {
8561                         mono_get_vtable_var (cfg);
8562                 } else {
8563                         /* FIXME: Is there a better way to do this?
8564                            We need the variable live for the duration
8565                            of the whole method. */
8566                         cfg->args [0]->flags |= MONO_INST_VOLATILE;
8567                 }
8568         }
8569
8570         /* add a check for this != NULL to inlined methods */
8571         if (is_virtual_call) {
8572                 MonoInst *arg_ins;
8573
8574                 NEW_ARGLOAD (cfg, arg_ins, 0);
8575                 MONO_ADD_INS (cfg->cbb, arg_ins);
8576                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
8577         }
8578
8579         skip_dead_blocks = !dont_verify;
8580         if (skip_dead_blocks) {
8581                 original_bb = bb = mono_basic_block_split (method, &cfg->error);
8582                 CHECK_CFG_ERROR;
8583                 g_assert (bb);
8584         }
8585
8586         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
8587         stack_start = sp = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
8588
8589         ins_flag = 0;
8590         start_new_bblock = 0;
8591         while (ip < end) {
8592                 if (cfg->method == method)
8593                         cfg->real_offset = ip - header->code;
8594                 else
8595                         cfg->real_offset = inline_offset;
8596                 cfg->ip = ip;
8597
8598                 context_used = 0;
8599
8600                 if (start_new_bblock) {
8601                         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
8602                         if (start_new_bblock == 2) {
8603                                 g_assert (ip == tblock->cil_code);
8604                         } else {
8605                                 GET_BBLOCK (cfg, tblock, ip);
8606                         }
8607                         cfg->cbb->next_bb = tblock;
8608                         cfg->cbb = tblock;
8609                         start_new_bblock = 0;
8610                         for (i = 0; i < cfg->cbb->in_scount; ++i) {
8611                                 if (cfg->verbose_level > 3)
8612                                         printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8613                                 EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8614                                 *sp++ = ins;
8615                         }
8616                         if (class_inits)
8617                                 g_slist_free (class_inits);
8618                         class_inits = NULL;
8619                 } else {
8620                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != cfg->cbb)) {
8621                                 link_bblock (cfg, cfg->cbb, tblock);
8622                                 if (sp != stack_start) {
8623                                         handle_stack_args (cfg, stack_start, sp - stack_start);
8624                                         sp = stack_start;
8625                                         CHECK_UNVERIFIABLE (cfg);
8626                                 }
8627                                 cfg->cbb->next_bb = tblock;
8628                                 cfg->cbb = tblock;
8629                                 for (i = 0; i < cfg->cbb->in_scount; ++i) {
8630                                         if (cfg->verbose_level > 3)
8631                                                 printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8632                                         EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8633                                         *sp++ = ins;
8634                                 }
8635                                 g_slist_free (class_inits);
8636                                 class_inits = NULL;
8637                         }
8638                 }
8639
8640                 if (skip_dead_blocks) {
8641                         int ip_offset = ip - header->code;
8642
8643                         if (ip_offset == bb->end)
8644                                 bb = bb->next;
8645
8646                         if (bb->dead) {
8647                                 int op_size = mono_opcode_size (ip, end);
8648                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
8649
8650                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
8651
8652                                 if (ip_offset + op_size == bb->end) {
8653                                         MONO_INST_NEW (cfg, ins, OP_NOP);
8654                                         MONO_ADD_INS (cfg->cbb, ins);
8655                                         start_new_bblock = 1;
8656                                 }
8657
8658                                 ip += op_size;
8659                                 continue;
8660                         }
8661                 }
8662                 /*
8663                  * Sequence points are points where the debugger can place a breakpoint.
8664                  * Currently, we generate these automatically at points where the IL
8665                  * stack is empty.
8666                  */
8667                 if (seq_points && ((!sym_seq_points && (sp == stack_start)) || (sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code)))) {
8668                         /*
8669                          * Make methods interruptable at the beginning, and at the targets of
8670                          * backward branches.
8671                          * Also, do this at the start of every bblock in methods with clauses too,
8672                          * to be able to handle instructions with inprecise control flow like
8673                          * throw/endfinally.
8674                          * Backward branches are handled at the end of method-to-ir ().
8675                          */
8676                         gboolean intr_loc = ip == header->code || (!cfg->cbb->last_ins && cfg->header->num_clauses);
8677                         gboolean sym_seq_point = sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code);
8678
8679                         /* Avoid sequence points on empty IL like .volatile */
8680                         // FIXME: Enable this
8681                         //if (!(cfg->cbb->last_ins && cfg->cbb->last_ins->opcode == OP_SEQ_POINT)) {
8682                         NEW_SEQ_POINT (cfg, ins, ip - header->code, intr_loc);
8683                         if ((sp != stack_start) && !sym_seq_point)
8684                                 ins->flags |= MONO_INST_NONEMPTY_STACK;
8685                         MONO_ADD_INS (cfg->cbb, ins);
8686
8687                         if (sym_seq_points)
8688                                 mono_bitset_set_fast (seq_point_set_locs, ip - header->code);
8689                 }
8690
8691                 cfg->cbb->real_offset = cfg->real_offset;
8692
8693                 if ((cfg->method == method) && cfg->coverage_info) {
8694                         guint32 cil_offset = ip - header->code;
8695                         cfg->coverage_info->data [cil_offset].cil_code = ip;
8696
8697                         /* TODO: Use an increment here */
8698 #if defined(TARGET_X86)
8699                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
8700                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
8701                         ins->inst_imm = 1;
8702                         MONO_ADD_INS (cfg->cbb, ins);
8703 #else
8704                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
8705                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
8706 #endif
8707                 }
8708
8709                 if (cfg->verbose_level > 3)
8710                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
8711
8712                 switch (*ip) {
8713                 case CEE_NOP:
8714                         if (seq_points && !sym_seq_points && sp != stack_start) {
8715                                 /*
8716                                  * The C# compiler uses these nops to notify the JIT that it should
8717                                  * insert seq points.
8718                                  */
8719                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, FALSE);
8720                                 MONO_ADD_INS (cfg->cbb, ins);
8721                         }
8722                         if (cfg->keep_cil_nops)
8723                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
8724                         else
8725                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8726                         ip++;
8727                         MONO_ADD_INS (cfg->cbb, ins);
8728                         break;
8729                 case CEE_BREAK:
8730                         if (should_insert_brekpoint (cfg->method)) {
8731                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
8732                         } else {
8733                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8734                         }
8735                         ip++;
8736                         MONO_ADD_INS (cfg->cbb, ins);
8737                         break;
8738                 case CEE_LDARG_0:
8739                 case CEE_LDARG_1:
8740                 case CEE_LDARG_2:
8741                 case CEE_LDARG_3:
8742                         CHECK_STACK_OVF (1);
8743                         n = (*ip)-CEE_LDARG_0;
8744                         CHECK_ARG (n);
8745                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8746                         ip++;
8747                         *sp++ = ins;
8748                         break;
8749                 case CEE_LDLOC_0:
8750                 case CEE_LDLOC_1:
8751                 case CEE_LDLOC_2:
8752                 case CEE_LDLOC_3:
8753                         CHECK_STACK_OVF (1);
8754                         n = (*ip)-CEE_LDLOC_0;
8755                         CHECK_LOCAL (n);
8756                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8757                         ip++;
8758                         *sp++ = ins;
8759                         break;
8760                 case CEE_STLOC_0:
8761                 case CEE_STLOC_1:
8762                 case CEE_STLOC_2:
8763                 case CEE_STLOC_3: {
8764                         CHECK_STACK (1);
8765                         n = (*ip)-CEE_STLOC_0;
8766                         CHECK_LOCAL (n);
8767                         --sp;
8768                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
8769                                 UNVERIFIED;
8770                         emit_stloc_ir (cfg, sp, header, n);
8771                         ++ip;
8772                         inline_costs += 1;
8773                         break;
8774                         }
8775                 case CEE_LDARG_S:
8776                         CHECK_OPSIZE (2);
8777                         CHECK_STACK_OVF (1);
8778                         n = ip [1];
8779                         CHECK_ARG (n);
8780                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8781                         *sp++ = ins;
8782                         ip += 2;
8783                         break;
8784                 case CEE_LDARGA_S:
8785                         CHECK_OPSIZE (2);
8786                         CHECK_STACK_OVF (1);
8787                         n = ip [1];
8788                         CHECK_ARG (n);
8789                         NEW_ARGLOADA (cfg, ins, n);
8790                         MONO_ADD_INS (cfg->cbb, ins);
8791                         *sp++ = ins;
8792                         ip += 2;
8793                         break;
8794                 case CEE_STARG_S:
8795                         CHECK_OPSIZE (2);
8796                         CHECK_STACK (1);
8797                         --sp;
8798                         n = ip [1];
8799                         CHECK_ARG (n);
8800                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
8801                                 UNVERIFIED;
8802                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
8803                         ip += 2;
8804                         break;
8805                 case CEE_LDLOC_S:
8806                         CHECK_OPSIZE (2);
8807                         CHECK_STACK_OVF (1);
8808                         n = ip [1];
8809                         CHECK_LOCAL (n);
8810                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8811                         *sp++ = ins;
8812                         ip += 2;
8813                         break;
8814                 case CEE_LDLOCA_S: {
8815                         unsigned char *tmp_ip;
8816                         CHECK_OPSIZE (2);
8817                         CHECK_STACK_OVF (1);
8818                         CHECK_LOCAL (ip [1]);
8819
8820                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
8821                                 ip = tmp_ip;
8822                                 inline_costs += 1;
8823                                 break;
8824                         }
8825
8826                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
8827                         *sp++ = ins;
8828                         ip += 2;
8829                         break;
8830                 }
8831                 case CEE_STLOC_S:
8832                         CHECK_OPSIZE (2);
8833                         CHECK_STACK (1);
8834                         --sp;
8835                         CHECK_LOCAL (ip [1]);
8836                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
8837                                 UNVERIFIED;
8838                         emit_stloc_ir (cfg, sp, header, ip [1]);
8839                         ip += 2;
8840                         inline_costs += 1;
8841                         break;
8842                 case CEE_LDNULL:
8843                         CHECK_STACK_OVF (1);
8844                         EMIT_NEW_PCONST (cfg, ins, NULL);
8845                         ins->type = STACK_OBJ;
8846                         ++ip;
8847                         *sp++ = ins;
8848                         break;
8849                 case CEE_LDC_I4_M1:
8850                         CHECK_STACK_OVF (1);
8851                         EMIT_NEW_ICONST (cfg, ins, -1);
8852                         ++ip;
8853                         *sp++ = ins;
8854                         break;
8855                 case CEE_LDC_I4_0:
8856                 case CEE_LDC_I4_1:
8857                 case CEE_LDC_I4_2:
8858                 case CEE_LDC_I4_3:
8859                 case CEE_LDC_I4_4:
8860                 case CEE_LDC_I4_5:
8861                 case CEE_LDC_I4_6:
8862                 case CEE_LDC_I4_7:
8863                 case CEE_LDC_I4_8:
8864                         CHECK_STACK_OVF (1);
8865                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
8866                         ++ip;
8867                         *sp++ = ins;
8868                         break;
8869                 case CEE_LDC_I4_S:
8870                         CHECK_OPSIZE (2);
8871                         CHECK_STACK_OVF (1);
8872                         ++ip;
8873                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
8874                         ++ip;
8875                         *sp++ = ins;
8876                         break;
8877                 case CEE_LDC_I4:
8878                         CHECK_OPSIZE (5);
8879                         CHECK_STACK_OVF (1);
8880                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
8881                         ip += 5;
8882                         *sp++ = ins;
8883                         break;
8884                 case CEE_LDC_I8:
8885                         CHECK_OPSIZE (9);
8886                         CHECK_STACK_OVF (1);
8887                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
8888                         ins->type = STACK_I8;
8889                         ins->dreg = alloc_dreg (cfg, STACK_I8);
8890                         ++ip;
8891                         ins->inst_l = (gint64)read64 (ip);
8892                         MONO_ADD_INS (cfg->cbb, ins);
8893                         ip += 8;
8894                         *sp++ = ins;
8895                         break;
8896                 case CEE_LDC_R4: {
8897                         float *f;
8898                         gboolean use_aotconst = FALSE;
8899
8900 #ifdef TARGET_POWERPC
8901                         /* FIXME: Clean this up */
8902                         if (cfg->compile_aot)
8903                                 use_aotconst = TRUE;
8904 #endif
8905
8906                         /* FIXME: we should really allocate this only late in the compilation process */
8907                         f = (float *)mono_domain_alloc (cfg->domain, sizeof (float));
8908                         CHECK_OPSIZE (5);
8909                         CHECK_STACK_OVF (1);
8910
8911                         if (use_aotconst) {
8912                                 MonoInst *cons;
8913                                 int dreg;
8914
8915                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
8916
8917                                 dreg = alloc_freg (cfg);
8918                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
8919                                 ins->type = cfg->r4_stack_type;
8920                         } else {
8921                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
8922                                 ins->type = cfg->r4_stack_type;
8923                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8924                                 ins->inst_p0 = f;
8925                                 MONO_ADD_INS (cfg->cbb, ins);
8926                         }
8927                         ++ip;
8928                         readr4 (ip, f);
8929                         ip += 4;
8930                         *sp++ = ins;                    
8931                         break;
8932                 }
8933                 case CEE_LDC_R8: {
8934                         double *d;
8935                         gboolean use_aotconst = FALSE;
8936
8937 #ifdef TARGET_POWERPC
8938                         /* FIXME: Clean this up */
8939                         if (cfg->compile_aot)
8940                                 use_aotconst = TRUE;
8941 #endif
8942
8943                         /* FIXME: we should really allocate this only late in the compilation process */
8944                         d = (double *)mono_domain_alloc (cfg->domain, sizeof (double));
8945                         CHECK_OPSIZE (9);
8946                         CHECK_STACK_OVF (1);
8947
8948                         if (use_aotconst) {
8949                                 MonoInst *cons;
8950                                 int dreg;
8951
8952                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
8953
8954                                 dreg = alloc_freg (cfg);
8955                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
8956                                 ins->type = STACK_R8;
8957                         } else {
8958                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
8959                                 ins->type = STACK_R8;
8960                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8961                                 ins->inst_p0 = d;
8962                                 MONO_ADD_INS (cfg->cbb, ins);
8963                         }
8964                         ++ip;
8965                         readr8 (ip, d);
8966                         ip += 8;
8967                         *sp++ = ins;
8968                         break;
8969                 }
8970                 case CEE_DUP: {
8971                         MonoInst *temp, *store;
8972                         CHECK_STACK (1);
8973                         CHECK_STACK_OVF (1);
8974                         sp--;
8975                         ins = *sp;
8976
8977                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
8978                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
8979
8980                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8981                         *sp++ = ins;
8982
8983                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8984                         *sp++ = ins;
8985
8986                         ++ip;
8987                         inline_costs += 2;
8988                         break;
8989                 }
8990                 case CEE_POP:
8991                         CHECK_STACK (1);
8992                         ip++;
8993                         --sp;
8994
8995 #ifdef TARGET_X86
8996                         if (sp [0]->type == STACK_R8)
8997                                 /* we need to pop the value from the x86 FP stack */
8998                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
8999 #endif
9000                         break;
9001                 case CEE_JMP: {
9002                         MonoCallInst *call;
9003                         MonoMethodSignature *fsig;
9004                         int i, n;
9005
9006                         INLINE_FAILURE ("jmp");
9007                         GSHAREDVT_FAILURE (*ip);
9008
9009                         CHECK_OPSIZE (5);
9010                         if (stack_start != sp)
9011                                 UNVERIFIED;
9012                         token = read32 (ip + 1);
9013                         /* FIXME: check the signature matches */
9014                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
9015                         CHECK_CFG_ERROR;
9016  
9017                         if (cfg->gshared && mono_method_check_context_used (cmethod))
9018                                 GENERIC_SHARING_FAILURE (CEE_JMP);
9019
9020                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
9021
9022                         fsig = mono_method_signature (cmethod);
9023                         n = fsig->param_count + fsig->hasthis;
9024                         if (cfg->llvm_only) {
9025                                 MonoInst **args;
9026
9027                                 args = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
9028                                 for (i = 0; i < n; ++i)
9029                                         EMIT_NEW_ARGLOAD (cfg, args [i], i);
9030                                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, TRUE, args, NULL, NULL, NULL);
9031                                 /*
9032                                  * The code in mono-basic-block.c treats the rest of the code as dead, but we
9033                                  * have to emit a normal return since llvm expects it.
9034                                  */
9035                                 if (cfg->ret)
9036                                         emit_setret (cfg, ins);
9037                                 MONO_INST_NEW (cfg, ins, OP_BR);
9038                                 ins->inst_target_bb = end_bblock;
9039                                 MONO_ADD_INS (cfg->cbb, ins);
9040                                 link_bblock (cfg, cfg->cbb, end_bblock);
9041                                 ip += 5;
9042                                 break;
9043                         } else if (cfg->backend->have_op_tail_call) {
9044                                 /* Handle tail calls similarly to calls */
9045                                 DISABLE_AOT (cfg);
9046
9047                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
9048                                 call->method = cmethod;
9049                                 call->tail_call = TRUE;
9050                                 call->signature = mono_method_signature (cmethod);
9051                                 call->args = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
9052                                 call->inst.inst_p0 = cmethod;
9053                                 for (i = 0; i < n; ++i)
9054                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
9055
9056                                 mono_arch_emit_call (cfg, call);
9057                                 cfg->param_area = MAX(cfg->param_area, call->stack_usage);
9058                                 MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
9059                         } else {
9060                                 for (i = 0; i < num_args; ++i)
9061                                         /* Prevent arguments from being optimized away */
9062                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
9063
9064                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9065                                 ins = (MonoInst*)call;
9066                                 ins->inst_p0 = cmethod;
9067                                 MONO_ADD_INS (cfg->cbb, ins);
9068                         }
9069
9070                         ip += 5;
9071                         start_new_bblock = 1;
9072                         break;
9073                 }
9074                 case CEE_CALLI: {
9075                         MonoInst *addr;
9076                         MonoMethodSignature *fsig;
9077
9078                         CHECK_OPSIZE (5);
9079                         token = read32 (ip + 1);
9080
9081                         ins = NULL;
9082
9083                         //GSHAREDVT_FAILURE (*ip);
9084                         cmethod = NULL;
9085                         CHECK_STACK (1);
9086                         --sp;
9087                         addr = *sp;
9088                         fsig = mini_get_signature (method, token, generic_context);
9089
9090                         if (method->dynamic && fsig->pinvoke) {
9091                                 MonoInst *args [3];
9092
9093                                 /*
9094                                  * This is a call through a function pointer using a pinvoke
9095                                  * signature. Have to create a wrapper and call that instead.
9096                                  * FIXME: This is very slow, need to create a wrapper at JIT time
9097                                  * instead based on the signature.
9098                                  */
9099                                 EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
9100                                 EMIT_NEW_PCONST (cfg, args [1], fsig);
9101                                 args [2] = addr;
9102                                 addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
9103                         }
9104
9105                         n = fsig->param_count + fsig->hasthis;
9106
9107                         CHECK_STACK (n);
9108
9109                         //g_assert (!virtual_ || fsig->hasthis);
9110
9111                         sp -= n;
9112
9113                         inline_costs += 10 * num_calls++;
9114
9115                         /*
9116                          * Making generic calls out of gsharedvt methods.
9117                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9118                          * patching gshared method addresses into a gsharedvt method.
9119                          */
9120                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
9121                                 /*
9122                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
9123                                  */
9124                                 MonoInst *callee = addr;
9125
9126                                 if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
9127                                         /* Not tested */
9128                                         GSHAREDVT_FAILURE (*ip);
9129
9130                                 if (cfg->llvm_only)
9131                                         // FIXME:
9132                                         GSHAREDVT_FAILURE (*ip);
9133
9134                                 addr = emit_get_rgctx_sig (cfg, context_used,
9135                                                                                           fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
9136                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
9137                                 goto calli_end;
9138                         }
9139
9140                         /* Prevent inlining of methods with indirect calls */
9141                         INLINE_FAILURE ("indirect call");
9142
9143                         if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
9144                                 MonoJumpInfoType info_type;
9145                                 gpointer info_data;
9146
9147                                 /*
9148                                  * Instead of emitting an indirect call, emit a direct call
9149                                  * with the contents of the aotconst as the patch info.
9150                                  */
9151                                 if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
9152                                         info_type = (MonoJumpInfoType)addr->inst_c1;
9153                                         info_data = addr->inst_p0;
9154                                 } else {
9155                                         info_type = (MonoJumpInfoType)addr->inst_right->inst_c1;
9156                                         info_data = addr->inst_right->inst_left;
9157                                 }
9158
9159                                 if (info_type == MONO_PATCH_INFO_ICALL_ADDR) {
9160                                         ins = (MonoInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_ICALL_ADDR_CALL, info_data, fsig, sp);
9161                                         NULLIFY_INS (addr);
9162                                         goto calli_end;
9163                                 } else if (info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
9164                                         ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
9165                                         NULLIFY_INS (addr);
9166                                         goto calli_end;
9167                                 }
9168                         }
9169                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9170
9171                         calli_end:
9172
9173                         /* End of call, INS should contain the result of the call, if any */
9174
9175                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9176                                 g_assert (ins);
9177                                 *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
9178                         }
9179
9180                         CHECK_CFG_EXCEPTION;
9181
9182                         ip += 5;
9183                         ins_flag = 0;
9184                         constrained_class = NULL;
9185                         break;
9186                 }
9187                 case CEE_CALL:
9188                 case CEE_CALLVIRT: {
9189                         MonoInst *addr = NULL;
9190                         MonoMethodSignature *fsig = NULL;
9191                         int array_rank = 0;
9192                         int virtual_ = *ip == CEE_CALLVIRT;
9193                         gboolean pass_imt_from_rgctx = FALSE;
9194                         MonoInst *imt_arg = NULL;
9195                         MonoInst *keep_this_alive = NULL;
9196                         gboolean pass_vtable = FALSE;
9197                         gboolean pass_mrgctx = FALSE;
9198                         MonoInst *vtable_arg = NULL;
9199                         gboolean check_this = FALSE;
9200                         gboolean supported_tail_call = FALSE;
9201                         gboolean tail_call = FALSE;
9202                         gboolean need_seq_point = FALSE;
9203                         guint32 call_opcode = *ip;
9204                         gboolean emit_widen = TRUE;
9205                         gboolean push_res = TRUE;
9206                         gboolean skip_ret = FALSE;
9207                         gboolean delegate_invoke = FALSE;
9208                         gboolean direct_icall = FALSE;
9209                         gboolean constrained_partial_call = FALSE;
9210                         MonoMethod *cil_method;
9211
9212                         CHECK_OPSIZE (5);
9213                         token = read32 (ip + 1);
9214
9215                         ins = NULL;
9216
9217                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
9218                         CHECK_CFG_ERROR;
9219
9220                         cil_method = cmethod;
9221                                 
9222                         if (constrained_class) {
9223                                 if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
9224                                         if (!mini_is_gsharedvt_klass (constrained_class)) {
9225                                                 g_assert (!cmethod->klass->valuetype);
9226                                                 if (!mini_type_is_reference (&constrained_class->byval_arg))
9227                                                         constrained_partial_call = TRUE;
9228                                         }
9229                                 }
9230
9231                                 if (method->wrapper_type != MONO_WRAPPER_NONE) {
9232                                         if (cfg->verbose_level > 2)
9233                                                 printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_class));
9234                                         if (!((constrained_class->byval_arg.type == MONO_TYPE_VAR ||
9235                                                    constrained_class->byval_arg.type == MONO_TYPE_MVAR) &&
9236                                                   cfg->gshared)) {
9237                                                 cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_class, generic_context, &cfg->error);
9238                                                 CHECK_CFG_ERROR;
9239                                         }
9240                                 } else {
9241                                         if (cfg->verbose_level > 2)
9242                                                 printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_class));
9243
9244                                         if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
9245                                                 /* 
9246                                                  * This is needed since get_method_constrained can't find 
9247                                                  * the method in klass representing a type var.
9248                                                  * The type var is guaranteed to be a reference type in this
9249                                                  * case.
9250                                                  */
9251                                                 if (!mini_is_gsharedvt_klass (constrained_class))
9252                                                         g_assert (!cmethod->klass->valuetype);
9253                                         } else {
9254                                                 cmethod = mono_get_method_constrained_checked (image, token, constrained_class, generic_context, &cil_method, &cfg->error);
9255                                                 CHECK_CFG_ERROR;
9256                                         }
9257                                 }
9258                         }
9259                                         
9260                         if (!dont_verify && !cfg->skip_visibility) {
9261                                 MonoMethod *target_method = cil_method;
9262                                 if (method->is_inflated) {
9263                                         target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context), &cfg->error);
9264                                         CHECK_CFG_ERROR;
9265                                 }
9266                                 if (!mono_method_can_access_method (method_definition, target_method) &&
9267                                         !mono_method_can_access_method (method, cil_method))
9268                                         METHOD_ACCESS_FAILURE (method, cil_method);
9269                         }
9270
9271                         if (mono_security_core_clr_enabled ())
9272                                 ensure_method_is_allowed_to_call_method (cfg, method, cil_method);
9273
9274                         if (!virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
9275                                 /* MS.NET seems to silently convert this to a callvirt */
9276                                 virtual_ = 1;
9277
9278                         {
9279                                 /*
9280                                  * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
9281                                  * converts to a callvirt.
9282                                  *
9283                                  * tests/bug-515884.il is an example of this behavior
9284                                  */
9285                                 const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
9286                                 const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
9287                                 if (!virtual_ && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
9288                                         virtual_ = 1;
9289                         }
9290
9291                         if (!cmethod->klass->inited)
9292                                 if (!mono_class_init (cmethod->klass))
9293                                         TYPE_LOAD_ERROR (cmethod->klass);
9294
9295                         fsig = mono_method_signature (cmethod);
9296                         if (!fsig)
9297                                 LOAD_ERROR;
9298                         if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
9299                                 mini_class_is_system_array (cmethod->klass)) {
9300                                 array_rank = cmethod->klass->rank;
9301                         } else if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && icall_is_direct_callable (cfg, cmethod)) {
9302                                 direct_icall = TRUE;
9303                         } else if (fsig->pinvoke) {
9304                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
9305                                 fsig = mono_method_signature (wrapper);
9306                         } else if (constrained_class) {
9307                         } else {
9308                                 fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
9309                                 CHECK_CFG_ERROR;
9310                         }
9311
9312                         if (cfg->llvm_only && !cfg->method->wrapper_type)
9313                                 cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, fsig);
9314
9315                         /* See code below */
9316                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
9317                                 MonoBasicBlock *tbb;
9318
9319                                 GET_BBLOCK (cfg, tbb, ip + 5);
9320                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
9321                                         /*
9322                                          * We want to extend the try block to cover the call, but we can't do it if the
9323                                          * call is made directly since its followed by an exception check.
9324                                          */
9325                                         direct_icall = FALSE;
9326                                 }
9327                         }
9328
9329                         mono_save_token_info (cfg, image, token, cil_method);
9330
9331                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip + 5 - header->code)))
9332                                 need_seq_point = TRUE;
9333
9334                         /* Don't support calls made using type arguments for now */
9335                         /*
9336                           if (cfg->gsharedvt) {
9337                           if (mini_is_gsharedvt_signature (fsig))
9338                           GSHAREDVT_FAILURE (*ip);
9339                           }
9340                         */
9341
9342                         if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
9343                                 g_assert_not_reached ();
9344
9345                         n = fsig->param_count + fsig->hasthis;
9346
9347                         if (!cfg->gshared && cmethod->klass->generic_container)
9348                                 UNVERIFIED;
9349
9350                         if (!cfg->gshared)
9351                                 g_assert (!mono_method_check_context_used (cmethod));
9352
9353                         CHECK_STACK (n);
9354
9355                         //g_assert (!virtual_ || fsig->hasthis);
9356
9357                         sp -= n;
9358
9359                         /*
9360                          * We have the `constrained.' prefix opcode.
9361                          */
9362                         if (constrained_class) {
9363                                 if (mini_is_gsharedvt_klass (constrained_class)) {
9364                                         if ((cmethod->klass != mono_defaults.object_class) && constrained_class->valuetype && cmethod->klass->valuetype) {
9365                                                 /* The 'Own method' case below */
9366                                         } else if (cmethod->klass->image != mono_defaults.corlib && !(cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !cmethod->klass->valuetype) {
9367                                                 /* 'The type parameter is instantiated as a reference type' case below. */
9368                                         } else {
9369                                                 ins = handle_constrained_gsharedvt_call (cfg, cmethod, fsig, sp, constrained_class, &emit_widen);
9370                                                 CHECK_CFG_EXCEPTION;
9371                                                 g_assert (ins);
9372                                                 goto call_end;
9373                                         }
9374                                 }
9375
9376                                 if (constrained_partial_call) {
9377                                         gboolean need_box = TRUE;
9378
9379                                         /*
9380                                          * The receiver is a valuetype, but the exact type is not known at compile time. This means the
9381                                          * called method is not known at compile time either. The called method could end up being
9382                                          * one of the methods on the parent classes (object/valuetype/enum), in which case we need
9383                                          * to box the receiver.
9384                                          * A simple solution would be to box always and make a normal virtual call, but that would
9385                                          * be bad performance wise.
9386                                          */
9387                                         if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE && cmethod->klass->generic_class) {
9388                                                 /*
9389                                                  * The parent classes implement no generic interfaces, so the called method will be a vtype method, so no boxing neccessary.
9390                                                  */
9391                                                 need_box = FALSE;
9392                                         }
9393
9394                                         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)) {
9395                                                 /* The called method is not virtual, i.e. Object:GetType (), the receiver is a vtype, has to box */
9396                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9397                                                 ins->klass = constrained_class;
9398                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9399                                                 CHECK_CFG_EXCEPTION;
9400                                         } else if (need_box) {
9401                                                 MonoInst *box_type;
9402                                                 MonoBasicBlock *is_ref_bb, *end_bb;
9403                                                 MonoInst *nonbox_call;
9404
9405                                                 /*
9406                                                  * Determine at runtime whenever the called method is defined on object/valuetype/enum, and emit a boxing call
9407                                                  * if needed.
9408                                                  * FIXME: It is possible to inline the called method in a lot of cases, i.e. for T_INT,
9409                                                  * the no-box case goes to a method in Int32, while the box case goes to a method in Enum.
9410                                                  */
9411                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
9412
9413                                                 NEW_BBLOCK (cfg, is_ref_bb);
9414                                                 NEW_BBLOCK (cfg, end_bb);
9415
9416                                                 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);
9417                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, box_type->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
9418                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
9419
9420                                                 /* Non-ref case */
9421                                                 nonbox_call = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9422
9423                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9424
9425                                                 /* Ref case */
9426                                                 MONO_START_BB (cfg, is_ref_bb);
9427                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9428                                                 ins->klass = constrained_class;
9429                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9430                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9431
9432                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9433
9434                                                 MONO_START_BB (cfg, end_bb);
9435                                                 cfg->cbb = end_bb;
9436
9437                                                 nonbox_call->dreg = ins->dreg;
9438                                                 goto call_end;
9439                                         } else {
9440                                                 g_assert (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
9441                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
9442                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9443                                                 goto call_end;
9444                                         }
9445                                 } else if (constrained_class->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
9446                                         /*
9447                                          * The type parameter is instantiated as a valuetype,
9448                                          * but that type doesn't override the method we're
9449                                          * calling, so we need to box `this'.
9450                                          */
9451                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9452                                         ins->klass = constrained_class;
9453                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9454                                         CHECK_CFG_EXCEPTION;
9455                                 } else if (!constrained_class->valuetype) {
9456                                         int dreg = alloc_ireg_ref (cfg);
9457
9458                                         /*
9459                                          * The type parameter is instantiated as a reference
9460                                          * type.  We have a managed pointer on the stack, so
9461                                          * we need to dereference it here.
9462                                          */
9463                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
9464                                         ins->type = STACK_OBJ;
9465                                         sp [0] = ins;
9466                                 } else {
9467                                         if (cmethod->klass->valuetype) {
9468                                                 /* Own method */
9469                                         } else {
9470                                                 /* Interface method */
9471                                                 int ioffset, slot;
9472
9473                                                 mono_class_setup_vtable (constrained_class);
9474                                                 CHECK_TYPELOAD (constrained_class);
9475                                                 ioffset = mono_class_interface_offset (constrained_class, cmethod->klass);
9476                                                 if (ioffset == -1)
9477                                                         TYPE_LOAD_ERROR (constrained_class);
9478                                                 slot = mono_method_get_vtable_slot (cmethod);
9479                                                 if (slot == -1)
9480                                                         TYPE_LOAD_ERROR (cmethod->klass);
9481                                                 cmethod = constrained_class->vtable [ioffset + slot];
9482
9483                                                 if (cmethod->klass == mono_defaults.enum_class) {
9484                                                         /* Enum implements some interfaces, so treat this as the first case */
9485                                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9486                                                         ins->klass = constrained_class;
9487                                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9488                                                         CHECK_CFG_EXCEPTION;
9489                                                 }
9490                                         }
9491                                         virtual_ = 0;
9492                                 }
9493                                 constrained_class = NULL;
9494                         }
9495
9496                         if (check_call_signature (cfg, fsig, sp))
9497                                 UNVERIFIED;
9498
9499                         if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
9500                                 delegate_invoke = TRUE;
9501
9502                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
9503                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9504                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9505                                         emit_widen = FALSE;
9506                                 }
9507
9508                                 goto call_end;
9509                         }
9510
9511                         /* 
9512                          * If the callee is a shared method, then its static cctor
9513                          * might not get called after the call was patched.
9514                          */
9515                         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)) {
9516                                 emit_class_init (cfg, cmethod->klass);
9517                                 CHECK_TYPELOAD (cmethod->klass);
9518                         }
9519
9520                         check_method_sharing (cfg, cmethod, &pass_vtable, &pass_mrgctx);
9521
9522                         if (cfg->gshared) {
9523                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
9524
9525                                 context_used = mini_method_check_context_used (cfg, cmethod);
9526
9527                                 if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9528                                         /* Generic method interface
9529                                            calls are resolved via a
9530                                            helper function and don't
9531                                            need an imt. */
9532                                         if (!cmethod_context || !cmethod_context->method_inst)
9533                                                 pass_imt_from_rgctx = TRUE;
9534                                 }
9535
9536                                 /*
9537                                  * If a shared method calls another
9538                                  * shared method then the caller must
9539                                  * have a generic sharing context
9540                                  * because the magic trampoline
9541                                  * requires it.  FIXME: We shouldn't
9542                                  * have to force the vtable/mrgctx
9543                                  * variable here.  Instead there
9544                                  * should be a flag in the cfg to
9545                                  * request a generic sharing context.
9546                                  */
9547                                 if (context_used &&
9548                                                 ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
9549                                         mono_get_vtable_var (cfg);
9550                         }
9551
9552                         if (pass_vtable) {
9553                                 if (context_used) {
9554                                         vtable_arg = emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
9555                                 } else {
9556                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
9557
9558                                         CHECK_TYPELOAD (cmethod->klass);
9559                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
9560                                 }
9561                         }
9562
9563                         if (pass_mrgctx) {
9564                                 g_assert (!vtable_arg);
9565
9566                                 if (!cfg->compile_aot) {
9567                                         /* 
9568                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
9569                                          * for type load errors before.
9570                                          */
9571                                         mono_class_setup_vtable (cmethod->klass);
9572                                         CHECK_TYPELOAD (cmethod->klass);
9573                                 }
9574
9575                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
9576
9577                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
9578                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
9579                                          MONO_METHOD_IS_FINAL (cmethod)) &&
9580                                         !mono_class_is_marshalbyref (cmethod->klass)) {
9581                                         if (virtual_)
9582                                                 check_this = TRUE;
9583                                         virtual_ = 0;
9584                                 }
9585                         }
9586
9587                         if (pass_imt_from_rgctx) {
9588                                 g_assert (!pass_vtable);
9589
9590                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9591                                         cmethod, MONO_RGCTX_INFO_METHOD);
9592                         }
9593
9594                         if (check_this)
9595                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9596
9597                         /* Calling virtual generic methods */
9598                         if (virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) &&
9599                             !(MONO_METHOD_IS_FINAL (cmethod) && 
9600                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
9601                             fsig->generic_param_count && 
9602                                 !(cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) &&
9603                                 !cfg->llvm_only) {
9604                                 MonoInst *this_temp, *this_arg_temp, *store;
9605                                 MonoInst *iargs [4];
9606
9607                                 g_assert (fsig->is_inflated);
9608
9609                                 /* Prevent inlining of methods that contain indirect calls */
9610                                 INLINE_FAILURE ("virtual generic call");
9611
9612                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
9613                                         GSHAREDVT_FAILURE (*ip);
9614
9615                                 if (cfg->backend->have_generalized_imt_thunk && cfg->backend->gshared_supported && cmethod->wrapper_type == MONO_WRAPPER_NONE) {
9616                                         g_assert (!imt_arg);
9617                                         if (!context_used)
9618                                                 g_assert (cmethod->is_inflated);
9619                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
9620                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
9621                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, sp [0], imt_arg, NULL);
9622                                 } else {
9623                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
9624                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
9625                                         MONO_ADD_INS (cfg->cbb, store);
9626
9627                                         /* FIXME: This should be a managed pointer */
9628                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
9629
9630                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
9631                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
9632                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
9633                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
9634                                         addr = mono_emit_jit_icall (cfg,
9635                                                                                                 mono_helper_compile_generic_method, iargs);
9636
9637                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
9638
9639                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9640                                 }
9641
9642                                 goto call_end;
9643                         }
9644
9645                         /*
9646                          * Implement a workaround for the inherent races involved in locking:
9647                          * Monitor.Enter ()
9648                          * try {
9649                          * } finally {
9650                          *    Monitor.Exit ()
9651                          * }
9652                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
9653                          * try block, the Exit () won't be executed, see:
9654                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
9655                          * To work around this, we extend such try blocks to include the last x bytes
9656                          * of the Monitor.Enter () call.
9657                          */
9658                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
9659                                 MonoBasicBlock *tbb;
9660
9661                                 GET_BBLOCK (cfg, tbb, ip + 5);
9662                                 /* 
9663                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
9664                                  * from Monitor.Enter like ArgumentNullException.
9665                                  */
9666                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
9667                                         /* Mark this bblock as needing to be extended */
9668                                         tbb->extend_try_block = TRUE;
9669                                 }
9670                         }
9671
9672                         /* Conversion to a JIT intrinsic */
9673                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
9674                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9675                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9676                                         emit_widen = FALSE;
9677                                 }
9678                                 goto call_end;
9679                         }
9680
9681                         /* Inlining */
9682                         if ((cfg->opt & MONO_OPT_INLINE) &&
9683                                 (!virtual_ || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
9684                             mono_method_check_inlining (cfg, cmethod)) {
9685                                 int costs;
9686                                 gboolean always = FALSE;
9687
9688                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
9689                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
9690                                         /* Prevent inlining of methods that call wrappers */
9691                                         INLINE_FAILURE ("wrapper call");
9692                                         cmethod = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
9693                                         always = TRUE;
9694                                 }
9695
9696                                 costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, always);
9697                                 if (costs) {
9698                                         cfg->real_offset += 5;
9699
9700                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9701                                                 /* *sp is already set by inline_method */
9702                                                 sp++;
9703                                                 push_res = FALSE;
9704                                         }
9705
9706                                         inline_costs += costs;
9707
9708                                         goto call_end;
9709                                 }
9710                         }
9711
9712                         /* Tail recursion elimination */
9713                         if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
9714                                 gboolean has_vtargs = FALSE;
9715                                 int i;
9716
9717                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9718                                 INLINE_FAILURE ("tail call");
9719
9720                                 /* keep it simple */
9721                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
9722                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
9723                                                 has_vtargs = TRUE;
9724                                 }
9725
9726                                 if (!has_vtargs) {
9727                                         for (i = 0; i < n; ++i)
9728                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9729                                         MONO_INST_NEW (cfg, ins, OP_BR);
9730                                         MONO_ADD_INS (cfg->cbb, ins);
9731                                         tblock = start_bblock->out_bb [0];
9732                                         link_bblock (cfg, cfg->cbb, tblock);
9733                                         ins->inst_target_bb = tblock;
9734                                         start_new_bblock = 1;
9735
9736                                         /* skip the CEE_RET, too */
9737                                         if (ip_in_bb (cfg, cfg->cbb, ip + 5))
9738                                                 skip_ret = TRUE;
9739                                         push_res = FALSE;
9740                                         goto call_end;
9741                                 }
9742                         }
9743
9744                         inline_costs += 10 * num_calls++;
9745
9746                         /*
9747                          * Making generic calls out of gsharedvt methods.
9748                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9749                          * patching gshared method addresses into a gsharedvt method.
9750                          */
9751                         if (cfg->gsharedvt && (mini_is_gsharedvt_signature (fsig) || cmethod->is_inflated || cmethod->klass->generic_class) &&
9752                                 !(cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY) &&
9753                                 (!(cfg->llvm_only && virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)))) {
9754                                 MonoRgctxInfoType info_type;
9755
9756                                 if (virtual_) {
9757                                         //if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
9758                                                 //GSHAREDVT_FAILURE (*ip);
9759                                         // disable for possible remoting calls
9760                                         if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
9761                                                 GSHAREDVT_FAILURE (*ip);
9762                                         if (fsig->generic_param_count) {
9763                                                 /* virtual generic call */
9764                                                 g_assert (!imt_arg);
9765                                                 /* Same as the virtual generic case above */
9766                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9767                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9768                                                 /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
9769                                                 vtable_arg = NULL;
9770                                         } else if ((cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !imt_arg) {
9771                                                 /* This can happen when we call a fully instantiated iface method */
9772                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9773                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9774                                                 vtable_arg = NULL;
9775                                         }
9776                                 }
9777
9778                                 if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
9779                                         keep_this_alive = sp [0];
9780
9781                                 if (virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
9782                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
9783                                 else
9784                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
9785                                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
9786
9787                                 if (cfg->llvm_only) {
9788                                         // FIXME: Avoid initializing vtable_arg
9789                                         ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
9790                                 } else {
9791                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9792                                 }
9793                                 goto call_end;
9794                         }
9795
9796                         /* Generic sharing */
9797
9798                         /*
9799                          * Use this if the callee is gsharedvt sharable too, since
9800                          * at runtime we might find an instantiation so the call cannot
9801                          * be patched (the 'no_patch' code path in mini-trampolines.c).
9802                          */
9803                         if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
9804                                 (!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
9805                                  !mono_class_generic_sharing_enabled (cmethod->klass)) &&
9806                                 (!virtual_ || MONO_METHOD_IS_FINAL (cmethod) ||
9807                                  !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
9808                                 INLINE_FAILURE ("gshared");
9809
9810                                 g_assert (cfg->gshared && cmethod);
9811                                 g_assert (!addr);
9812
9813                                 /*
9814                                  * We are compiling a call to a
9815                                  * generic method from shared code,
9816                                  * which means that we have to look up
9817                                  * the method in the rgctx and do an
9818                                  * indirect call.
9819                                  */
9820                                 if (fsig->hasthis)
9821                                         MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9822
9823                                 if (cfg->llvm_only) {
9824                                         if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig))
9825                                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER);
9826                                         else
9827                                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9828                                         // FIXME: Avoid initializing imt_arg/vtable_arg
9829                                         ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
9830                                 } else {
9831                                         addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9832                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9833                                 }
9834                                 goto call_end;
9835                         }
9836
9837                         /* Direct calls to icalls */
9838                         if (direct_icall) {
9839                                 MonoMethod *wrapper;
9840                                 int costs;
9841
9842                                 /* Inline the wrapper */
9843                                 wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
9844
9845                                 costs = inline_method (cfg, wrapper, fsig, sp, ip, cfg->real_offset, TRUE);
9846                                 g_assert (costs > 0);
9847                                 cfg->real_offset += 5;
9848
9849                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9850                                         /* *sp is already set by inline_method */
9851                                         sp++;
9852                                         push_res = FALSE;
9853                                 }
9854
9855                                 inline_costs += costs;
9856
9857                                 goto call_end;
9858                         }
9859                                         
9860                         /* Array methods */
9861                         if (array_rank) {
9862                                 MonoInst *addr;
9863
9864                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
9865                                         MonoInst *val = sp [fsig->param_count];
9866
9867                                         if (val->type == STACK_OBJ) {
9868                                                 MonoInst *iargs [2];
9869
9870                                                 iargs [0] = sp [0];
9871                                                 iargs [1] = val;
9872                                                 
9873                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
9874                                         }
9875                                         
9876                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
9877                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
9878                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !(val->opcode == OP_PCONST && val->inst_c0 == 0))
9879                                                 emit_write_barrier (cfg, addr, val);
9880                                         if (cfg->gen_write_barriers && mini_is_gsharedvt_klass (cmethod->klass))
9881                                                 GSHAREDVT_FAILURE (*ip);
9882                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
9883                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9884
9885                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
9886                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
9887                                         if (!cmethod->klass->element_class->valuetype && !readonly)
9888                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
9889                                         CHECK_TYPELOAD (cmethod->klass);
9890                                         
9891                                         readonly = FALSE;
9892                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9893                                         ins = addr;
9894                                 } else {
9895                                         g_assert_not_reached ();
9896                                 }
9897
9898                                 emit_widen = FALSE;
9899                                 goto call_end;
9900                         }
9901
9902                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual_ ? sp [0] : NULL);
9903                         if (ins)
9904                                 goto call_end;
9905
9906                         /* Tail prefix / tail call optimization */
9907
9908                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
9909                         /* FIXME: runtime generic context pointer for jumps? */
9910                         /* FIXME: handle this for generic sharing eventually */
9911                         if ((ins_flag & MONO_INST_TAILCALL) &&
9912                                 !vtable_arg && !cfg->gshared && is_supported_tail_call (cfg, method, cmethod, fsig, call_opcode))
9913                                 supported_tail_call = TRUE;
9914
9915                         if (supported_tail_call) {
9916                                 MonoCallInst *call;
9917
9918                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9919                                 INLINE_FAILURE ("tail call");
9920
9921                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
9922
9923                                 if (cfg->backend->have_op_tail_call) {
9924                                         /* Handle tail calls similarly to normal calls */
9925                                         tail_call = TRUE;
9926                                 } else {
9927                                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
9928
9929                                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9930                                         call->tail_call = TRUE;
9931                                         call->method = cmethod;
9932                                         call->signature = mono_method_signature (cmethod);
9933
9934                                         /*
9935                                          * We implement tail calls by storing the actual arguments into the 
9936                                          * argument variables, then emitting a CEE_JMP.
9937                                          */
9938                                         for (i = 0; i < n; ++i) {
9939                                                 /* Prevent argument from being register allocated */
9940                                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
9941                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9942                                         }
9943                                         ins = (MonoInst*)call;
9944                                         ins->inst_p0 = cmethod;
9945                                         ins->inst_p1 = arg_array [0];
9946                                         MONO_ADD_INS (cfg->cbb, ins);
9947                                         link_bblock (cfg, cfg->cbb, end_bblock);
9948                                         start_new_bblock = 1;
9949
9950                                         // FIXME: Eliminate unreachable epilogs
9951
9952                                         /*
9953                                          * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9954                                          * only reachable from this call.
9955                                          */
9956                                         GET_BBLOCK (cfg, tblock, ip + 5);
9957                                         if (tblock == cfg->cbb || tblock->in_count == 0)
9958                                                 skip_ret = TRUE;
9959                                         push_res = FALSE;
9960
9961                                         goto call_end;
9962                                 }
9963                         }
9964
9965                         /* 
9966                          * Synchronized wrappers.
9967                          * Its hard to determine where to replace a method with its synchronized
9968                          * wrapper without causing an infinite recursion. The current solution is
9969                          * to add the synchronized wrapper in the trampolines, and to
9970                          * change the called method to a dummy wrapper, and resolve that wrapper
9971                          * to the real method in mono_jit_compile_method ().
9972                          */
9973                         if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
9974                                 MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
9975                                 if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
9976                                         cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
9977                         }
9978
9979                         /*
9980                          * Virtual calls in llvm-only mode.
9981                          */
9982                         if (cfg->llvm_only && virtual_ && cmethod && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
9983                                 ins = emit_llvmonly_virtual_call (cfg, cmethod, fsig, context_used, sp);
9984                                 goto call_end;
9985                         }
9986
9987                         /* Common call */
9988                         INLINE_FAILURE ("call");
9989                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual_ ? sp [0] : NULL,
9990                                                                                           imt_arg, vtable_arg);
9991
9992                         if (tail_call && !cfg->llvm_only) {
9993                                 link_bblock (cfg, cfg->cbb, end_bblock);
9994                                 start_new_bblock = 1;
9995
9996                                 // FIXME: Eliminate unreachable epilogs
9997
9998                                 /*
9999                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
10000                                  * only reachable from this call.
10001                                  */
10002                                 GET_BBLOCK (cfg, tblock, ip + 5);
10003                                 if (tblock == cfg->cbb || tblock->in_count == 0)
10004                                         skip_ret = TRUE;
10005                                 push_res = FALSE;
10006                         }
10007
10008                         call_end:
10009
10010                         /* End of call, INS should contain the result of the call, if any */
10011
10012                         if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
10013                                 g_assert (ins);
10014                                 if (emit_widen)
10015                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
10016                                 else
10017                                         *sp++ = ins;
10018                         }
10019
10020                         if (keep_this_alive) {
10021                                 MonoInst *dummy_use;
10022
10023                                 /* See mono_emit_method_call_full () */
10024                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
10025                         }
10026
10027                         CHECK_CFG_EXCEPTION;
10028
10029                         ip += 5;
10030                         if (skip_ret) {
10031                                 g_assert (*ip == CEE_RET);
10032                                 ip += 1;
10033                         }
10034                         ins_flag = 0;
10035                         constrained_class = NULL;
10036                         if (need_seq_point)
10037                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10038                         break;
10039                 }
10040                 case CEE_RET:
10041                         if (cfg->method != method) {
10042                                 /* return from inlined method */
10043                                 /* 
10044                                  * If in_count == 0, that means the ret is unreachable due to
10045                                  * being preceeded by a throw. In that case, inline_method () will
10046                                  * handle setting the return value 
10047                                  * (test case: test_0_inline_throw ()).
10048                                  */
10049                                 if (return_var && cfg->cbb->in_count) {
10050                                         MonoType *ret_type = mono_method_signature (method)->ret;
10051
10052                                         MonoInst *store;
10053                                         CHECK_STACK (1);
10054                                         --sp;
10055
10056                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
10057                                                 UNVERIFIED;
10058
10059                                         //g_assert (returnvar != -1);
10060                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
10061                                         cfg->ret_var_set = TRUE;
10062                                 } 
10063                         } else {
10064                                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
10065
10066                                 if (cfg->lmf_var && cfg->cbb->in_count && !cfg->llvm_only)
10067                                         emit_pop_lmf (cfg);
10068
10069                                 if (cfg->ret) {
10070                                         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (method)->ret);
10071
10072                                         if (seq_points && !sym_seq_points) {
10073                                                 /* 
10074                                                  * Place a seq point here too even through the IL stack is not
10075                                                  * empty, so a step over on
10076                                                  * call <FOO>
10077                                                  * ret
10078                                                  * will work correctly.
10079                                                  */
10080                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
10081                                                 MONO_ADD_INS (cfg->cbb, ins);
10082                                         }
10083
10084                                         g_assert (!return_var);
10085                                         CHECK_STACK (1);
10086                                         --sp;
10087
10088                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
10089                                                 UNVERIFIED;
10090
10091                                         emit_setret (cfg, *sp);
10092                                 }
10093                         }
10094                         if (sp != stack_start)
10095                                 UNVERIFIED;
10096                         MONO_INST_NEW (cfg, ins, OP_BR);
10097                         ip++;
10098                         ins->inst_target_bb = end_bblock;
10099                         MONO_ADD_INS (cfg->cbb, ins);
10100                         link_bblock (cfg, cfg->cbb, end_bblock);
10101                         start_new_bblock = 1;
10102                         break;
10103                 case CEE_BR_S:
10104                         CHECK_OPSIZE (2);
10105                         MONO_INST_NEW (cfg, ins, OP_BR);
10106                         ip++;
10107                         target = ip + 1 + (signed char)(*ip);
10108                         ++ip;
10109                         GET_BBLOCK (cfg, tblock, target);
10110                         link_bblock (cfg, cfg->cbb, tblock);
10111                         ins->inst_target_bb = tblock;
10112                         if (sp != stack_start) {
10113                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10114                                 sp = stack_start;
10115                                 CHECK_UNVERIFIABLE (cfg);
10116                         }
10117                         MONO_ADD_INS (cfg->cbb, ins);
10118                         start_new_bblock = 1;
10119                         inline_costs += BRANCH_COST;
10120                         break;
10121                 case CEE_BEQ_S:
10122                 case CEE_BGE_S:
10123                 case CEE_BGT_S:
10124                 case CEE_BLE_S:
10125                 case CEE_BLT_S:
10126                 case CEE_BNE_UN_S:
10127                 case CEE_BGE_UN_S:
10128                 case CEE_BGT_UN_S:
10129                 case CEE_BLE_UN_S:
10130                 case CEE_BLT_UN_S:
10131                         CHECK_OPSIZE (2);
10132                         CHECK_STACK (2);
10133                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
10134                         ip++;
10135                         target = ip + 1 + *(signed char*)ip;
10136                         ip++;
10137
10138                         ADD_BINCOND (NULL);
10139
10140                         sp = stack_start;
10141                         inline_costs += BRANCH_COST;
10142                         break;
10143                 case CEE_BR:
10144                         CHECK_OPSIZE (5);
10145                         MONO_INST_NEW (cfg, ins, OP_BR);
10146                         ip++;
10147
10148                         target = ip + 4 + (gint32)read32(ip);
10149                         ip += 4;
10150                         GET_BBLOCK (cfg, tblock, target);
10151                         link_bblock (cfg, cfg->cbb, tblock);
10152                         ins->inst_target_bb = tblock;
10153                         if (sp != stack_start) {
10154                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10155                                 sp = stack_start;
10156                                 CHECK_UNVERIFIABLE (cfg);
10157                         }
10158
10159                         MONO_ADD_INS (cfg->cbb, ins);
10160
10161                         start_new_bblock = 1;
10162                         inline_costs += BRANCH_COST;
10163                         break;
10164                 case CEE_BRFALSE_S:
10165                 case CEE_BRTRUE_S:
10166                 case CEE_BRFALSE:
10167                 case CEE_BRTRUE: {
10168                         MonoInst *cmp;
10169                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
10170                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
10171                         guint32 opsize = is_short ? 1 : 4;
10172
10173                         CHECK_OPSIZE (opsize);
10174                         CHECK_STACK (1);
10175                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
10176                                 UNVERIFIED;
10177                         ip ++;
10178                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
10179                         ip += opsize;
10180
10181                         sp--;
10182
10183                         GET_BBLOCK (cfg, tblock, target);
10184                         link_bblock (cfg, cfg->cbb, tblock);
10185                         GET_BBLOCK (cfg, tblock, ip);
10186                         link_bblock (cfg, cfg->cbb, tblock);
10187
10188                         if (sp != stack_start) {
10189                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10190                                 CHECK_UNVERIFIABLE (cfg);
10191                         }
10192
10193                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
10194                         cmp->sreg1 = sp [0]->dreg;
10195                         type_from_op (cfg, cmp, sp [0], NULL);
10196                         CHECK_TYPE (cmp);
10197
10198 #if SIZEOF_REGISTER == 4
10199                         if (cmp->opcode == OP_LCOMPARE_IMM) {
10200                                 /* Convert it to OP_LCOMPARE */
10201                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
10202                                 ins->type = STACK_I8;
10203                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
10204                                 ins->inst_l = 0;
10205                                 MONO_ADD_INS (cfg->cbb, ins);
10206                                 cmp->opcode = OP_LCOMPARE;
10207                                 cmp->sreg2 = ins->dreg;
10208                         }
10209 #endif
10210                         MONO_ADD_INS (cfg->cbb, cmp);
10211
10212                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
10213                         type_from_op (cfg, ins, sp [0], NULL);
10214                         MONO_ADD_INS (cfg->cbb, ins);
10215                         ins->inst_many_bb = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
10216                         GET_BBLOCK (cfg, tblock, target);
10217                         ins->inst_true_bb = tblock;
10218                         GET_BBLOCK (cfg, tblock, ip);
10219                         ins->inst_false_bb = tblock;
10220                         start_new_bblock = 2;
10221
10222                         sp = stack_start;
10223                         inline_costs += BRANCH_COST;
10224                         break;
10225                 }
10226                 case CEE_BEQ:
10227                 case CEE_BGE:
10228                 case CEE_BGT:
10229                 case CEE_BLE:
10230                 case CEE_BLT:
10231                 case CEE_BNE_UN:
10232                 case CEE_BGE_UN:
10233                 case CEE_BGT_UN:
10234                 case CEE_BLE_UN:
10235                 case CEE_BLT_UN:
10236                         CHECK_OPSIZE (5);
10237                         CHECK_STACK (2);
10238                         MONO_INST_NEW (cfg, ins, *ip);
10239                         ip++;
10240                         target = ip + 4 + (gint32)read32(ip);
10241                         ip += 4;
10242
10243                         ADD_BINCOND (NULL);
10244
10245                         sp = stack_start;
10246                         inline_costs += BRANCH_COST;
10247                         break;
10248                 case CEE_SWITCH: {
10249                         MonoInst *src1;
10250                         MonoBasicBlock **targets;
10251                         MonoBasicBlock *default_bblock;
10252                         MonoJumpInfoBBTable *table;
10253                         int offset_reg = alloc_preg (cfg);
10254                         int target_reg = alloc_preg (cfg);
10255                         int table_reg = alloc_preg (cfg);
10256                         int sum_reg = alloc_preg (cfg);
10257                         gboolean use_op_switch;
10258
10259                         CHECK_OPSIZE (5);
10260                         CHECK_STACK (1);
10261                         n = read32 (ip + 1);
10262                         --sp;
10263                         src1 = sp [0];
10264                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
10265                                 UNVERIFIED;
10266
10267                         ip += 5;
10268                         CHECK_OPSIZE (n * sizeof (guint32));
10269                         target = ip + n * sizeof (guint32);
10270
10271                         GET_BBLOCK (cfg, default_bblock, target);
10272                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
10273
10274                         targets = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
10275                         for (i = 0; i < n; ++i) {
10276                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
10277                                 targets [i] = tblock;
10278                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
10279                                 ip += 4;
10280                         }
10281
10282                         if (sp != stack_start) {
10283                                 /* 
10284                                  * Link the current bb with the targets as well, so handle_stack_args
10285                                  * will set their in_stack correctly.
10286                                  */
10287                                 link_bblock (cfg, cfg->cbb, default_bblock);
10288                                 for (i = 0; i < n; ++i)
10289                                         link_bblock (cfg, cfg->cbb, targets [i]);
10290
10291                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10292                                 sp = stack_start;
10293                                 CHECK_UNVERIFIABLE (cfg);
10294
10295                                 /* Undo the links */
10296                                 mono_unlink_bblock (cfg, cfg->cbb, default_bblock);
10297                                 for (i = 0; i < n; ++i)
10298                                         mono_unlink_bblock (cfg, cfg->cbb, targets [i]);
10299                         }
10300
10301                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
10302                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
10303
10304                         for (i = 0; i < n; ++i)
10305                                 link_bblock (cfg, cfg->cbb, targets [i]);
10306
10307                         table = (MonoJumpInfoBBTable *)mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
10308                         table->table = targets;
10309                         table->table_size = n;
10310
10311                         use_op_switch = FALSE;
10312 #ifdef TARGET_ARM
10313                         /* ARM implements SWITCH statements differently */
10314                         /* FIXME: Make it use the generic implementation */
10315                         if (!cfg->compile_aot)
10316                                 use_op_switch = TRUE;
10317 #endif
10318
10319                         if (COMPILE_LLVM (cfg))
10320                                 use_op_switch = TRUE;
10321
10322                         cfg->cbb->has_jump_table = 1;
10323
10324                         if (use_op_switch) {
10325                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
10326                                 ins->sreg1 = src1->dreg;
10327                                 ins->inst_p0 = table;
10328                                 ins->inst_many_bb = targets;
10329                                 ins->klass = (MonoClass *)GUINT_TO_POINTER (n);
10330                                 MONO_ADD_INS (cfg->cbb, ins);
10331                         } else {
10332                                 if (sizeof (gpointer) == 8)
10333                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
10334                                 else
10335                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
10336
10337 #if SIZEOF_REGISTER == 8
10338                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
10339                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
10340 #endif
10341
10342                                 if (cfg->compile_aot) {
10343                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
10344                                 } else {
10345                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
10346                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
10347                                         ins->inst_p0 = table;
10348                                         ins->dreg = table_reg;
10349                                         MONO_ADD_INS (cfg->cbb, ins);
10350                                 }
10351
10352                                 /* FIXME: Use load_memindex */
10353                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
10354                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
10355                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
10356                         }
10357                         start_new_bblock = 1;
10358                         inline_costs += (BRANCH_COST * 2);
10359                         break;
10360                 }
10361                 case CEE_LDIND_I1:
10362                 case CEE_LDIND_U1:
10363                 case CEE_LDIND_I2:
10364                 case CEE_LDIND_U2:
10365                 case CEE_LDIND_I4:
10366                 case CEE_LDIND_U4:
10367                 case CEE_LDIND_I8:
10368                 case CEE_LDIND_I:
10369                 case CEE_LDIND_R4:
10370                 case CEE_LDIND_R8:
10371                 case CEE_LDIND_REF:
10372                         CHECK_STACK (1);
10373                         --sp;
10374
10375                         switch (*ip) {
10376                         case CEE_LDIND_R4:
10377                         case CEE_LDIND_R8:
10378                                 dreg = alloc_freg (cfg);
10379                                 break;
10380                         case CEE_LDIND_I8:
10381                                 dreg = alloc_lreg (cfg);
10382                                 break;
10383                         case CEE_LDIND_REF:
10384                                 dreg = alloc_ireg_ref (cfg);
10385                                 break;
10386                         default:
10387                                 dreg = alloc_preg (cfg);
10388                         }
10389
10390                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
10391                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
10392                         if (*ip == CEE_LDIND_R4)
10393                                 ins->type = cfg->r4_stack_type;
10394                         ins->flags |= ins_flag;
10395                         MONO_ADD_INS (cfg->cbb, ins);
10396                         *sp++ = ins;
10397                         if (ins_flag & MONO_INST_VOLATILE) {
10398                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10399                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10400                         }
10401                         ins_flag = 0;
10402                         ++ip;
10403                         break;
10404                 case CEE_STIND_REF:
10405                 case CEE_STIND_I1:
10406                 case CEE_STIND_I2:
10407                 case CEE_STIND_I4:
10408                 case CEE_STIND_I8:
10409                 case CEE_STIND_R4:
10410                 case CEE_STIND_R8:
10411                 case CEE_STIND_I:
10412                         CHECK_STACK (2);
10413                         sp -= 2;
10414
10415                         if (ins_flag & MONO_INST_VOLATILE) {
10416                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
10417                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
10418                         }
10419
10420                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
10421                         ins->flags |= ins_flag;
10422                         ins_flag = 0;
10423
10424                         MONO_ADD_INS (cfg->cbb, ins);
10425
10426                         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)))
10427                                 emit_write_barrier (cfg, sp [0], sp [1]);
10428
10429                         inline_costs += 1;
10430                         ++ip;
10431                         break;
10432
10433                 case CEE_MUL:
10434                         CHECK_STACK (2);
10435
10436                         MONO_INST_NEW (cfg, ins, (*ip));
10437                         sp -= 2;
10438                         ins->sreg1 = sp [0]->dreg;
10439                         ins->sreg2 = sp [1]->dreg;
10440                         type_from_op (cfg, ins, sp [0], sp [1]);
10441                         CHECK_TYPE (ins);
10442                         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type);
10443
10444                         /* Use the immediate opcodes if possible */
10445                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
10446                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
10447                                 if (imm_opcode != -1) {
10448                                         ins->opcode = imm_opcode;
10449                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
10450                                         ins->sreg2 = -1;
10451
10452                                         NULLIFY_INS (sp [1]);
10453                                 }
10454                         }
10455
10456                         MONO_ADD_INS ((cfg)->cbb, (ins));
10457
10458                         *sp++ = mono_decompose_opcode (cfg, ins);
10459                         ip++;
10460                         break;
10461                 case CEE_ADD:
10462                 case CEE_SUB:
10463                 case CEE_DIV:
10464                 case CEE_DIV_UN:
10465                 case CEE_REM:
10466                 case CEE_REM_UN:
10467                 case CEE_AND:
10468                 case CEE_OR:
10469                 case CEE_XOR:
10470                 case CEE_SHL:
10471                 case CEE_SHR:
10472                 case CEE_SHR_UN:
10473                         CHECK_STACK (2);
10474
10475                         MONO_INST_NEW (cfg, ins, (*ip));
10476                         sp -= 2;
10477                         ins->sreg1 = sp [0]->dreg;
10478                         ins->sreg2 = sp [1]->dreg;
10479                         type_from_op (cfg, ins, sp [0], sp [1]);
10480                         CHECK_TYPE (ins);
10481                         add_widen_op (cfg, ins, &sp [0], &sp [1]);
10482                         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type);
10483
10484                         /* FIXME: Pass opcode to is_inst_imm */
10485
10486                         /* Use the immediate opcodes if possible */
10487                         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)) {
10488                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
10489                                 if (imm_opcode != -1) {
10490                                         ins->opcode = imm_opcode;
10491                                         if (sp [1]->opcode == OP_I8CONST) {
10492 #if SIZEOF_REGISTER == 8
10493                                                 ins->inst_imm = sp [1]->inst_l;
10494 #else
10495                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
10496                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
10497 #endif
10498                                         }
10499                                         else
10500                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
10501                                         ins->sreg2 = -1;
10502
10503                                         /* Might be followed by an instruction added by add_widen_op */
10504                                         if (sp [1]->next == NULL)
10505                                                 NULLIFY_INS (sp [1]);
10506                                 }
10507                         }
10508                         MONO_ADD_INS ((cfg)->cbb, (ins));
10509
10510                         *sp++ = mono_decompose_opcode (cfg, ins);
10511                         ip++;
10512                         break;
10513                 case CEE_NEG:
10514                 case CEE_NOT:
10515                 case CEE_CONV_I1:
10516                 case CEE_CONV_I2:
10517                 case CEE_CONV_I4:
10518                 case CEE_CONV_R4:
10519                 case CEE_CONV_R8:
10520                 case CEE_CONV_U4:
10521                 case CEE_CONV_I8:
10522                 case CEE_CONV_U8:
10523                 case CEE_CONV_OVF_I8:
10524                 case CEE_CONV_OVF_U8:
10525                 case CEE_CONV_R_UN:
10526                         CHECK_STACK (1);
10527
10528                         /* Special case this earlier so we have long constants in the IR */
10529                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
10530                                 int data = sp [-1]->inst_c0;
10531                                 sp [-1]->opcode = OP_I8CONST;
10532                                 sp [-1]->type = STACK_I8;
10533 #if SIZEOF_REGISTER == 8
10534                                 if ((*ip) == CEE_CONV_U8)
10535                                         sp [-1]->inst_c0 = (guint32)data;
10536                                 else
10537                                         sp [-1]->inst_c0 = data;
10538 #else
10539                                 sp [-1]->inst_ls_word = data;
10540                                 if ((*ip) == CEE_CONV_U8)
10541                                         sp [-1]->inst_ms_word = 0;
10542                                 else
10543                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
10544 #endif
10545                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
10546                         }
10547                         else {
10548                                 ADD_UNOP (*ip);
10549                         }
10550                         ip++;
10551                         break;
10552                 case CEE_CONV_OVF_I4:
10553                 case CEE_CONV_OVF_I1:
10554                 case CEE_CONV_OVF_I2:
10555                 case CEE_CONV_OVF_I:
10556                 case CEE_CONV_OVF_U:
10557                         CHECK_STACK (1);
10558
10559                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10560                                 ADD_UNOP (CEE_CONV_OVF_I8);
10561                                 ADD_UNOP (*ip);
10562                         } else {
10563                                 ADD_UNOP (*ip);
10564                         }
10565                         ip++;
10566                         break;
10567                 case CEE_CONV_OVF_U1:
10568                 case CEE_CONV_OVF_U2:
10569                 case CEE_CONV_OVF_U4:
10570                         CHECK_STACK (1);
10571
10572                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10573                                 ADD_UNOP (CEE_CONV_OVF_U8);
10574                                 ADD_UNOP (*ip);
10575                         } else {
10576                                 ADD_UNOP (*ip);
10577                         }
10578                         ip++;
10579                         break;
10580                 case CEE_CONV_OVF_I1_UN:
10581                 case CEE_CONV_OVF_I2_UN:
10582                 case CEE_CONV_OVF_I4_UN:
10583                 case CEE_CONV_OVF_I8_UN:
10584                 case CEE_CONV_OVF_U1_UN:
10585                 case CEE_CONV_OVF_U2_UN:
10586                 case CEE_CONV_OVF_U4_UN:
10587                 case CEE_CONV_OVF_U8_UN:
10588                 case CEE_CONV_OVF_I_UN:
10589                 case CEE_CONV_OVF_U_UN:
10590                 case CEE_CONV_U2:
10591                 case CEE_CONV_U1:
10592                 case CEE_CONV_I:
10593                 case CEE_CONV_U:
10594                         CHECK_STACK (1);
10595                         ADD_UNOP (*ip);
10596                         CHECK_CFG_EXCEPTION;
10597                         ip++;
10598                         break;
10599                 case CEE_ADD_OVF:
10600                 case CEE_ADD_OVF_UN:
10601                 case CEE_MUL_OVF:
10602                 case CEE_MUL_OVF_UN:
10603                 case CEE_SUB_OVF:
10604                 case CEE_SUB_OVF_UN:
10605                         CHECK_STACK (2);
10606                         ADD_BINOP (*ip);
10607                         ip++;
10608                         break;
10609                 case CEE_CPOBJ:
10610                         GSHAREDVT_FAILURE (*ip);
10611                         CHECK_OPSIZE (5);
10612                         CHECK_STACK (2);
10613                         token = read32 (ip + 1);
10614                         klass = mini_get_class (method, token, generic_context);
10615                         CHECK_TYPELOAD (klass);
10616                         sp -= 2;
10617                         if (generic_class_is_reference_type (cfg, klass)) {
10618                                 MonoInst *store, *load;
10619                                 int dreg = alloc_ireg_ref (cfg);
10620
10621                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
10622                                 load->flags |= ins_flag;
10623                                 MONO_ADD_INS (cfg->cbb, load);
10624
10625                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
10626                                 store->flags |= ins_flag;
10627                                 MONO_ADD_INS (cfg->cbb, store);
10628
10629                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
10630                                         emit_write_barrier (cfg, sp [0], sp [1]);
10631                         } else {
10632                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10633                         }
10634                         ins_flag = 0;
10635                         ip += 5;
10636                         break;
10637                 case CEE_LDOBJ: {
10638                         int loc_index = -1;
10639                         int stloc_len = 0;
10640
10641                         CHECK_OPSIZE (5);
10642                         CHECK_STACK (1);
10643                         --sp;
10644                         token = read32 (ip + 1);
10645                         klass = mini_get_class (method, token, generic_context);
10646                         CHECK_TYPELOAD (klass);
10647
10648                         /* Optimize the common ldobj+stloc combination */
10649                         switch (ip [5]) {
10650                         case CEE_STLOC_S:
10651                                 loc_index = ip [6];
10652                                 stloc_len = 2;
10653                                 break;
10654                         case CEE_STLOC_0:
10655                         case CEE_STLOC_1:
10656                         case CEE_STLOC_2:
10657                         case CEE_STLOC_3:
10658                                 loc_index = ip [5] - CEE_STLOC_0;
10659                                 stloc_len = 1;
10660                                 break;
10661                         default:
10662                                 break;
10663                         }
10664
10665                         if ((loc_index != -1) && ip_in_bb (cfg, cfg->cbb, ip + 5)) {
10666                                 CHECK_LOCAL (loc_index);
10667
10668                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10669                                 ins->dreg = cfg->locals [loc_index]->dreg;
10670                                 ins->flags |= ins_flag;
10671                                 ip += 5;
10672                                 ip += stloc_len;
10673                                 if (ins_flag & MONO_INST_VOLATILE) {
10674                                         /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10675                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10676                                 }
10677                                 ins_flag = 0;
10678                                 break;
10679                         }
10680
10681                         /* Optimize the ldobj+stobj combination */
10682                         /* The reference case ends up being a load+store anyway */
10683                         /* Skip this if the operation is volatile. */
10684                         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)) {
10685                                 CHECK_STACK (1);
10686
10687                                 sp --;
10688
10689                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10690
10691                                 ip += 5 + 5;
10692                                 ins_flag = 0;
10693                                 break;
10694                         }
10695
10696                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10697                         ins->flags |= ins_flag;
10698                         *sp++ = ins;
10699
10700                         if (ins_flag & MONO_INST_VOLATILE) {
10701                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10702                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10703                         }
10704
10705                         ip += 5;
10706                         ins_flag = 0;
10707                         inline_costs += 1;
10708                         break;
10709                 }
10710                 case CEE_LDSTR:
10711                         CHECK_STACK_OVF (1);
10712                         CHECK_OPSIZE (5);
10713                         n = read32 (ip + 1);
10714
10715                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
10716                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
10717                                 ins->type = STACK_OBJ;
10718                                 *sp = ins;
10719                         }
10720                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
10721                                 MonoInst *iargs [1];
10722                                 char *str = (char *)mono_method_get_wrapper_data (method, n);
10723
10724                                 if (cfg->compile_aot)
10725                                         EMIT_NEW_LDSTRLITCONST (cfg, iargs [0], str);
10726                                 else
10727                                         EMIT_NEW_PCONST (cfg, iargs [0], str);
10728                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
10729                         } else {
10730                                 if (cfg->opt & MONO_OPT_SHARED) {
10731                                         MonoInst *iargs [3];
10732
10733                                         if (cfg->compile_aot) {
10734                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
10735                                         }
10736                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10737                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
10738                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
10739                                         *sp = mono_emit_jit_icall (cfg, mono_ldstr, iargs);
10740                                         mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
10741                                 } else {
10742                                         if (cfg->cbb->out_of_line) {
10743                                                 MonoInst *iargs [2];
10744
10745                                                 if (image == mono_defaults.corlib) {
10746                                                         /* 
10747                                                          * Avoid relocations in AOT and save some space by using a 
10748                                                          * version of helper_ldstr specialized to mscorlib.
10749                                                          */
10750                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
10751                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
10752                                                 } else {
10753                                                         /* Avoid creating the string object */
10754                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
10755                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
10756                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
10757                                                 }
10758                                         } 
10759                                         else
10760                                         if (cfg->compile_aot) {
10761                                                 NEW_LDSTRCONST (cfg, ins, image, n);
10762                                                 *sp = ins;
10763                                                 MONO_ADD_INS (cfg->cbb, ins);
10764                                         } 
10765                                         else {
10766                                                 NEW_PCONST (cfg, ins, NULL);
10767                                                 ins->type = STACK_OBJ;
10768                                                 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
10769                                                 if (!ins->inst_p0)
10770                                                         OUT_OF_MEMORY_FAILURE;
10771
10772                                                 *sp = ins;
10773                                                 MONO_ADD_INS (cfg->cbb, ins);
10774                                         }
10775                                 }
10776                         }
10777
10778                         sp++;
10779                         ip += 5;
10780                         break;
10781                 case CEE_NEWOBJ: {
10782                         MonoInst *iargs [2];
10783                         MonoMethodSignature *fsig;
10784                         MonoInst this_ins;
10785                         MonoInst *alloc;
10786                         MonoInst *vtable_arg = NULL;
10787
10788                         CHECK_OPSIZE (5);
10789                         token = read32 (ip + 1);
10790                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
10791                         CHECK_CFG_ERROR;
10792
10793                         fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
10794                         CHECK_CFG_ERROR;
10795
10796                         mono_save_token_info (cfg, image, token, cmethod);
10797
10798                         if (!mono_class_init (cmethod->klass))
10799                                 TYPE_LOAD_ERROR (cmethod->klass);
10800
10801                         context_used = mini_method_check_context_used (cfg, cmethod);
10802
10803                         if (mono_security_core_clr_enabled ())
10804                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
10805
10806                         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)) {
10807                                 emit_class_init (cfg, cmethod->klass);
10808                                 CHECK_TYPELOAD (cmethod->klass);
10809                         }
10810
10811                         /*
10812                         if (cfg->gsharedvt) {
10813                                 if (mini_is_gsharedvt_variable_signature (sig))
10814                                         GSHAREDVT_FAILURE (*ip);
10815                         }
10816                         */
10817
10818                         n = fsig->param_count;
10819                         CHECK_STACK (n);
10820
10821                         /* 
10822                          * Generate smaller code for the common newobj <exception> instruction in
10823                          * argument checking code.
10824                          */
10825                         if (cfg->cbb->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
10826                                 is_exception_class (cmethod->klass) && n <= 2 &&
10827                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
10828                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
10829                                 MonoInst *iargs [3];
10830
10831                                 sp -= n;
10832
10833                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
10834                                 switch (n) {
10835                                 case 0:
10836                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
10837                                         break;
10838                                 case 1:
10839                                         iargs [1] = sp [0];
10840                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
10841                                         break;
10842                                 case 2:
10843                                         iargs [1] = sp [0];
10844                                         iargs [2] = sp [1];
10845                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
10846                                         break;
10847                                 default:
10848                                         g_assert_not_reached ();
10849                                 }
10850
10851                                 ip += 5;
10852                                 inline_costs += 5;
10853                                 break;
10854                         }
10855
10856                         /* move the args to allow room for 'this' in the first position */
10857                         while (n--) {
10858                                 --sp;
10859                                 sp [1] = sp [0];
10860                         }
10861
10862                         /* check_call_signature () requires sp[0] to be set */
10863                         this_ins.type = STACK_OBJ;
10864                         sp [0] = &this_ins;
10865                         if (check_call_signature (cfg, fsig, sp))
10866                                 UNVERIFIED;
10867
10868                         iargs [0] = NULL;
10869
10870                         if (mini_class_is_system_array (cmethod->klass)) {
10871                                 *sp = emit_get_rgctx_method (cfg, context_used,
10872                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
10873
10874                                 /* Avoid varargs in the common case */
10875                                 if (fsig->param_count == 1)
10876                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
10877                                 else if (fsig->param_count == 2)
10878                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
10879                                 else if (fsig->param_count == 3)
10880                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
10881                                 else if (fsig->param_count == 4)
10882                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
10883                                 else
10884                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
10885                         } else if (cmethod->string_ctor) {
10886                                 g_assert (!context_used);
10887                                 g_assert (!vtable_arg);
10888                                 /* we simply pass a null pointer */
10889                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
10890                                 /* now call the string ctor */
10891                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
10892                         } else {
10893                                 if (cmethod->klass->valuetype) {
10894                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
10895                                         emit_init_rvar (cfg, iargs [0]->dreg, &cmethod->klass->byval_arg);
10896                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
10897
10898                                         alloc = NULL;
10899
10900                                         /* 
10901                                          * The code generated by mini_emit_virtual_call () expects
10902                                          * iargs [0] to be a boxed instance, but luckily the vcall
10903                                          * will be transformed into a normal call there.
10904                                          */
10905                                 } else if (context_used) {
10906                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
10907                                         *sp = alloc;
10908                                 } else {
10909                                         MonoVTable *vtable = NULL;
10910
10911                                         if (!cfg->compile_aot)
10912                                                 vtable = mono_class_vtable (cfg->domain, cmethod->klass);
10913                                         CHECK_TYPELOAD (cmethod->klass);
10914
10915                                         /*
10916                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
10917                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
10918                                          * As a workaround, we call class cctors before allocating objects.
10919                                          */
10920                                         if (mini_field_access_needs_cctor_run (cfg, method, cmethod->klass, vtable) && !(g_slist_find (class_inits, cmethod->klass))) {
10921                                                 emit_class_init (cfg, cmethod->klass);
10922                                                 if (cfg->verbose_level > 2)
10923                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
10924                                                 class_inits = g_slist_prepend (class_inits, cmethod->klass);
10925                                         }
10926
10927                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
10928                                         *sp = alloc;
10929                                 }
10930                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
10931
10932                                 if (alloc)
10933                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
10934
10935                                 /* Now call the actual ctor */
10936                                 handle_ctor_call (cfg, cmethod, fsig, context_used, sp, ip, &inline_costs);
10937                                 CHECK_CFG_EXCEPTION;
10938                         }
10939
10940                         if (alloc == NULL) {
10941                                 /* Valuetype */
10942                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
10943                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
10944                                 *sp++= ins;
10945                         } else {
10946                                 *sp++ = alloc;
10947                         }
10948                         
10949                         ip += 5;
10950                         inline_costs += 5;
10951                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip - header->code)))
10952                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10953                         break;
10954                 }
10955                 case CEE_CASTCLASS:
10956                         CHECK_STACK (1);
10957                         --sp;
10958                         CHECK_OPSIZE (5);
10959                         token = read32 (ip + 1);
10960                         klass = mini_get_class (method, token, generic_context);
10961                         CHECK_TYPELOAD (klass);
10962                         if (sp [0]->type != STACK_OBJ)
10963                                 UNVERIFIED;
10964
10965                         ins = handle_castclass (cfg, klass, *sp, ip, &inline_costs);
10966                         CHECK_CFG_EXCEPTION;
10967
10968                         *sp ++ = ins;
10969                         ip += 5;
10970                         break;
10971                 case CEE_ISINST: {
10972                         CHECK_STACK (1);
10973                         --sp;
10974                         CHECK_OPSIZE (5);
10975                         token = read32 (ip + 1);
10976                         klass = mini_get_class (method, token, generic_context);
10977                         CHECK_TYPELOAD (klass);
10978                         if (sp [0]->type != STACK_OBJ)
10979                                 UNVERIFIED;
10980  
10981                         context_used = mini_class_check_context_used (cfg, klass);
10982
10983                         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
10984                                 MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
10985                                 MonoInst *args [3];
10986                                 int idx;
10987
10988                                 /* obj */
10989                                 args [0] = *sp;
10990
10991                                 /* klass */
10992                                 EMIT_NEW_CLASSCONST (cfg, args [1], klass);
10993
10994                                 /* inline cache*/
10995                                 idx = get_castclass_cache_idx (cfg);
10996                                 args [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
10997
10998                                 *sp++ = mono_emit_method_call (cfg, mono_isinst, args, NULL);
10999                                 ip += 5;
11000                                 inline_costs += 2;
11001                         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
11002                                 MonoMethod *mono_isinst;
11003                                 MonoInst *iargs [1];
11004                                 int costs;
11005
11006                                 mono_isinst = mono_marshal_get_isinst (klass); 
11007                                 iargs [0] = sp [0];
11008
11009                                 costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), 
11010                                                                            iargs, ip, cfg->real_offset, TRUE);
11011                                 CHECK_CFG_EXCEPTION;
11012                                 g_assert (costs > 0);
11013                                 
11014                                 ip += 5;
11015                                 cfg->real_offset += 5;
11016
11017                                 *sp++= iargs [0];
11018
11019                                 inline_costs += costs;
11020                         }
11021                         else {
11022                                 ins = handle_isinst (cfg, klass, *sp, context_used);
11023                                 CHECK_CFG_EXCEPTION;
11024                                 *sp ++ = ins;
11025                                 ip += 5;
11026                         }
11027                         break;
11028                 }
11029                 case CEE_UNBOX_ANY: {
11030                         MonoInst *res, *addr;
11031
11032                         CHECK_STACK (1);
11033                         --sp;
11034                         CHECK_OPSIZE (5);
11035                         token = read32 (ip + 1);
11036                         klass = mini_get_class (method, token, generic_context);
11037                         CHECK_TYPELOAD (klass);
11038
11039                         mono_save_token_info (cfg, image, token, klass);
11040
11041                         context_used = mini_class_check_context_used (cfg, klass);
11042
11043                         if (mini_is_gsharedvt_klass (klass)) {
11044                                 res = handle_unbox_gsharedvt (cfg, klass, *sp);
11045                                 inline_costs += 2;
11046                         } else if (generic_class_is_reference_type (cfg, klass)) {
11047                                 res = handle_castclass (cfg, klass, *sp, ip, &inline_costs);
11048                                 CHECK_CFG_EXCEPTION;
11049                         } else if (mono_class_is_nullable (klass)) {
11050                                 res = handle_unbox_nullable (cfg, *sp, klass, context_used);
11051                         } else {
11052                                 addr = handle_unbox (cfg, klass, sp, context_used);
11053                                 /* LDOBJ */
11054                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11055                                 res = ins;
11056                                 inline_costs += 2;
11057                         }
11058
11059                         *sp ++ = res;
11060                         ip += 5;
11061                         break;
11062                 }
11063                 case CEE_BOX: {
11064                         MonoInst *val;
11065                         MonoClass *enum_class;
11066                         MonoMethod *has_flag;
11067
11068                         CHECK_STACK (1);
11069                         --sp;
11070                         val = *sp;
11071                         CHECK_OPSIZE (5);
11072                         token = read32 (ip + 1);
11073                         klass = mini_get_class (method, token, generic_context);
11074                         CHECK_TYPELOAD (klass);
11075
11076                         mono_save_token_info (cfg, image, token, klass);
11077
11078                         context_used = mini_class_check_context_used (cfg, klass);
11079
11080                         if (generic_class_is_reference_type (cfg, klass)) {
11081                                 *sp++ = val;
11082                                 ip += 5;
11083                                 break;
11084                         }
11085
11086                         if (klass == mono_defaults.void_class)
11087                                 UNVERIFIED;
11088                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
11089                                 UNVERIFIED;
11090                         /* frequent check in generic code: box (struct), brtrue */
11091
11092                         /*
11093                          * Look for:
11094                          *
11095                          *   <push int/long ptr>
11096                          *   <push int/long>
11097                          *   box MyFlags
11098                          *   constrained. MyFlags
11099                          *   callvirt instace bool class [mscorlib] System.Enum::HasFlag (class [mscorlib] System.Enum)
11100                          *
11101                          * If we find this sequence and the operand types on box and constrained
11102                          * are equal, we can emit a specialized instruction sequence instead of
11103                          * the very slow HasFlag () call.
11104                          */
11105                         if ((cfg->opt & MONO_OPT_INTRINS) &&
11106                             /* Cheap checks first. */
11107                             ip + 5 + 6 + 5 < end &&
11108                             ip [5] == CEE_PREFIX1 &&
11109                             ip [6] == CEE_CONSTRAINED_ &&
11110                             ip [11] == CEE_CALLVIRT &&
11111                             ip_in_bb (cfg, cfg->cbb, ip + 5 + 6 + 5) &&
11112                             mono_class_is_enum (klass) &&
11113                             (enum_class = mini_get_class (method, read32 (ip + 7), generic_context)) &&
11114                             (has_flag = mini_get_method (cfg, method, read32 (ip + 12), NULL, generic_context)) &&
11115                             has_flag->klass == mono_defaults.enum_class &&
11116                             !strcmp (has_flag->name, "HasFlag") &&
11117                             has_flag->signature->hasthis &&
11118                             has_flag->signature->param_count == 1) {
11119                                 CHECK_TYPELOAD (enum_class);
11120
11121                                 if (enum_class == klass) {
11122                                         MonoInst *enum_this, *enum_flag;
11123
11124                                         ip += 5 + 6 + 5;
11125                                         --sp;
11126
11127                                         enum_this = sp [0];
11128                                         enum_flag = sp [1];
11129
11130                                         *sp++ = handle_enum_has_flag (cfg, klass, enum_this, enum_flag);
11131                                         break;
11132                                 }
11133                         }
11134
11135                         // FIXME: LLVM can't handle the inconsistent bb linking
11136                         if (!mono_class_is_nullable (klass) &&
11137                                 !mini_is_gsharedvt_klass (klass) &&
11138                                 ip + 5 < end && ip_in_bb (cfg, cfg->cbb, ip + 5) &&
11139                                 (ip [5] == CEE_BRTRUE || 
11140                                  ip [5] == CEE_BRTRUE_S ||
11141                                  ip [5] == CEE_BRFALSE ||
11142                                  ip [5] == CEE_BRFALSE_S)) {
11143                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
11144                                 int dreg;
11145                                 MonoBasicBlock *true_bb, *false_bb;
11146
11147                                 ip += 5;
11148
11149                                 if (cfg->verbose_level > 3) {
11150                                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
11151                                         printf ("<box+brtrue opt>\n");
11152                                 }
11153
11154                                 switch (*ip) {
11155                                 case CEE_BRTRUE_S:
11156                                 case CEE_BRFALSE_S:
11157                                         CHECK_OPSIZE (2);
11158                                         ip++;
11159                                         target = ip + 1 + (signed char)(*ip);
11160                                         ip++;
11161                                         break;
11162                                 case CEE_BRTRUE:
11163                                 case CEE_BRFALSE:
11164                                         CHECK_OPSIZE (5);
11165                                         ip++;
11166                                         target = ip + 4 + (gint)(read32 (ip));
11167                                         ip += 4;
11168                                         break;
11169                                 default:
11170                                         g_assert_not_reached ();
11171                                 }
11172
11173                                 /* 
11174                                  * We need to link both bblocks, since it is needed for handling stack
11175                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
11176                                  * Branching to only one of them would lead to inconsistencies, so
11177                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
11178                                  */
11179                                 GET_BBLOCK (cfg, true_bb, target);
11180                                 GET_BBLOCK (cfg, false_bb, ip);
11181
11182                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
11183                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
11184
11185                                 if (sp != stack_start) {
11186                                         handle_stack_args (cfg, stack_start, sp - stack_start);
11187                                         sp = stack_start;
11188                                         CHECK_UNVERIFIABLE (cfg);
11189                                 }
11190
11191                                 if (COMPILE_LLVM (cfg)) {
11192                                         dreg = alloc_ireg (cfg);
11193                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
11194                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
11195
11196                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
11197                                 } else {
11198                                         /* The JIT can't eliminate the iconst+compare */
11199                                         MONO_INST_NEW (cfg, ins, OP_BR);
11200                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
11201                                         MONO_ADD_INS (cfg->cbb, ins);
11202                                 }
11203
11204                                 start_new_bblock = 1;
11205                                 break;
11206                         }
11207
11208                         *sp++ = handle_box (cfg, val, klass, context_used);
11209
11210                         CHECK_CFG_EXCEPTION;
11211                         ip += 5;
11212                         inline_costs += 1;
11213                         break;
11214                 }
11215                 case CEE_UNBOX: {
11216                         CHECK_STACK (1);
11217                         --sp;
11218                         CHECK_OPSIZE (5);
11219                         token = read32 (ip + 1);
11220                         klass = mini_get_class (method, token, generic_context);
11221                         CHECK_TYPELOAD (klass);
11222
11223                         mono_save_token_info (cfg, image, token, klass);
11224
11225                         context_used = mini_class_check_context_used (cfg, klass);
11226
11227                         if (mono_class_is_nullable (klass)) {
11228                                 MonoInst *val;
11229
11230                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
11231                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
11232
11233                                 *sp++= ins;
11234                         } else {
11235                                 ins = handle_unbox (cfg, klass, sp, context_used);
11236                                 *sp++ = ins;
11237                         }
11238                         ip += 5;
11239                         inline_costs += 2;
11240                         break;
11241                 }
11242                 case CEE_LDFLD:
11243                 case CEE_LDFLDA:
11244                 case CEE_STFLD:
11245                 case CEE_LDSFLD:
11246                 case CEE_LDSFLDA:
11247                 case CEE_STSFLD: {
11248                         MonoClassField *field;
11249 #ifndef DISABLE_REMOTING
11250                         int costs;
11251 #endif
11252                         guint foffset;
11253                         gboolean is_instance;
11254                         int op;
11255                         gpointer addr = NULL;
11256                         gboolean is_special_static;
11257                         MonoType *ftype;
11258                         MonoInst *store_val = NULL;
11259                         MonoInst *thread_ins;
11260
11261                         op = *ip;
11262                         is_instance = (op == CEE_LDFLD || op == CEE_LDFLDA || op == CEE_STFLD);
11263                         if (is_instance) {
11264                                 if (op == CEE_STFLD) {
11265                                         CHECK_STACK (2);
11266                                         sp -= 2;
11267                                         store_val = sp [1];
11268                                 } else {
11269                                         CHECK_STACK (1);
11270                                         --sp;
11271                                 }
11272                                 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
11273                                         UNVERIFIED;
11274                                 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
11275                                         UNVERIFIED;
11276                         } else {
11277                                 if (op == CEE_STSFLD) {
11278                                         CHECK_STACK (1);
11279                                         sp--;
11280                                         store_val = sp [0];
11281                                 }
11282                         }
11283
11284                         CHECK_OPSIZE (5);
11285                         token = read32 (ip + 1);
11286                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
11287                                 field = (MonoClassField *)mono_method_get_wrapper_data (method, token);
11288                                 klass = field->parent;
11289                         }
11290                         else {
11291                                 field = mono_field_from_token_checked (image, token, &klass, generic_context, &cfg->error);
11292                                 CHECK_CFG_ERROR;
11293                         }
11294                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
11295                                 FIELD_ACCESS_FAILURE (method, field);
11296                         mono_class_init (klass);
11297
11298                         /* if the class is Critical then transparent code cannot access it's fields */
11299                         if (!is_instance && mono_security_core_clr_enabled ())
11300                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
11301
11302                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
11303                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
11304                         if (mono_security_core_clr_enabled ())
11305                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
11306                         */
11307
11308                         ftype = mono_field_get_type (field);
11309
11310                         /*
11311                          * LDFLD etc. is usable on static fields as well, so convert those cases to
11312                          * the static case.
11313                          */
11314                         if (is_instance && ftype->attrs & FIELD_ATTRIBUTE_STATIC) {
11315                                 switch (op) {
11316                                 case CEE_LDFLD:
11317                                         op = CEE_LDSFLD;
11318                                         break;
11319                                 case CEE_STFLD:
11320                                         op = CEE_STSFLD;
11321                                         break;
11322                                 case CEE_LDFLDA:
11323                                         op = CEE_LDSFLDA;
11324                                         break;
11325                                 default:
11326                                         g_assert_not_reached ();
11327                                 }
11328                                 is_instance = FALSE;
11329                         }
11330
11331                         context_used = mini_class_check_context_used (cfg, klass);
11332
11333                         /* INSTANCE CASE */
11334
11335                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
11336                         if (op == CEE_STFLD) {
11337                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
11338                                         UNVERIFIED;
11339 #ifndef DISABLE_REMOTING
11340                                 if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
11341                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
11342                                         MonoInst *iargs [5];
11343
11344                                         GSHAREDVT_FAILURE (op);
11345
11346                                         iargs [0] = sp [0];
11347                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11348                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
11349                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
11350                                                     field->offset);
11351                                         iargs [4] = sp [1];
11352
11353                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
11354                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
11355                                                                                            iargs, ip, cfg->real_offset, TRUE);
11356                                                 CHECK_CFG_EXCEPTION;
11357                                                 g_assert (costs > 0);
11358                                                       
11359                                                 cfg->real_offset += 5;
11360
11361                                                 inline_costs += costs;
11362                                         } else {
11363                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
11364                                         }
11365                                 } else
11366 #endif
11367                                 {
11368                                         MonoInst *store;
11369
11370                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
11371
11372                                         if (mini_is_gsharedvt_klass (klass)) {
11373                                                 MonoInst *offset_ins;
11374
11375                                                 context_used = mini_class_check_context_used (cfg, klass);
11376
11377                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11378                                                 /* The value is offset by 1 */
11379                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11380                                                 dreg = alloc_ireg_mp (cfg);
11381                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11382                                                 /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
11383                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
11384                                         } else {
11385                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
11386                                         }
11387                                         if (sp [0]->opcode != OP_LDADDR)
11388                                                 store->flags |= MONO_INST_FAULT;
11389
11390                                 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)) {
11391                                         /* insert call to write barrier */
11392                                         MonoInst *ptr;
11393                                         int dreg;
11394
11395                                         dreg = alloc_ireg_mp (cfg);
11396                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
11397                                         emit_write_barrier (cfg, ptr, sp [1]);
11398                                 }
11399
11400                                         store->flags |= ins_flag;
11401                                 }
11402                                 ins_flag = 0;
11403                                 ip += 5;
11404                                 break;
11405                         }
11406
11407 #ifndef DISABLE_REMOTING
11408                         if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
11409                                 MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
11410                                 MonoInst *iargs [4];
11411
11412                                 GSHAREDVT_FAILURE (op);
11413
11414                                 iargs [0] = sp [0];
11415                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11416                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
11417                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
11418                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
11419                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
11420                                                                                    iargs, ip, cfg->real_offset, TRUE);
11421                                         CHECK_CFG_EXCEPTION;
11422                                         g_assert (costs > 0);
11423                                                       
11424                                         cfg->real_offset += 5;
11425
11426                                         *sp++ = iargs [0];
11427
11428                                         inline_costs += costs;
11429                                 } else {
11430                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
11431                                         *sp++ = ins;
11432                                 }
11433                         } else 
11434 #endif
11435                         if (is_instance) {
11436                                 if (sp [0]->type == STACK_VTYPE) {
11437                                         MonoInst *var;
11438
11439                                         /* Have to compute the address of the variable */
11440
11441                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
11442                                         if (!var)
11443                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
11444                                         else
11445                                                 g_assert (var->klass == klass);
11446                                         
11447                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
11448                                         sp [0] = ins;
11449                                 }
11450
11451                                 if (op == CEE_LDFLDA) {
11452                                         if (sp [0]->type == STACK_OBJ) {
11453                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
11454                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
11455                                         }
11456
11457                                         dreg = alloc_ireg_mp (cfg);
11458
11459                                         if (mini_is_gsharedvt_klass (klass)) {
11460                                                 MonoInst *offset_ins;
11461
11462                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11463                                                 /* The value is offset by 1 */
11464                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11465                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11466                                         } else {
11467                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
11468                                         }
11469                                         ins->klass = mono_class_from_mono_type (field->type);
11470                                         ins->type = STACK_MP;
11471                                         *sp++ = ins;
11472                                 } else {
11473                                         MonoInst *load;
11474
11475                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
11476
11477                                         if (mini_is_gsharedvt_klass (klass)) {
11478                                                 MonoInst *offset_ins;
11479
11480                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11481                                                 /* The value is offset by 1 */
11482                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11483                                                 dreg = alloc_ireg_mp (cfg);
11484                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11485                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
11486                                         } else {
11487                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
11488                                         }
11489                                         load->flags |= ins_flag;
11490                                         if (sp [0]->opcode != OP_LDADDR)
11491                                                 load->flags |= MONO_INST_FAULT;
11492                                         *sp++ = load;
11493                                 }
11494                         }
11495
11496                         if (is_instance) {
11497                                 ins_flag = 0;
11498                                 ip += 5;
11499                                 break;
11500                         }
11501
11502                         /* STATIC CASE */
11503                         context_used = mini_class_check_context_used (cfg, klass);
11504
11505                         if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL) {
11506                                 mono_error_set_field_load (&cfg->error, field->parent, field->name, "Using static instructions with literal field");
11507                                 CHECK_CFG_ERROR;
11508                         }
11509
11510                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
11511                          * to be called here.
11512                          */
11513                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
11514                                 mono_class_vtable (cfg->domain, klass);
11515                                 CHECK_TYPELOAD (klass);
11516                         }
11517                         mono_domain_lock (cfg->domain);
11518                         if (cfg->domain->special_static_fields)
11519                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
11520                         mono_domain_unlock (cfg->domain);
11521
11522                         is_special_static = mono_class_field_is_special_static (field);
11523
11524                         if (is_special_static && ((gsize)addr & 0x80000000) == 0)
11525                                 thread_ins = mono_get_thread_intrinsic (cfg);
11526                         else
11527                                 thread_ins = NULL;
11528
11529                         /* Generate IR to compute the field address */
11530                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && thread_ins && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
11531                                 /*
11532                                  * Fast access to TLS data
11533                                  * Inline version of get_thread_static_data () in
11534                                  * threads.c.
11535                                  */
11536                                 guint32 offset;
11537                                 int idx, static_data_reg, array_reg, dreg;
11538
11539                                 GSHAREDVT_FAILURE (op);
11540
11541                                 MONO_ADD_INS (cfg->cbb, thread_ins);
11542                                 static_data_reg = alloc_ireg (cfg);
11543                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
11544
11545                                 if (cfg->compile_aot) {
11546                                         int offset_reg, offset2_reg, idx_reg;
11547
11548                                         /* For TLS variables, this will return the TLS offset */
11549                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
11550                                         offset_reg = ins->dreg;
11551                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
11552                                         idx_reg = alloc_ireg (cfg);
11553                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, idx_reg, offset_reg, 0x3f);
11554                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
11555                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
11556                                         array_reg = alloc_ireg (cfg);
11557                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
11558                                         offset2_reg = alloc_ireg (cfg);
11559                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, offset2_reg, offset_reg, 6);
11560                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset2_reg, 0x1ffffff);
11561                                         dreg = alloc_ireg (cfg);
11562                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
11563                                 } else {
11564                                         offset = (gsize)addr & 0x7fffffff;
11565                                         idx = offset & 0x3f;
11566
11567                                         array_reg = alloc_ireg (cfg);
11568                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
11569                                         dreg = alloc_ireg (cfg);
11570                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, ((offset >> 6) & 0x1ffffff));
11571                                 }
11572                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
11573                                         (cfg->compile_aot && is_special_static) ||
11574                                         (context_used && is_special_static)) {
11575                                 MonoInst *iargs [2];
11576
11577                                 g_assert (field->parent);
11578                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11579                                 if (context_used) {
11580                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
11581                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
11582                                 } else {
11583                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11584                                 }
11585                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11586                         } else if (context_used) {
11587                                 MonoInst *static_data;
11588
11589                                 /*
11590                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
11591                                         method->klass->name_space, method->klass->name, method->name,
11592                                         depth, field->offset);
11593                                 */
11594
11595                                 if (mono_class_needs_cctor_run (klass, method))
11596                                         emit_class_init (cfg, klass);
11597
11598                                 /*
11599                                  * The pointer we're computing here is
11600                                  *
11601                                  *   super_info.static_data + field->offset
11602                                  */
11603                                 static_data = emit_get_rgctx_klass (cfg, context_used,
11604                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
11605
11606                                 if (mini_is_gsharedvt_klass (klass)) {
11607                                         MonoInst *offset_ins;
11608
11609                                         offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11610                                         /* The value is offset by 1 */
11611                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11612                                         dreg = alloc_ireg_mp (cfg);
11613                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
11614                                 } else if (field->offset == 0) {
11615                                         ins = static_data;
11616                                 } else {
11617                                         int addr_reg = mono_alloc_preg (cfg);
11618                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
11619                                 }
11620                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
11621                                 MonoInst *iargs [2];
11622
11623                                 g_assert (field->parent);
11624                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11625                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11626                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11627                         } else {
11628                                 MonoVTable *vtable = NULL;
11629
11630                                 if (!cfg->compile_aot)
11631                                         vtable = mono_class_vtable (cfg->domain, klass);
11632                                 CHECK_TYPELOAD (klass);
11633
11634                                 if (!addr) {
11635                                         if (mini_field_access_needs_cctor_run (cfg, method, klass, vtable)) {
11636                                                 if (!(g_slist_find (class_inits, klass))) {
11637                                                         emit_class_init (cfg, klass);
11638                                                         if (cfg->verbose_level > 2)
11639                                                                 printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
11640                                                         class_inits = g_slist_prepend (class_inits, klass);
11641                                                 }
11642                                         } else {
11643                                                 if (cfg->run_cctors) {
11644                                                         /* This makes so that inline cannot trigger */
11645                                                         /* .cctors: too many apps depend on them */
11646                                                         /* running with a specific order... */
11647                                                         g_assert (vtable);
11648                                                         if (! vtable->initialized)
11649                                                                 INLINE_FAILURE ("class init");
11650                                                         if (!mono_runtime_class_init_full (vtable, &cfg->error)) {
11651                                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
11652                                                                 g_assert_not_reached ();
11653                                                                 goto exception_exit;
11654                                                         }
11655                                                 }
11656                                         }
11657                                         if (cfg->compile_aot)
11658                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
11659                                         else {
11660                                                 g_assert (vtable);
11661                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11662                                                 g_assert (addr);
11663                                                 EMIT_NEW_PCONST (cfg, ins, addr);
11664                                         }
11665                                 } else {
11666                                         MonoInst *iargs [1];
11667                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
11668                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
11669                                 }
11670                         }
11671
11672                         /* Generate IR to do the actual load/store operation */
11673
11674                         if ((op == CEE_STFLD || op == CEE_STSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11675                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11676                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11677                         }
11678
11679                         if (op == CEE_LDSFLDA) {
11680                                 ins->klass = mono_class_from_mono_type (ftype);
11681                                 ins->type = STACK_PTR;
11682                                 *sp++ = ins;
11683                         } else if (op == CEE_STSFLD) {
11684                                 MonoInst *store;
11685
11686                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
11687                                 store->flags |= ins_flag;
11688                         } else {
11689                                 gboolean is_const = FALSE;
11690                                 MonoVTable *vtable = NULL;
11691                                 gpointer addr = NULL;
11692
11693                                 if (!context_used) {
11694                                         vtable = mono_class_vtable (cfg->domain, klass);
11695                                         CHECK_TYPELOAD (klass);
11696                                 }
11697                                 if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) ||
11698                                                 (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) {
11699                                         int ro_type = ftype->type;
11700                                         if (!addr)
11701                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11702                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
11703                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
11704                                         }
11705
11706                                         GSHAREDVT_FAILURE (op);
11707
11708                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
11709                                         is_const = TRUE;
11710                                         switch (ro_type) {
11711                                         case MONO_TYPE_BOOLEAN:
11712                                         case MONO_TYPE_U1:
11713                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
11714                                                 sp++;
11715                                                 break;
11716                                         case MONO_TYPE_I1:
11717                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
11718                                                 sp++;
11719                                                 break;                                          
11720                                         case MONO_TYPE_CHAR:
11721                                         case MONO_TYPE_U2:
11722                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
11723                                                 sp++;
11724                                                 break;
11725                                         case MONO_TYPE_I2:
11726                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
11727                                                 sp++;
11728                                                 break;
11729                                                 break;
11730                                         case MONO_TYPE_I4:
11731                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
11732                                                 sp++;
11733                                                 break;                                          
11734                                         case MONO_TYPE_U4:
11735                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
11736                                                 sp++;
11737                                                 break;
11738                                         case MONO_TYPE_I:
11739                                         case MONO_TYPE_U:
11740                                         case MONO_TYPE_PTR:
11741                                         case MONO_TYPE_FNPTR:
11742                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11743                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
11744                                                 sp++;
11745                                                 break;
11746                                         case MONO_TYPE_STRING:
11747                                         case MONO_TYPE_OBJECT:
11748                                         case MONO_TYPE_CLASS:
11749                                         case MONO_TYPE_SZARRAY:
11750                                         case MONO_TYPE_ARRAY:
11751                                                 if (!mono_gc_is_moving ()) {
11752                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11753                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
11754                                                         sp++;
11755                                                 } else {
11756                                                         is_const = FALSE;
11757                                                 }
11758                                                 break;
11759                                         case MONO_TYPE_I8:
11760                                         case MONO_TYPE_U8:
11761                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
11762                                                 sp++;
11763                                                 break;
11764                                         case MONO_TYPE_R4:
11765                                         case MONO_TYPE_R8:
11766                                         case MONO_TYPE_VALUETYPE:
11767                                         default:
11768                                                 is_const = FALSE;
11769                                                 break;
11770                                         }
11771                                 }
11772
11773                                 if (!is_const) {
11774                                         MonoInst *load;
11775
11776                                         CHECK_STACK_OVF (1);
11777
11778                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
11779                                         load->flags |= ins_flag;
11780                                         ins_flag = 0;
11781                                         *sp++ = load;
11782                                 }
11783                         }
11784
11785                         if ((op == CEE_LDFLD || op == CEE_LDSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11786                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
11787                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
11788                         }
11789
11790                         ins_flag = 0;
11791                         ip += 5;
11792                         break;
11793                 }
11794                 case CEE_STOBJ:
11795                         CHECK_STACK (2);
11796                         sp -= 2;
11797                         CHECK_OPSIZE (5);
11798                         token = read32 (ip + 1);
11799                         klass = mini_get_class (method, token, generic_context);
11800                         CHECK_TYPELOAD (klass);
11801                         if (ins_flag & MONO_INST_VOLATILE) {
11802                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11803                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11804                         }
11805                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
11806                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
11807                         ins->flags |= ins_flag;
11808                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
11809                                         generic_class_is_reference_type (cfg, klass)) {
11810                                 /* insert call to write barrier */
11811                                 emit_write_barrier (cfg, sp [0], sp [1]);
11812                         }
11813                         ins_flag = 0;
11814                         ip += 5;
11815                         inline_costs += 1;
11816                         break;
11817
11818                         /*
11819                          * Array opcodes
11820                          */
11821                 case CEE_NEWARR: {
11822                         MonoInst *len_ins;
11823                         const char *data_ptr;
11824                         int data_size = 0;
11825                         guint32 field_token;
11826
11827                         CHECK_STACK (1);
11828                         --sp;
11829
11830                         CHECK_OPSIZE (5);
11831                         token = read32 (ip + 1);
11832
11833                         klass = mini_get_class (method, token, generic_context);
11834                         CHECK_TYPELOAD (klass);
11835
11836                         context_used = mini_class_check_context_used (cfg, klass);
11837
11838                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
11839                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_OVF_U4);
11840                                 ins->sreg1 = sp [0]->dreg;
11841                                 ins->type = STACK_I4;
11842                                 ins->dreg = alloc_ireg (cfg);
11843                                 MONO_ADD_INS (cfg->cbb, ins);
11844                                 *sp = mono_decompose_opcode (cfg, ins);
11845                         }
11846
11847                         if (context_used) {
11848                                 MonoInst *args [3];
11849                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11850                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
11851
11852                                 /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
11853
11854                                 /* vtable */
11855                                 args [0] = emit_get_rgctx_klass (cfg, context_used,
11856                                         array_class, MONO_RGCTX_INFO_VTABLE);
11857                                 /* array len */
11858                                 args [1] = sp [0];
11859
11860                                 if (managed_alloc)
11861                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
11862                                 else
11863                                         ins = mono_emit_jit_icall (cfg, ves_icall_array_new_specific, args);
11864                         } else {
11865                                 if (cfg->opt & MONO_OPT_SHARED) {
11866                                         /* Decompose now to avoid problems with references to the domainvar */
11867                                         MonoInst *iargs [3];
11868
11869                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11870                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11871                                         iargs [2] = sp [0];
11872
11873                                         ins = mono_emit_jit_icall (cfg, mono_array_new, iargs);
11874                                 } else {
11875                                         /* Decompose later since it is needed by abcrem */
11876                                         MonoClass *array_type = mono_array_class_get (klass, 1);
11877                                         mono_class_vtable (cfg->domain, array_type);
11878                                         CHECK_TYPELOAD (array_type);
11879
11880                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
11881                                         ins->dreg = alloc_ireg_ref (cfg);
11882                                         ins->sreg1 = sp [0]->dreg;
11883                                         ins->inst_newa_class = klass;
11884                                         ins->type = STACK_OBJ;
11885                                         ins->klass = array_type;
11886                                         MONO_ADD_INS (cfg->cbb, ins);
11887                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11888                                         cfg->cbb->has_array_access = TRUE;
11889
11890                                         /* Needed so mono_emit_load_get_addr () gets called */
11891                                         mono_get_got_var (cfg);
11892                                 }
11893                         }
11894
11895                         len_ins = sp [0];
11896                         ip += 5;
11897                         *sp++ = ins;
11898                         inline_costs += 1;
11899
11900                         /* 
11901                          * we inline/optimize the initialization sequence if possible.
11902                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
11903                          * for small sizes open code the memcpy
11904                          * ensure the rva field is big enough
11905                          */
11906                         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))) {
11907                                 MonoMethod *memcpy_method = get_memcpy_method ();
11908                                 MonoInst *iargs [3];
11909                                 int add_reg = alloc_ireg_mp (cfg);
11910
11911                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, MONO_STRUCT_OFFSET (MonoArray, vector));
11912                                 if (cfg->compile_aot) {
11913                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
11914                                 } else {
11915                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
11916                                 }
11917                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
11918                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
11919                                 ip += 11;
11920                         }
11921
11922                         break;
11923                 }
11924                 case CEE_LDLEN:
11925                         CHECK_STACK (1);
11926                         --sp;
11927                         if (sp [0]->type != STACK_OBJ)
11928                                 UNVERIFIED;
11929
11930                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
11931                         ins->dreg = alloc_preg (cfg);
11932                         ins->sreg1 = sp [0]->dreg;
11933                         ins->type = STACK_I4;
11934                         /* This flag will be inherited by the decomposition */
11935                         ins->flags |= MONO_INST_FAULT;
11936                         MONO_ADD_INS (cfg->cbb, ins);
11937                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11938                         cfg->cbb->has_array_access = TRUE;
11939                         ip ++;
11940                         *sp++ = ins;
11941                         break;
11942                 case CEE_LDELEMA:
11943                         CHECK_STACK (2);
11944                         sp -= 2;
11945                         CHECK_OPSIZE (5);
11946                         if (sp [0]->type != STACK_OBJ)
11947                                 UNVERIFIED;
11948
11949                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11950
11951                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11952                         CHECK_TYPELOAD (klass);
11953                         /* we need to make sure that this array is exactly the type it needs
11954                          * to be for correctness. the wrappers are lax with their usage
11955                          * so we need to ignore them here
11956                          */
11957                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
11958                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11959                                 mini_emit_check_array_type (cfg, sp [0], array_class);
11960                                 CHECK_TYPELOAD (array_class);
11961                         }
11962
11963                         readonly = FALSE;
11964                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11965                         *sp++ = ins;
11966                         ip += 5;
11967                         break;
11968                 case CEE_LDELEM:
11969                 case CEE_LDELEM_I1:
11970                 case CEE_LDELEM_U1:
11971                 case CEE_LDELEM_I2:
11972                 case CEE_LDELEM_U2:
11973                 case CEE_LDELEM_I4:
11974                 case CEE_LDELEM_U4:
11975                 case CEE_LDELEM_I8:
11976                 case CEE_LDELEM_I:
11977                 case CEE_LDELEM_R4:
11978                 case CEE_LDELEM_R8:
11979                 case CEE_LDELEM_REF: {
11980                         MonoInst *addr;
11981
11982                         CHECK_STACK (2);
11983                         sp -= 2;
11984
11985                         if (*ip == CEE_LDELEM) {
11986                                 CHECK_OPSIZE (5);
11987                                 token = read32 (ip + 1);
11988                                 klass = mini_get_class (method, token, generic_context);
11989                                 CHECK_TYPELOAD (klass);
11990                                 mono_class_init (klass);
11991                         }
11992                         else
11993                                 klass = array_access_to_klass (*ip);
11994
11995                         if (sp [0]->type != STACK_OBJ)
11996                                 UNVERIFIED;
11997
11998                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11999
12000                         if (mini_is_gsharedvt_variable_klass (klass)) {
12001                                 // FIXME-VT: OP_ICONST optimization
12002                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
12003                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
12004                                 ins->opcode = OP_LOADV_MEMBASE;
12005                         } else if (sp [1]->opcode == OP_ICONST) {
12006                                 int array_reg = sp [0]->dreg;
12007                                 int index_reg = sp [1]->dreg;
12008                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
12009
12010                                 if (SIZEOF_REGISTER == 8 && COMPILE_LLVM (cfg))
12011                                         MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, index_reg);
12012
12013                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
12014                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
12015                         } else {
12016                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
12017                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
12018                         }
12019                         *sp++ = ins;
12020                         if (*ip == CEE_LDELEM)
12021                                 ip += 5;
12022                         else
12023                                 ++ip;
12024                         break;
12025                 }
12026                 case CEE_STELEM_I:
12027                 case CEE_STELEM_I1:
12028                 case CEE_STELEM_I2:
12029                 case CEE_STELEM_I4:
12030                 case CEE_STELEM_I8:
12031                 case CEE_STELEM_R4:
12032                 case CEE_STELEM_R8:
12033                 case CEE_STELEM_REF:
12034                 case CEE_STELEM: {
12035                         CHECK_STACK (3);
12036                         sp -= 3;
12037
12038                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
12039
12040                         if (*ip == CEE_STELEM) {
12041                                 CHECK_OPSIZE (5);
12042                                 token = read32 (ip + 1);
12043                                 klass = mini_get_class (method, token, generic_context);
12044                                 CHECK_TYPELOAD (klass);
12045                                 mono_class_init (klass);
12046                         }
12047                         else
12048                                 klass = array_access_to_klass (*ip);
12049
12050                         if (sp [0]->type != STACK_OBJ)
12051                                 UNVERIFIED;
12052
12053                         emit_array_store (cfg, klass, sp, TRUE);
12054
12055                         if (*ip == CEE_STELEM)
12056                                 ip += 5;
12057                         else
12058                                 ++ip;
12059                         inline_costs += 1;
12060                         break;
12061                 }
12062                 case CEE_CKFINITE: {
12063                         CHECK_STACK (1);
12064                         --sp;
12065
12066                         if (cfg->llvm_only) {
12067                                 MonoInst *iargs [1];
12068
12069                                 iargs [0] = sp [0];
12070                                 *sp++ = mono_emit_jit_icall (cfg, mono_ckfinite, iargs);
12071                         } else  {
12072                                 MONO_INST_NEW (cfg, ins, OP_CKFINITE);
12073                                 ins->sreg1 = sp [0]->dreg;
12074                                 ins->dreg = alloc_freg (cfg);
12075                                 ins->type = STACK_R8;
12076                                 MONO_ADD_INS (cfg->cbb, ins);
12077
12078                                 *sp++ = mono_decompose_opcode (cfg, ins);
12079                         }
12080
12081                         ++ip;
12082                         break;
12083                 }
12084                 case CEE_REFANYVAL: {
12085                         MonoInst *src_var, *src;
12086
12087                         int klass_reg = alloc_preg (cfg);
12088                         int dreg = alloc_preg (cfg);
12089
12090                         GSHAREDVT_FAILURE (*ip);
12091
12092                         CHECK_STACK (1);
12093                         MONO_INST_NEW (cfg, ins, *ip);
12094                         --sp;
12095                         CHECK_OPSIZE (5);
12096                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
12097                         CHECK_TYPELOAD (klass);
12098
12099                         context_used = mini_class_check_context_used (cfg, klass);
12100
12101                         // FIXME:
12102                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12103                         if (!src_var)
12104                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
12105                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
12106                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass));
12107
12108                         if (context_used) {
12109                                 MonoInst *klass_ins;
12110
12111                                 klass_ins = emit_get_rgctx_klass (cfg, context_used,
12112                                                 klass, MONO_RGCTX_INFO_KLASS);
12113
12114                                 // FIXME:
12115                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
12116                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
12117                         } else {
12118                                 mini_emit_class_check (cfg, klass_reg, klass);
12119                         }
12120                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value));
12121                         ins->type = STACK_MP;
12122                         ins->klass = klass;
12123                         *sp++ = ins;
12124                         ip += 5;
12125                         break;
12126                 }
12127                 case CEE_MKREFANY: {
12128                         MonoInst *loc, *addr;
12129
12130                         GSHAREDVT_FAILURE (*ip);
12131
12132                         CHECK_STACK (1);
12133                         MONO_INST_NEW (cfg, ins, *ip);
12134                         --sp;
12135                         CHECK_OPSIZE (5);
12136                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
12137                         CHECK_TYPELOAD (klass);
12138
12139                         context_used = mini_class_check_context_used (cfg, klass);
12140
12141                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
12142                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
12143
12144                         if (context_used) {
12145                                 MonoInst *const_ins;
12146                                 int type_reg = alloc_preg (cfg);
12147
12148                                 const_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
12149                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
12150                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
12151                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
12152                         } else if (cfg->compile_aot) {
12153                                 int const_reg = alloc_preg (cfg);
12154                                 int type_reg = alloc_preg (cfg);
12155
12156                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
12157                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
12158                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
12159                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
12160                         } else {
12161                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), &klass->byval_arg);
12162                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), klass);
12163                         }
12164                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
12165
12166                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
12167                         ins->type = STACK_VTYPE;
12168                         ins->klass = mono_defaults.typed_reference_class;
12169                         *sp++ = ins;
12170                         ip += 5;
12171                         break;
12172                 }
12173                 case CEE_LDTOKEN: {
12174                         gpointer handle;
12175                         MonoClass *handle_class;
12176
12177                         CHECK_STACK_OVF (1);
12178
12179                         CHECK_OPSIZE (5);
12180                         n = read32 (ip + 1);
12181
12182                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
12183                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
12184                                 handle = mono_method_get_wrapper_data (method, n);
12185                                 handle_class = (MonoClass *)mono_method_get_wrapper_data (method, n + 1);
12186                                 if (handle_class == mono_defaults.typehandle_class)
12187                                         handle = &((MonoClass*)handle)->byval_arg;
12188                         }
12189                         else {
12190                                 handle = mono_ldtoken_checked (image, n, &handle_class, generic_context, &cfg->error);
12191                                 CHECK_CFG_ERROR;
12192                         }
12193                         if (!handle)
12194                                 LOAD_ERROR;
12195                         mono_class_init (handle_class);
12196                         if (cfg->gshared) {
12197                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
12198                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
12199                                         /* This case handles ldtoken
12200                                            of an open type, like for
12201                                            typeof(Gen<>). */
12202                                         context_used = 0;
12203                                 } else if (handle_class == mono_defaults.typehandle_class) {
12204                                         context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type ((MonoType *)handle));
12205                                 } else if (handle_class == mono_defaults.fieldhandle_class)
12206                                         context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
12207                                 else if (handle_class == mono_defaults.methodhandle_class)
12208                                         context_used = mini_method_check_context_used (cfg, (MonoMethod *)handle);
12209                                 else
12210                                         g_assert_not_reached ();
12211                         }
12212
12213                         if ((cfg->opt & MONO_OPT_SHARED) &&
12214                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
12215                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
12216                                 MonoInst *addr, *vtvar, *iargs [3];
12217                                 int method_context_used;
12218
12219                                 method_context_used = mini_method_check_context_used (cfg, method);
12220
12221                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
12222
12223                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
12224                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
12225                                 if (method_context_used) {
12226                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
12227                                                 method, MONO_RGCTX_INFO_METHOD);
12228                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
12229                                 } else {
12230                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
12231                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
12232                                 }
12233                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12234
12235                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
12236
12237                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12238                         } else {
12239                                 if ((ip + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 5) && 
12240                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
12241                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
12242                                         (cmethod->klass == mono_defaults.systemtype_class) &&
12243                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
12244                                         MonoClass *tclass = mono_class_from_mono_type ((MonoType *)handle);
12245
12246                                         mono_class_init (tclass);
12247                                         if (context_used) {
12248                                                 ins = emit_get_rgctx_klass (cfg, context_used,
12249                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
12250                                         } else if (cfg->compile_aot) {
12251                                                 if (method->wrapper_type) {
12252                                                         mono_error_init (&error); //got to do it since there are multiple conditionals below
12253                                                         if (mono_class_get_checked (tclass->image, tclass->type_token, &error) == tclass && !generic_context) {
12254                                                                 /* Special case for static synchronized wrappers */
12255                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
12256                                                         } else {
12257                                                                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
12258                                                                 /* FIXME: n is not a normal token */
12259                                                                 DISABLE_AOT (cfg);
12260                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12261                                                         }
12262                                                 } else {
12263                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
12264                                                 }
12265                                         } else {
12266                                                 MonoReflectionType *rt = mono_type_get_object_checked (cfg->domain, (MonoType *)handle, &cfg->error);
12267                                                 CHECK_CFG_ERROR;
12268                                                 EMIT_NEW_PCONST (cfg, ins, rt);
12269                                         }
12270                                         ins->type = STACK_OBJ;
12271                                         ins->klass = cmethod->klass;
12272                                         ip += 5;
12273                                 } else {
12274                                         MonoInst *addr, *vtvar;
12275
12276                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
12277
12278                                         if (context_used) {
12279                                                 if (handle_class == mono_defaults.typehandle_class) {
12280                                                         ins = emit_get_rgctx_klass (cfg, context_used,
12281                                                                         mono_class_from_mono_type ((MonoType *)handle),
12282                                                                         MONO_RGCTX_INFO_TYPE);
12283                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
12284                                                         ins = emit_get_rgctx_method (cfg, context_used,
12285                                                                         (MonoMethod *)handle, MONO_RGCTX_INFO_METHOD);
12286                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
12287                                                         ins = emit_get_rgctx_field (cfg, context_used,
12288                                                                         (MonoClassField *)handle, MONO_RGCTX_INFO_CLASS_FIELD);
12289                                                 } else {
12290                                                         g_assert_not_reached ();
12291                                                 }
12292                                         } else if (cfg->compile_aot) {
12293                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n, generic_context);
12294                                         } else {
12295                                                 EMIT_NEW_PCONST (cfg, ins, handle);
12296                                         }
12297                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12298                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
12299                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12300                                 }
12301                         }
12302
12303                         *sp++ = ins;
12304                         ip += 5;
12305                         break;
12306                 }
12307                 case CEE_THROW:
12308                         CHECK_STACK (1);
12309                         MONO_INST_NEW (cfg, ins, OP_THROW);
12310                         --sp;
12311                         ins->sreg1 = sp [0]->dreg;
12312                         ip++;
12313                         cfg->cbb->out_of_line = TRUE;
12314                         MONO_ADD_INS (cfg->cbb, ins);
12315                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
12316                         MONO_ADD_INS (cfg->cbb, ins);
12317                         sp = stack_start;
12318                         
12319                         link_bblock (cfg, cfg->cbb, end_bblock);
12320                         start_new_bblock = 1;
12321                         /* This can complicate code generation for llvm since the return value might not be defined */
12322                         if (COMPILE_LLVM (cfg))
12323                                 INLINE_FAILURE ("throw");
12324                         break;
12325                 case CEE_ENDFINALLY:
12326                         /* mono_save_seq_point_info () depends on this */
12327                         if (sp != stack_start)
12328                                 emit_seq_point (cfg, method, ip, FALSE, FALSE);
12329                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
12330                         MONO_ADD_INS (cfg->cbb, ins);
12331                         ip++;
12332                         start_new_bblock = 1;
12333
12334                         /*
12335                          * Control will leave the method so empty the stack, otherwise
12336                          * the next basic block will start with a nonempty stack.
12337                          */
12338                         while (sp != stack_start) {
12339                                 sp--;
12340                         }
12341                         break;
12342                 case CEE_LEAVE:
12343                 case CEE_LEAVE_S: {
12344                         GList *handlers;
12345
12346                         if (*ip == CEE_LEAVE) {
12347                                 CHECK_OPSIZE (5);
12348                                 target = ip + 5 + (gint32)read32(ip + 1);
12349                         } else {
12350                                 CHECK_OPSIZE (2);
12351                                 target = ip + 2 + (signed char)(ip [1]);
12352                         }
12353
12354                         /* empty the stack */
12355                         while (sp != stack_start) {
12356                                 sp--;
12357                         }
12358
12359                         /* 
12360                          * If this leave statement is in a catch block, check for a
12361                          * pending exception, and rethrow it if necessary.
12362                          * We avoid doing this in runtime invoke wrappers, since those are called
12363                          * by native code which excepts the wrapper to catch all exceptions.
12364                          */
12365                         for (i = 0; i < header->num_clauses; ++i) {
12366                                 MonoExceptionClause *clause = &header->clauses [i];
12367
12368                                 /* 
12369                                  * Use <= in the final comparison to handle clauses with multiple
12370                                  * leave statements, like in bug #78024.
12371                                  * The ordering of the exception clauses guarantees that we find the
12372                                  * innermost clause.
12373                                  */
12374                                 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) {
12375                                         MonoInst *exc_ins;
12376                                         MonoBasicBlock *dont_throw;
12377
12378                                         /*
12379                                           MonoInst *load;
12380
12381                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
12382                                         */
12383
12384                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
12385
12386                                         NEW_BBLOCK (cfg, dont_throw);
12387
12388                                         /*
12389                                          * Currently, we always rethrow the abort exception, despite the 
12390                                          * fact that this is not correct. See thread6.cs for an example. 
12391                                          * But propagating the abort exception is more important than 
12392                                          * getting the sematics right.
12393                                          */
12394                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
12395                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
12396                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
12397
12398                                         MONO_START_BB (cfg, dont_throw);
12399                                 }
12400                         }
12401
12402 #ifdef ENABLE_LLVM
12403                         cfg->cbb->try_end = (intptr_t)(ip - header->code);
12404 #endif
12405
12406                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
12407                                 GList *tmp;
12408                                 MonoExceptionClause *clause;
12409
12410                                 for (tmp = handlers; tmp; tmp = tmp->next) {
12411                                         clause = (MonoExceptionClause *)tmp->data;
12412                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
12413                                         g_assert (tblock);
12414                                         link_bblock (cfg, cfg->cbb, tblock);
12415                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
12416                                         ins->inst_target_bb = tblock;
12417                                         ins->inst_eh_block = clause;
12418                                         MONO_ADD_INS (cfg->cbb, ins);
12419                                         cfg->cbb->has_call_handler = 1;
12420                                         if (COMPILE_LLVM (cfg)) {
12421                                                 MonoBasicBlock *target_bb;
12422
12423                                                 /* 
12424                                                  * Link the finally bblock with the target, since it will
12425                                                  * conceptually branch there.
12426                                                  */
12427                                                 GET_BBLOCK (cfg, tblock, cfg->cil_start + clause->handler_offset + clause->handler_len - 1);
12428                                                 GET_BBLOCK (cfg, target_bb, target);
12429                                                 link_bblock (cfg, tblock, target_bb);
12430                                         }
12431                                 }
12432                                 g_list_free (handlers);
12433                         } 
12434
12435                         MONO_INST_NEW (cfg, ins, OP_BR);
12436                         MONO_ADD_INS (cfg->cbb, ins);
12437                         GET_BBLOCK (cfg, tblock, target);
12438                         link_bblock (cfg, cfg->cbb, tblock);
12439                         ins->inst_target_bb = tblock;
12440
12441                         start_new_bblock = 1;
12442
12443                         if (*ip == CEE_LEAVE)
12444                                 ip += 5;
12445                         else
12446                                 ip += 2;
12447
12448                         break;
12449                 }
12450
12451                         /*
12452                          * Mono specific opcodes
12453                          */
12454                 case MONO_CUSTOM_PREFIX: {
12455
12456                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
12457
12458                         CHECK_OPSIZE (2);
12459                         switch (ip [1]) {
12460                         case CEE_MONO_ICALL: {
12461                                 gpointer func;
12462                                 MonoJitICallInfo *info;
12463
12464                                 token = read32 (ip + 2);
12465                                 func = mono_method_get_wrapper_data (method, token);
12466                                 info = mono_find_jit_icall_by_addr (func);
12467                                 if (!info)
12468                                         g_error ("Could not find icall address in wrapper %s", mono_method_full_name (method, 1));
12469                                 g_assert (info);
12470
12471                                 CHECK_STACK (info->sig->param_count);
12472                                 sp -= info->sig->param_count;
12473
12474                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
12475                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
12476                                         *sp++ = ins;
12477
12478                                 ip += 6;
12479                                 inline_costs += 10 * num_calls++;
12480
12481                                 break;
12482                         }
12483                         case CEE_MONO_LDPTR_CARD_TABLE:
12484                         case CEE_MONO_LDPTR_NURSERY_START:
12485                         case CEE_MONO_LDPTR_NURSERY_BITS:
12486                         case CEE_MONO_LDPTR_INT_REQ_FLAG: {
12487                                 CHECK_STACK_OVF (1);
12488
12489                                 switch (ip [1]) {
12490                                         case CEE_MONO_LDPTR_CARD_TABLE:
12491                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
12492                                                 break;
12493                                         case CEE_MONO_LDPTR_NURSERY_START:
12494                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_START, NULL);
12495                                                 break;
12496                                         case CEE_MONO_LDPTR_NURSERY_BITS:
12497                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_BITS, NULL);
12498                                                 break;
12499                                         case CEE_MONO_LDPTR_INT_REQ_FLAG:
12500                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
12501                                                 break;
12502                                 }
12503
12504                                 *sp++ = ins;
12505                                 ip += 2;
12506                                 inline_costs += 10 * num_calls++;
12507                                 break;
12508                         }
12509                         case CEE_MONO_LDPTR: {
12510                                 gpointer ptr;
12511
12512                                 CHECK_STACK_OVF (1);
12513                                 CHECK_OPSIZE (6);
12514                                 token = read32 (ip + 2);
12515
12516                                 ptr = mono_method_get_wrapper_data (method, token);
12517                                 EMIT_NEW_PCONST (cfg, ins, ptr);
12518                                 *sp++ = ins;
12519                                 ip += 6;
12520                                 inline_costs += 10 * num_calls++;
12521                                 /* Can't embed random pointers into AOT code */
12522                                 DISABLE_AOT (cfg);
12523                                 break;
12524                         }
12525                         case CEE_MONO_JIT_ICALL_ADDR: {
12526                                 MonoJitICallInfo *callinfo;
12527                                 gpointer ptr;
12528
12529                                 CHECK_STACK_OVF (1);
12530                                 CHECK_OPSIZE (6);
12531                                 token = read32 (ip + 2);
12532
12533                                 ptr = mono_method_get_wrapper_data (method, token);
12534                                 callinfo = mono_find_jit_icall_by_addr (ptr);
12535                                 g_assert (callinfo);
12536                                 EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
12537                                 *sp++ = ins;
12538                                 ip += 6;
12539                                 inline_costs += 10 * num_calls++;
12540                                 break;
12541                         }
12542                         case CEE_MONO_ICALL_ADDR: {
12543                                 MonoMethod *cmethod;
12544                                 gpointer ptr;
12545
12546                                 CHECK_STACK_OVF (1);
12547                                 CHECK_OPSIZE (6);
12548                                 token = read32 (ip + 2);
12549
12550                                 cmethod = (MonoMethod *)mono_method_get_wrapper_data (method, token);
12551
12552                                 if (cfg->compile_aot) {
12553                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
12554                                 } else {
12555                                         ptr = mono_lookup_internal_call (cmethod);
12556                                         g_assert (ptr);
12557                                         EMIT_NEW_PCONST (cfg, ins, ptr);
12558                                 }
12559                                 *sp++ = ins;
12560                                 ip += 6;
12561                                 break;
12562                         }
12563                         case CEE_MONO_VTADDR: {
12564                                 MonoInst *src_var, *src;
12565
12566                                 CHECK_STACK (1);
12567                                 --sp;
12568
12569                                 // FIXME:
12570                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12571                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
12572                                 *sp++ = src;
12573                                 ip += 2;
12574                                 break;
12575                         }
12576                         case CEE_MONO_NEWOBJ: {
12577                                 MonoInst *iargs [2];
12578
12579                                 CHECK_STACK_OVF (1);
12580                                 CHECK_OPSIZE (6);
12581                                 token = read32 (ip + 2);
12582                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12583                                 mono_class_init (klass);
12584                                 NEW_DOMAINCONST (cfg, iargs [0]);
12585                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
12586                                 NEW_CLASSCONST (cfg, iargs [1], klass);
12587                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
12588                                 *sp++ = mono_emit_jit_icall (cfg, ves_icall_object_new, iargs);
12589                                 ip += 6;
12590                                 inline_costs += 10 * num_calls++;
12591                                 break;
12592                         }
12593                         case CEE_MONO_OBJADDR:
12594                                 CHECK_STACK (1);
12595                                 --sp;
12596                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
12597                                 ins->dreg = alloc_ireg_mp (cfg);
12598                                 ins->sreg1 = sp [0]->dreg;
12599                                 ins->type = STACK_MP;
12600                                 MONO_ADD_INS (cfg->cbb, ins);
12601                                 *sp++ = ins;
12602                                 ip += 2;
12603                                 break;
12604                         case CEE_MONO_LDNATIVEOBJ:
12605                                 /*
12606                                  * Similar to LDOBJ, but instead load the unmanaged 
12607                                  * representation of the vtype to the stack.
12608                                  */
12609                                 CHECK_STACK (1);
12610                                 CHECK_OPSIZE (6);
12611                                 --sp;
12612                                 token = read32 (ip + 2);
12613                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12614                                 g_assert (klass->valuetype);
12615                                 mono_class_init (klass);
12616
12617                                 {
12618                                         MonoInst *src, *dest, *temp;
12619
12620                                         src = sp [0];
12621                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
12622                                         temp->backend.is_pinvoke = 1;
12623                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
12624                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
12625
12626                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
12627                                         dest->type = STACK_VTYPE;
12628                                         dest->klass = klass;
12629
12630                                         *sp ++ = dest;
12631                                         ip += 6;
12632                                 }
12633                                 break;
12634                         case CEE_MONO_RETOBJ: {
12635                                 /*
12636                                  * Same as RET, but return the native representation of a vtype
12637                                  * to the caller.
12638                                  */
12639                                 g_assert (cfg->ret);
12640                                 g_assert (mono_method_signature (method)->pinvoke); 
12641                                 CHECK_STACK (1);
12642                                 --sp;
12643                                 
12644                                 CHECK_OPSIZE (6);
12645                                 token = read32 (ip + 2);    
12646                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12647
12648                                 if (!cfg->vret_addr) {
12649                                         g_assert (cfg->ret_var_is_local);
12650
12651                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
12652                                 } else {
12653                                         EMIT_NEW_RETLOADA (cfg, ins);
12654                                 }
12655                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
12656                                 
12657                                 if (sp != stack_start)
12658                                         UNVERIFIED;
12659                                 
12660                                 MONO_INST_NEW (cfg, ins, OP_BR);
12661                                 ins->inst_target_bb = end_bblock;
12662                                 MONO_ADD_INS (cfg->cbb, ins);
12663                                 link_bblock (cfg, cfg->cbb, end_bblock);
12664                                 start_new_bblock = 1;
12665                                 ip += 6;
12666                                 break;
12667                         }
12668                         case CEE_MONO_CISINST:
12669                         case CEE_MONO_CCASTCLASS: {
12670                                 int token;
12671                                 CHECK_STACK (1);
12672                                 --sp;
12673                                 CHECK_OPSIZE (6);
12674                                 token = read32 (ip + 2);
12675                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12676                                 if (ip [1] == CEE_MONO_CISINST)
12677                                         ins = handle_cisinst (cfg, klass, sp [0]);
12678                                 else
12679                                         ins = handle_ccastclass (cfg, klass, sp [0]);
12680                                 *sp++ = ins;
12681                                 ip += 6;
12682                                 break;
12683                         }
12684                         case CEE_MONO_SAVE_LMF:
12685                         case CEE_MONO_RESTORE_LMF:
12686                                 ip += 2;
12687                                 break;
12688                         case CEE_MONO_CLASSCONST:
12689                                 CHECK_STACK_OVF (1);
12690                                 CHECK_OPSIZE (6);
12691                                 token = read32 (ip + 2);
12692                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
12693                                 *sp++ = ins;
12694                                 ip += 6;
12695                                 inline_costs += 10 * num_calls++;
12696                                 break;
12697                         case CEE_MONO_NOT_TAKEN:
12698                                 cfg->cbb->out_of_line = TRUE;
12699                                 ip += 2;
12700                                 break;
12701                         case CEE_MONO_TLS: {
12702                                 MonoTlsKey key;
12703
12704                                 CHECK_STACK_OVF (1);
12705                                 CHECK_OPSIZE (6);
12706                                 key = (MonoTlsKey)read32 (ip + 2);
12707                                 g_assert (key < TLS_KEY_NUM);
12708
12709                                 ins = mono_create_tls_get (cfg, key);
12710                                 if (!ins) {
12711                                         if (cfg->compile_aot) {
12712                                                 DISABLE_AOT (cfg);
12713                                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
12714                                                 ins->dreg = alloc_preg (cfg);
12715                                                 ins->type = STACK_PTR;
12716                                         } else {
12717                                                 g_assert_not_reached ();
12718                                         }
12719                                 }
12720                                 ins->type = STACK_PTR;
12721                                 MONO_ADD_INS (cfg->cbb, ins);
12722                                 *sp++ = ins;
12723                                 ip += 6;
12724                                 break;
12725                         }
12726                         case CEE_MONO_DYN_CALL: {
12727                                 MonoCallInst *call;
12728
12729                                 /* It would be easier to call a trampoline, but that would put an
12730                                  * extra frame on the stack, confusing exception handling. So
12731                                  * implement it inline using an opcode for now.
12732                                  */
12733
12734                                 if (!cfg->dyn_call_var) {
12735                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12736                                         /* prevent it from being register allocated */
12737                                         cfg->dyn_call_var->flags |= MONO_INST_VOLATILE;
12738                                 }
12739
12740                                 /* Has to use a call inst since it local regalloc expects it */
12741                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
12742                                 ins = (MonoInst*)call;
12743                                 sp -= 2;
12744                                 ins->sreg1 = sp [0]->dreg;
12745                                 ins->sreg2 = sp [1]->dreg;
12746                                 MONO_ADD_INS (cfg->cbb, ins);
12747
12748                                 cfg->param_area = MAX (cfg->param_area, cfg->backend->dyn_call_param_area);
12749
12750                                 ip += 2;
12751                                 inline_costs += 10 * num_calls++;
12752
12753                                 break;
12754                         }
12755                         case CEE_MONO_MEMORY_BARRIER: {
12756                                 CHECK_OPSIZE (6);
12757                                 emit_memory_barrier (cfg, (int)read32 (ip + 2));
12758                                 ip += 6;
12759                                 break;
12760                         }
12761                         case CEE_MONO_JIT_ATTACH: {
12762                                 MonoInst *args [16], *domain_ins;
12763                                 MonoInst *ad_ins, *jit_tls_ins;
12764                                 MonoBasicBlock *next_bb = NULL, *call_bb = NULL;
12765
12766                                 cfg->attach_cookie = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12767                                 cfg->attach_dummy = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12768
12769                                 if (mono_threads_is_coop_enabled ()) {
12770                                         /* AOT code is only used in the root domain */
12771                                         EMIT_NEW_PCONST (cfg, args [0], cfg->compile_aot ? NULL : cfg->domain);
12772                                         EMIT_NEW_VARLOADA (cfg, args [1], cfg->attach_dummy, cfg->attach_dummy->inst_vtype);
12773                                         ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
12774                                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->attach_cookie->dreg, ins->dreg);
12775                                 } else {
12776                                         EMIT_NEW_PCONST (cfg, ins, NULL);
12777                                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->attach_cookie->dreg, ins->dreg);
12778
12779                                         ad_ins = mono_get_domain_intrinsic (cfg);
12780                                         jit_tls_ins = mono_get_jit_tls_intrinsic (cfg);
12781
12782                                         if (cfg->backend->have_tls_get && ad_ins && jit_tls_ins) {
12783                                                 NEW_BBLOCK (cfg, next_bb);
12784                                                 NEW_BBLOCK (cfg, call_bb);
12785
12786                                                 if (cfg->compile_aot) {
12787                                                         /* AOT code is only used in the root domain */
12788                                                         EMIT_NEW_PCONST (cfg, domain_ins, NULL);
12789                                                 } else {
12790                                                         EMIT_NEW_PCONST (cfg, domain_ins, cfg->domain);
12791                                                 }
12792                                                 MONO_ADD_INS (cfg->cbb, ad_ins);
12793                                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, ad_ins->dreg, domain_ins->dreg);
12794                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, call_bb);
12795
12796                                                 MONO_ADD_INS (cfg->cbb, jit_tls_ins);
12797                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, jit_tls_ins->dreg, 0);
12798                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, call_bb);
12799
12800                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, next_bb);
12801                                                 MONO_START_BB (cfg, call_bb);
12802                                         }
12803
12804                                         /* AOT code is only used in the root domain */
12805                                         EMIT_NEW_PCONST (cfg, args [0], cfg->compile_aot ? NULL : cfg->domain);
12806                                         EMIT_NEW_PCONST (cfg, args [1], NULL);
12807                                         ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
12808                                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->attach_cookie->dreg, ins->dreg);
12809
12810                                         if (next_bb)
12811                                                 MONO_START_BB (cfg, next_bb);
12812                                 }
12813
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->attach_cookie->dreg);
12823                                 EMIT_NEW_VARLOADA (cfg, args [1], cfg->attach_dummy, cfg->attach_dummy->inst_vtype);
12824                                 mono_emit_jit_icall (cfg, mono_jit_thread_detach, args);
12825                                 ip += 2;
12826                                 break;
12827                         }
12828                         case CEE_MONO_CALLI_EXTRA_ARG: {
12829                                 MonoInst *addr;
12830                                 MonoMethodSignature *fsig;
12831                                 MonoInst *arg;
12832
12833                                 /*
12834                                  * This is the same as CEE_CALLI, but passes an additional argument
12835                                  * to the called method in llvmonly mode.
12836                                  * This is only used by delegate invoke wrappers to call the
12837                                  * actual delegate method.
12838                                  */
12839                                 g_assert (method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE);
12840
12841                                 CHECK_OPSIZE (6);
12842                                 token = read32 (ip + 2);
12843
12844                                 ins = NULL;
12845
12846                                 cmethod = NULL;
12847                                 CHECK_STACK (1);
12848                                 --sp;
12849                                 addr = *sp;
12850                                 fsig = mini_get_signature (method, token, generic_context);
12851
12852                                 if (cfg->llvm_only)
12853                                         cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, fsig);
12854
12855                                 n = fsig->param_count + fsig->hasthis + 1;
12856
12857                                 CHECK_STACK (n);
12858
12859                                 sp -= n;
12860                                 arg = sp [n - 1];
12861
12862                                 if (cfg->llvm_only) {
12863                                         /*
12864                                          * The lowest bit of 'arg' determines whenever the callee uses the gsharedvt
12865                                          * cconv. This is set by mono_init_delegate ().
12866                                          */
12867                                         if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig)) {
12868                                                 MonoInst *callee = addr;
12869                                                 MonoInst *call, *localloc_ins;
12870                                                 MonoBasicBlock *is_gsharedvt_bb, *end_bb;
12871                                                 int low_bit_reg = alloc_preg (cfg);
12872
12873                                                 NEW_BBLOCK (cfg, is_gsharedvt_bb);
12874                                                 NEW_BBLOCK (cfg, end_bb);
12875
12876                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, low_bit_reg, arg->dreg, 1);
12877                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_bit_reg, 0);
12878                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_gsharedvt_bb);
12879
12880                                                 /* Normal case: callee uses a normal cconv, have to add an out wrapper */
12881                                                 addr = emit_get_rgctx_sig (cfg, context_used,
12882                                                                                                    fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
12883                                                 /*
12884                                                  * ADDR points to a gsharedvt-out wrapper, have to pass <callee, arg> as an extra arg.
12885                                                  */
12886                                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
12887                                                 ins->dreg = alloc_preg (cfg);
12888                                                 ins->inst_imm = 2 * SIZEOF_VOID_P;
12889                                                 MONO_ADD_INS (cfg->cbb, ins);
12890                                                 localloc_ins = ins;
12891                                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12892                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, 0, callee->dreg);
12893                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, SIZEOF_VOID_P, arg->dreg);
12894
12895                                                 call = emit_extra_arg_calli (cfg, fsig, sp, localloc_ins->dreg, addr);
12896                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12897
12898                                                 /* Gsharedvt case: callee uses a gsharedvt cconv, no conversion is needed */
12899                                                 MONO_START_BB (cfg, is_gsharedvt_bb);
12900                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PXOR_IMM, arg->dreg, arg->dreg, 1);
12901                                                 ins = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
12902                                                 ins->dreg = call->dreg;
12903
12904                                                 MONO_START_BB (cfg, end_bb);
12905                                         } else {
12906                                                 /* Caller uses a normal calling conv */
12907
12908                                                 MonoInst *callee = addr;
12909                                                 MonoInst *call, *localloc_ins;
12910                                                 MonoBasicBlock *is_gsharedvt_bb, *end_bb;
12911                                                 int low_bit_reg = alloc_preg (cfg);
12912
12913                                                 NEW_BBLOCK (cfg, is_gsharedvt_bb);
12914                                                 NEW_BBLOCK (cfg, end_bb);
12915
12916                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, low_bit_reg, arg->dreg, 1);
12917                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_bit_reg, 0);
12918                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_gsharedvt_bb);
12919
12920                                                 /* Normal case: callee uses a normal cconv, no conversion is needed */
12921                                                 call = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
12922                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12923                                                 /* Gsharedvt case: callee uses a gsharedvt cconv, have to add an in wrapper */
12924                                                 MONO_START_BB (cfg, is_gsharedvt_bb);
12925                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PXOR_IMM, arg->dreg, arg->dreg, 1);
12926                                                 NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER, fsig);
12927                                                 MONO_ADD_INS (cfg->cbb, addr);
12928                                                 /*
12929                                                  * ADDR points to a gsharedvt-in wrapper, have to pass <callee, arg> as an extra arg.
12930                                                  */
12931                                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
12932                                                 ins->dreg = alloc_preg (cfg);
12933                                                 ins->inst_imm = 2 * SIZEOF_VOID_P;
12934                                                 MONO_ADD_INS (cfg->cbb, ins);
12935                                                 localloc_ins = ins;
12936                                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12937                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, 0, callee->dreg);
12938                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, SIZEOF_VOID_P, arg->dreg);
12939
12940                                                 ins = emit_extra_arg_calli (cfg, fsig, sp, localloc_ins->dreg, addr);
12941                                                 ins->dreg = call->dreg;
12942                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12943
12944                                                 MONO_START_BB (cfg, end_bb);
12945                                         }
12946                                 } else {
12947                                         /* Same as CEE_CALLI */
12948                                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
12949                                                 /*
12950                                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
12951                                                  */
12952                                                 MonoInst *callee = addr;
12953
12954                                                 addr = emit_get_rgctx_sig (cfg, context_used,
12955                                                                                                    fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
12956                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
12957                                         } else {
12958                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
12959                                         }
12960                                 }
12961
12962                                 if (!MONO_TYPE_IS_VOID (fsig->ret))
12963                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
12964
12965                                 CHECK_CFG_EXCEPTION;
12966
12967                                 ip += 6;
12968                                 ins_flag = 0;
12969                                 constrained_class = NULL;
12970                                 break;
12971                         }
12972                         default:
12973                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
12974                                 break;
12975                         }
12976                         break;
12977                 }
12978
12979                 case CEE_PREFIX1: {
12980                         CHECK_OPSIZE (2);
12981                         switch (ip [1]) {
12982                         case CEE_ARGLIST: {
12983                                 /* somewhat similar to LDTOKEN */
12984                                 MonoInst *addr, *vtvar;
12985                                 CHECK_STACK_OVF (1);
12986                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
12987
12988                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12989                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
12990
12991                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12992                                 ins->type = STACK_VTYPE;
12993                                 ins->klass = mono_defaults.argumenthandle_class;
12994                                 *sp++ = ins;
12995                                 ip += 2;
12996                                 break;
12997                         }
12998                         case CEE_CEQ:
12999                         case CEE_CGT:
13000                         case CEE_CGT_UN:
13001                         case CEE_CLT:
13002                         case CEE_CLT_UN: {
13003                                 MonoInst *cmp, *arg1, *arg2;
13004
13005                                 CHECK_STACK (2);
13006                                 sp -= 2;
13007                                 arg1 = sp [0];
13008                                 arg2 = sp [1];
13009
13010                                 /*
13011                                  * The following transforms:
13012                                  *    CEE_CEQ    into OP_CEQ
13013                                  *    CEE_CGT    into OP_CGT
13014                                  *    CEE_CGT_UN into OP_CGT_UN
13015                                  *    CEE_CLT    into OP_CLT
13016                                  *    CEE_CLT_UN into OP_CLT_UN
13017                                  */
13018                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
13019
13020                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
13021                                 cmp->sreg1 = arg1->dreg;
13022                                 cmp->sreg2 = arg2->dreg;
13023                                 type_from_op (cfg, cmp, arg1, arg2);
13024                                 CHECK_TYPE (cmp);
13025                                 add_widen_op (cfg, cmp, &arg1, &arg2);
13026                                 if ((arg1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((arg1->type == STACK_PTR) || (arg1->type == STACK_OBJ) || (arg1->type == STACK_MP))))
13027                                         cmp->opcode = OP_LCOMPARE;
13028                                 else if (arg1->type == STACK_R4)
13029                                         cmp->opcode = OP_RCOMPARE;
13030                                 else if (arg1->type == STACK_R8)
13031                                         cmp->opcode = OP_FCOMPARE;
13032                                 else
13033                                         cmp->opcode = OP_ICOMPARE;
13034                                 MONO_ADD_INS (cfg->cbb, cmp);
13035                                 ins->type = STACK_I4;
13036                                 ins->dreg = alloc_dreg (cfg, (MonoStackType)ins->type);
13037                                 type_from_op (cfg, ins, arg1, arg2);
13038
13039                                 if (cmp->opcode == OP_FCOMPARE || cmp->opcode == OP_RCOMPARE) {
13040                                         /*
13041                                          * The backends expect the fceq opcodes to do the
13042                                          * comparison too.
13043                                          */
13044                                         ins->sreg1 = cmp->sreg1;
13045                                         ins->sreg2 = cmp->sreg2;
13046                                         NULLIFY_INS (cmp);
13047                                 }
13048                                 MONO_ADD_INS (cfg->cbb, ins);
13049                                 *sp++ = ins;
13050                                 ip += 2;
13051                                 break;
13052                         }
13053                         case CEE_LDFTN: {
13054                                 MonoInst *argconst;
13055                                 MonoMethod *cil_method;
13056
13057                                 CHECK_STACK_OVF (1);
13058                                 CHECK_OPSIZE (6);
13059                                 n = read32 (ip + 2);
13060                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
13061                                 CHECK_CFG_ERROR;
13062
13063                                 mono_class_init (cmethod->klass);
13064
13065                                 mono_save_token_info (cfg, image, n, cmethod);
13066
13067                                 context_used = mini_method_check_context_used (cfg, cmethod);
13068
13069                                 cil_method = cmethod;
13070                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
13071                                         METHOD_ACCESS_FAILURE (method, cil_method);
13072
13073                                 if (mono_security_core_clr_enabled ())
13074                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
13075
13076                                 /* 
13077                                  * Optimize the common case of ldftn+delegate creation
13078                                  */
13079                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
13080                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
13081                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
13082                                                 MonoInst *target_ins, *handle_ins;
13083                                                 MonoMethod *invoke;
13084                                                 int invoke_context_used;
13085
13086                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
13087                                                 if (!invoke || !mono_method_signature (invoke))
13088                                                         LOAD_ERROR;
13089
13090                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
13091
13092                                                 target_ins = sp [-1];
13093
13094                                                 if (mono_security_core_clr_enabled ())
13095                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
13096
13097                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
13098                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
13099                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
13100                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
13101                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
13102                                                         }
13103                                                 }
13104
13105                                                 /* FIXME: SGEN support */
13106                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
13107                                                         ip += 6;
13108                                                         if (cfg->verbose_level > 3)
13109                                                                 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));
13110                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, FALSE))) {
13111                                                                 sp --;
13112                                                                 *sp = handle_ins;
13113                                                                 CHECK_CFG_EXCEPTION;
13114                                                                 ip += 5;
13115                                                                 sp ++;
13116                                                                 break;
13117                                                         }
13118                                                         ip -= 6;
13119                                                 }
13120                                         }
13121                                 }
13122
13123                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
13124                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
13125                                 *sp++ = ins;
13126                                 
13127                                 ip += 6;
13128                                 inline_costs += 10 * num_calls++;
13129                                 break;
13130                         }
13131                         case CEE_LDVIRTFTN: {
13132                                 MonoInst *args [2];
13133
13134                                 CHECK_STACK (1);
13135                                 CHECK_OPSIZE (6);
13136                                 n = read32 (ip + 2);
13137                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
13138                                 CHECK_CFG_ERROR;
13139
13140                                 mono_class_init (cmethod->klass);
13141  
13142                                 context_used = mini_method_check_context_used (cfg, cmethod);
13143
13144                                 if (mono_security_core_clr_enabled ())
13145                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
13146
13147                                 /*
13148                                  * Optimize the common case of ldvirtftn+delegate creation
13149                                  */
13150                                 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)) {
13151                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
13152                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
13153                                                 MonoInst *target_ins, *handle_ins;
13154                                                 MonoMethod *invoke;
13155                                                 int invoke_context_used;
13156                                                 gboolean is_virtual = cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL;
13157
13158                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
13159                                                 if (!invoke || !mono_method_signature (invoke))
13160                                                         LOAD_ERROR;
13161
13162                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
13163
13164                                                 target_ins = sp [-1];
13165
13166                                                 if (mono_security_core_clr_enabled ())
13167                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
13168
13169                                                 /* FIXME: SGEN support */
13170                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
13171                                                         ip += 6;
13172                                                         if (cfg->verbose_level > 3)
13173                                                                 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));
13174                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, is_virtual))) {
13175                                                                 sp -= 2;
13176                                                                 *sp = handle_ins;
13177                                                                 CHECK_CFG_EXCEPTION;
13178                                                                 ip += 5;
13179                                                                 sp ++;
13180                                                                 break;
13181                                                         }
13182                                                         ip -= 6;
13183                                                 }
13184                                         }
13185                                 }
13186
13187                                 --sp;
13188                                 args [0] = *sp;
13189
13190                                 args [1] = emit_get_rgctx_method (cfg, context_used,
13191                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
13192
13193                                 if (context_used)
13194                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
13195                                 else
13196                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
13197
13198                                 ip += 6;
13199                                 inline_costs += 10 * num_calls++;
13200                                 break;
13201                         }
13202                         case CEE_LDARG:
13203                                 CHECK_STACK_OVF (1);
13204                                 CHECK_OPSIZE (4);
13205                                 n = read16 (ip + 2);
13206                                 CHECK_ARG (n);
13207                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
13208                                 *sp++ = ins;
13209                                 ip += 4;
13210                                 break;
13211                         case CEE_LDARGA:
13212                                 CHECK_STACK_OVF (1);
13213                                 CHECK_OPSIZE (4);
13214                                 n = read16 (ip + 2);
13215                                 CHECK_ARG (n);
13216                                 NEW_ARGLOADA (cfg, ins, n);
13217                                 MONO_ADD_INS (cfg->cbb, ins);
13218                                 *sp++ = ins;
13219                                 ip += 4;
13220                                 break;
13221                         case CEE_STARG:
13222                                 CHECK_STACK (1);
13223                                 --sp;
13224                                 CHECK_OPSIZE (4);
13225                                 n = read16 (ip + 2);
13226                                 CHECK_ARG (n);
13227                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
13228                                         UNVERIFIED;
13229                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
13230                                 ip += 4;
13231                                 break;
13232                         case CEE_LDLOC:
13233                                 CHECK_STACK_OVF (1);
13234                                 CHECK_OPSIZE (4);
13235                                 n = read16 (ip + 2);
13236                                 CHECK_LOCAL (n);
13237                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
13238                                 *sp++ = ins;
13239                                 ip += 4;
13240                                 break;
13241                         case CEE_LDLOCA: {
13242                                 unsigned char *tmp_ip;
13243                                 CHECK_STACK_OVF (1);
13244                                 CHECK_OPSIZE (4);
13245                                 n = read16 (ip + 2);
13246                                 CHECK_LOCAL (n);
13247
13248                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
13249                                         ip = tmp_ip;
13250                                         inline_costs += 1;
13251                                         break;
13252                                 }                       
13253                                 
13254                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
13255                                 *sp++ = ins;
13256                                 ip += 4;
13257                                 break;
13258                         }
13259                         case CEE_STLOC:
13260                                 CHECK_STACK (1);
13261                                 --sp;
13262                                 CHECK_OPSIZE (4);
13263                                 n = read16 (ip + 2);
13264                                 CHECK_LOCAL (n);
13265                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
13266                                         UNVERIFIED;
13267                                 emit_stloc_ir (cfg, sp, header, n);
13268                                 ip += 4;
13269                                 inline_costs += 1;
13270                                 break;
13271                         case CEE_LOCALLOC:
13272                                 CHECK_STACK (1);
13273                                 --sp;
13274                                 if (sp != stack_start) 
13275                                         UNVERIFIED;
13276                                 if (cfg->method != method) 
13277                                         /* 
13278                                          * Inlining this into a loop in a parent could lead to 
13279                                          * stack overflows which is different behavior than the
13280                                          * non-inlined case, thus disable inlining in this case.
13281                                          */
13282                                         INLINE_FAILURE("localloc");
13283
13284                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
13285                                 ins->dreg = alloc_preg (cfg);
13286                                 ins->sreg1 = sp [0]->dreg;
13287                                 ins->type = STACK_PTR;
13288                                 MONO_ADD_INS (cfg->cbb, ins);
13289
13290                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
13291                                 if (init_locals)
13292                                         ins->flags |= MONO_INST_INIT;
13293
13294                                 *sp++ = ins;
13295                                 ip += 2;
13296                                 break;
13297                         case CEE_ENDFILTER: {
13298                                 MonoExceptionClause *clause, *nearest;
13299                                 int cc;
13300
13301                                 CHECK_STACK (1);
13302                                 --sp;
13303                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
13304                                         UNVERIFIED;
13305                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
13306                                 ins->sreg1 = (*sp)->dreg;
13307                                 MONO_ADD_INS (cfg->cbb, ins);
13308                                 start_new_bblock = 1;
13309                                 ip += 2;
13310
13311                                 nearest = NULL;
13312                                 for (cc = 0; cc < header->num_clauses; ++cc) {
13313                                         clause = &header->clauses [cc];
13314                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
13315                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
13316                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset)))
13317                                                 nearest = clause;
13318                                 }
13319                                 g_assert (nearest);
13320                                 if ((ip - header->code) != nearest->handler_offset)
13321                                         UNVERIFIED;
13322
13323                                 break;
13324                         }
13325                         case CEE_UNALIGNED_:
13326                                 ins_flag |= MONO_INST_UNALIGNED;
13327                                 /* FIXME: record alignment? we can assume 1 for now */
13328                                 CHECK_OPSIZE (3);
13329                                 ip += 3;
13330                                 break;
13331                         case CEE_VOLATILE_:
13332                                 ins_flag |= MONO_INST_VOLATILE;
13333                                 ip += 2;
13334                                 break;
13335                         case CEE_TAIL_:
13336                                 ins_flag   |= MONO_INST_TAILCALL;
13337                                 cfg->flags |= MONO_CFG_HAS_TAIL;
13338                                 /* Can't inline tail calls at this time */
13339                                 inline_costs += 100000;
13340                                 ip += 2;
13341                                 break;
13342                         case CEE_INITOBJ:
13343                                 CHECK_STACK (1);
13344                                 --sp;
13345                                 CHECK_OPSIZE (6);
13346                                 token = read32 (ip + 2);
13347                                 klass = mini_get_class (method, token, generic_context);
13348                                 CHECK_TYPELOAD (klass);
13349                                 if (generic_class_is_reference_type (cfg, klass))
13350                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
13351                                 else
13352                                         mini_emit_initobj (cfg, *sp, NULL, klass);
13353                                 ip += 6;
13354                                 inline_costs += 1;
13355                                 break;
13356                         case CEE_CONSTRAINED_:
13357                                 CHECK_OPSIZE (6);
13358                                 token = read32 (ip + 2);
13359                                 constrained_class = mini_get_class (method, token, generic_context);
13360                                 CHECK_TYPELOAD (constrained_class);
13361                                 ip += 6;
13362                                 break;
13363                         case CEE_CPBLK:
13364                         case CEE_INITBLK: {
13365                                 MonoInst *iargs [3];
13366                                 CHECK_STACK (3);
13367                                 sp -= 3;
13368
13369                                 /* Skip optimized paths for volatile operations. */
13370                                 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)) {
13371                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
13372                                 } 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)) {
13373                                         /* emit_memset only works when val == 0 */
13374                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
13375                                 } else {
13376                                         MonoInst *call;
13377                                         iargs [0] = sp [0];
13378                                         iargs [1] = sp [1];
13379                                         iargs [2] = sp [2];
13380                                         if (ip [1] == CEE_CPBLK) {
13381                                                 /*
13382                                                  * FIXME: It's unclear whether we should be emitting both the acquire
13383                                                  * and release barriers for cpblk. It is technically both a load and
13384                                                  * store operation, so it seems like that's the sensible thing to do.
13385                                                  *
13386                                                  * FIXME: We emit full barriers on both sides of the operation for
13387                                                  * simplicity. We should have a separate atomic memcpy method instead.
13388                                                  */
13389                                                 MonoMethod *memcpy_method = get_memcpy_method ();
13390
13391                                                 if (ins_flag & MONO_INST_VOLATILE)
13392                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
13393
13394                                                 call = mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
13395                                                 call->flags |= ins_flag;
13396
13397                                                 if (ins_flag & MONO_INST_VOLATILE)
13398                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
13399                                         } else {
13400                                                 MonoMethod *memset_method = get_memset_method ();
13401                                                 if (ins_flag & MONO_INST_VOLATILE) {
13402                                                         /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
13403                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
13404                                                 }
13405                                                 call = mono_emit_method_call (cfg, memset_method, iargs, NULL);
13406                                                 call->flags |= ins_flag;
13407                                         }
13408                                 }
13409                                 ip += 2;
13410                                 ins_flag = 0;
13411                                 inline_costs += 1;
13412                                 break;
13413                         }
13414                         case CEE_NO_:
13415                                 CHECK_OPSIZE (3);
13416                                 if (ip [2] & 0x1)
13417                                         ins_flag |= MONO_INST_NOTYPECHECK;
13418                                 if (ip [2] & 0x2)
13419                                         ins_flag |= MONO_INST_NORANGECHECK;
13420                                 /* we ignore the no-nullcheck for now since we
13421                                  * really do it explicitly only when doing callvirt->call
13422                                  */
13423                                 ip += 3;
13424                                 break;
13425                         case CEE_RETHROW: {
13426                                 MonoInst *load;
13427                                 int handler_offset = -1;
13428
13429                                 for (i = 0; i < header->num_clauses; ++i) {
13430                                         MonoExceptionClause *clause = &header->clauses [i];
13431                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
13432                                                 handler_offset = clause->handler_offset;
13433                                                 break;
13434                                         }
13435                                 }
13436
13437                                 cfg->cbb->flags |= BB_EXCEPTION_UNSAFE;
13438
13439                                 if (handler_offset == -1)
13440                                         UNVERIFIED;
13441
13442                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
13443                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
13444                                 ins->sreg1 = load->dreg;
13445                                 MONO_ADD_INS (cfg->cbb, ins);
13446
13447                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
13448                                 MONO_ADD_INS (cfg->cbb, ins);
13449
13450                                 sp = stack_start;
13451                                 link_bblock (cfg, cfg->cbb, end_bblock);
13452                                 start_new_bblock = 1;
13453                                 ip += 2;
13454                                 break;
13455                         }
13456                         case CEE_SIZEOF: {
13457                                 guint32 val;
13458                                 int ialign;
13459
13460                                 CHECK_STACK_OVF (1);
13461                                 CHECK_OPSIZE (6);
13462                                 token = read32 (ip + 2);
13463                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !image_is_dynamic (method->klass->image) && !generic_context) {
13464                                         MonoType *type = mono_type_create_from_typespec_checked (image, token, &cfg->error);
13465                                         CHECK_CFG_ERROR;
13466
13467                                         val = mono_type_size (type, &ialign);
13468                                 } else {
13469                                         MonoClass *klass = mini_get_class (method, token, generic_context);
13470                                         CHECK_TYPELOAD (klass);
13471
13472                                         val = mono_type_size (&klass->byval_arg, &ialign);
13473
13474                                         if (mini_is_gsharedvt_klass (klass))
13475                                                 GSHAREDVT_FAILURE (*ip);
13476                                 }
13477                                 EMIT_NEW_ICONST (cfg, ins, val);
13478                                 *sp++= ins;
13479                                 ip += 6;
13480                                 break;
13481                         }
13482                         case CEE_REFANYTYPE: {
13483                                 MonoInst *src_var, *src;
13484
13485                                 GSHAREDVT_FAILURE (*ip);
13486
13487                                 CHECK_STACK (1);
13488                                 --sp;
13489
13490                                 // FIXME:
13491                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
13492                                 if (!src_var)
13493                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
13494                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
13495                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type));
13496                                 *sp++ = ins;
13497                                 ip += 2;
13498                                 break;
13499                         }
13500                         case CEE_READONLY_:
13501                                 readonly = TRUE;
13502                                 ip += 2;
13503                                 break;
13504
13505                         case CEE_UNUSED56:
13506                         case CEE_UNUSED57:
13507                         case CEE_UNUSED70:
13508                         case CEE_UNUSED:
13509                         case CEE_UNUSED99:
13510                                 UNVERIFIED;
13511                                 
13512                         default:
13513                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
13514                                 UNVERIFIED;
13515                         }
13516                         break;
13517                 }
13518                 case CEE_UNUSED58:
13519                 case CEE_UNUSED1:
13520                         UNVERIFIED;
13521
13522                 default:
13523                         g_warning ("opcode 0x%02x not handled", *ip);
13524                         UNVERIFIED;
13525                 }
13526         }
13527         if (start_new_bblock != 1)
13528                 UNVERIFIED;
13529
13530         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
13531         if (cfg->cbb->next_bb) {
13532                 /* This could already be set because of inlining, #693905 */
13533                 MonoBasicBlock *bb = cfg->cbb;
13534
13535                 while (bb->next_bb)
13536                         bb = bb->next_bb;
13537                 bb->next_bb = end_bblock;
13538         } else {
13539                 cfg->cbb->next_bb = end_bblock;
13540         }
13541
13542         if (cfg->method == method && cfg->domainvar) {
13543                 MonoInst *store;
13544                 MonoInst *get_domain;
13545
13546                 cfg->cbb = init_localsbb;
13547
13548                 if ((get_domain = mono_get_domain_intrinsic (cfg))) {
13549                         MONO_ADD_INS (cfg->cbb, get_domain);
13550                 } else {
13551                         get_domain = mono_emit_jit_icall (cfg, mono_domain_get, NULL);
13552                 }
13553                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
13554                 MONO_ADD_INS (cfg->cbb, store);
13555         }
13556
13557 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
13558         if (cfg->compile_aot)
13559                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
13560                 mono_get_got_var (cfg);
13561 #endif
13562
13563         if (cfg->method == method && cfg->got_var)
13564                 mono_emit_load_got_addr (cfg);
13565
13566         if (init_localsbb) {
13567                 cfg->cbb = init_localsbb;
13568                 cfg->ip = NULL;
13569                 for (i = 0; i < header->num_locals; ++i) {
13570                         emit_init_local (cfg, i, header->locals [i], init_locals);
13571                 }
13572         }
13573
13574         if (cfg->init_ref_vars && cfg->method == method) {
13575                 /* Emit initialization for ref vars */
13576                 // FIXME: Avoid duplication initialization for IL locals.
13577                 for (i = 0; i < cfg->num_varinfo; ++i) {
13578                         MonoInst *ins = cfg->varinfo [i];
13579
13580                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
13581                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
13582                 }
13583         }
13584
13585         if (cfg->lmf_var && cfg->method == method && !cfg->llvm_only) {
13586                 cfg->cbb = init_localsbb;
13587                 emit_push_lmf (cfg);
13588         }
13589
13590         cfg->cbb = init_localsbb;
13591         emit_instrumentation_call (cfg, mono_profiler_method_enter);
13592
13593         if (seq_points) {
13594                 MonoBasicBlock *bb;
13595
13596                 /*
13597                  * Make seq points at backward branch targets interruptable.
13598                  */
13599                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
13600                         if (bb->code && bb->in_count > 1 && bb->code->opcode == OP_SEQ_POINT)
13601                                 bb->code->flags |= MONO_INST_SINGLE_STEP_LOC;
13602         }
13603
13604         /* Add a sequence point for method entry/exit events */
13605         if (seq_points && cfg->gen_sdb_seq_points) {
13606                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
13607                 MONO_ADD_INS (init_localsbb, ins);
13608                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
13609                 MONO_ADD_INS (cfg->bb_exit, ins);
13610         }
13611
13612         /*
13613          * Add seq points for IL offsets which have line number info, but wasn't generated a seq point during JITting because
13614          * the code they refer to was dead (#11880).
13615          */
13616         if (sym_seq_points) {
13617                 for (i = 0; i < header->code_size; ++i) {
13618                         if (mono_bitset_test_fast (seq_point_locs, i) && !mono_bitset_test_fast (seq_point_set_locs, i)) {
13619                                 MonoInst *ins;
13620
13621                                 NEW_SEQ_POINT (cfg, ins, i, FALSE);
13622                                 mono_add_seq_point (cfg, NULL, ins, SEQ_POINT_NATIVE_OFFSET_DEAD_CODE);
13623                         }
13624                 }
13625         }
13626
13627         cfg->ip = NULL;
13628
13629         if (cfg->method == method) {
13630                 MonoBasicBlock *bb;
13631                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13632                         bb->region = mono_find_block_region (cfg, bb->real_offset);
13633                         if (cfg->spvars)
13634                                 mono_create_spvar_for_region (cfg, bb->region);
13635                         if (cfg->verbose_level > 2)
13636                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
13637                 }
13638         }
13639
13640         if (inline_costs < 0) {
13641                 char *mname;
13642
13643                 /* Method is too large */
13644                 mname = mono_method_full_name (method, TRUE);
13645                 mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Method %s is too complex.", mname));
13646                 g_free (mname);
13647         }
13648
13649         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
13650                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
13651
13652         goto cleanup;
13653
13654 mono_error_exit:
13655         g_assert (!mono_error_ok (&cfg->error));
13656         goto cleanup;
13657  
13658  exception_exit:
13659         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
13660         goto cleanup;
13661
13662  unverified:
13663         set_exception_type_from_invalid_il (cfg, method, ip);
13664         goto cleanup;
13665
13666  cleanup:
13667         g_slist_free (class_inits);
13668         mono_basic_block_free (original_bb);
13669         cfg->dont_inline = g_list_remove (cfg->dont_inline, method);
13670         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
13671         if (cfg->exception_type)
13672                 return -1;
13673         else
13674                 return inline_costs;
13675 }
13676
13677 static int
13678 store_membase_reg_to_store_membase_imm (int opcode)
13679 {
13680         switch (opcode) {
13681         case OP_STORE_MEMBASE_REG:
13682                 return OP_STORE_MEMBASE_IMM;
13683         case OP_STOREI1_MEMBASE_REG:
13684                 return OP_STOREI1_MEMBASE_IMM;
13685         case OP_STOREI2_MEMBASE_REG:
13686                 return OP_STOREI2_MEMBASE_IMM;
13687         case OP_STOREI4_MEMBASE_REG:
13688                 return OP_STOREI4_MEMBASE_IMM;
13689         case OP_STOREI8_MEMBASE_REG:
13690                 return OP_STOREI8_MEMBASE_IMM;
13691         default:
13692                 g_assert_not_reached ();
13693         }
13694
13695         return -1;
13696 }               
13697
13698 int
13699 mono_op_to_op_imm (int opcode)
13700 {
13701         switch (opcode) {
13702         case OP_IADD:
13703                 return OP_IADD_IMM;
13704         case OP_ISUB:
13705                 return OP_ISUB_IMM;
13706         case OP_IDIV:
13707                 return OP_IDIV_IMM;
13708         case OP_IDIV_UN:
13709                 return OP_IDIV_UN_IMM;
13710         case OP_IREM:
13711                 return OP_IREM_IMM;
13712         case OP_IREM_UN:
13713                 return OP_IREM_UN_IMM;
13714         case OP_IMUL:
13715                 return OP_IMUL_IMM;
13716         case OP_IAND:
13717                 return OP_IAND_IMM;
13718         case OP_IOR:
13719                 return OP_IOR_IMM;
13720         case OP_IXOR:
13721                 return OP_IXOR_IMM;
13722         case OP_ISHL:
13723                 return OP_ISHL_IMM;
13724         case OP_ISHR:
13725                 return OP_ISHR_IMM;
13726         case OP_ISHR_UN:
13727                 return OP_ISHR_UN_IMM;
13728
13729         case OP_LADD:
13730                 return OP_LADD_IMM;
13731         case OP_LSUB:
13732                 return OP_LSUB_IMM;
13733         case OP_LAND:
13734                 return OP_LAND_IMM;
13735         case OP_LOR:
13736                 return OP_LOR_IMM;
13737         case OP_LXOR:
13738                 return OP_LXOR_IMM;
13739         case OP_LSHL:
13740                 return OP_LSHL_IMM;
13741         case OP_LSHR:
13742                 return OP_LSHR_IMM;
13743         case OP_LSHR_UN:
13744                 return OP_LSHR_UN_IMM;
13745 #if SIZEOF_REGISTER == 8
13746         case OP_LREM:
13747                 return OP_LREM_IMM;
13748 #endif
13749
13750         case OP_COMPARE:
13751                 return OP_COMPARE_IMM;
13752         case OP_ICOMPARE:
13753                 return OP_ICOMPARE_IMM;
13754         case OP_LCOMPARE:
13755                 return OP_LCOMPARE_IMM;
13756
13757         case OP_STORE_MEMBASE_REG:
13758                 return OP_STORE_MEMBASE_IMM;
13759         case OP_STOREI1_MEMBASE_REG:
13760                 return OP_STOREI1_MEMBASE_IMM;
13761         case OP_STOREI2_MEMBASE_REG:
13762                 return OP_STOREI2_MEMBASE_IMM;
13763         case OP_STOREI4_MEMBASE_REG:
13764                 return OP_STOREI4_MEMBASE_IMM;
13765
13766 #if defined(TARGET_X86) || defined (TARGET_AMD64)
13767         case OP_X86_PUSH:
13768                 return OP_X86_PUSH_IMM;
13769         case OP_X86_COMPARE_MEMBASE_REG:
13770                 return OP_X86_COMPARE_MEMBASE_IMM;
13771 #endif
13772 #if defined(TARGET_AMD64)
13773         case OP_AMD64_ICOMPARE_MEMBASE_REG:
13774                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13775 #endif
13776         case OP_VOIDCALL_REG:
13777                 return OP_VOIDCALL;
13778         case OP_CALL_REG:
13779                 return OP_CALL;
13780         case OP_LCALL_REG:
13781                 return OP_LCALL;
13782         case OP_FCALL_REG:
13783                 return OP_FCALL;
13784         case OP_LOCALLOC:
13785                 return OP_LOCALLOC_IMM;
13786         }
13787
13788         return -1;
13789 }
13790
13791 static int
13792 ldind_to_load_membase (int opcode)
13793 {
13794         switch (opcode) {
13795         case CEE_LDIND_I1:
13796                 return OP_LOADI1_MEMBASE;
13797         case CEE_LDIND_U1:
13798                 return OP_LOADU1_MEMBASE;
13799         case CEE_LDIND_I2:
13800                 return OP_LOADI2_MEMBASE;
13801         case CEE_LDIND_U2:
13802                 return OP_LOADU2_MEMBASE;
13803         case CEE_LDIND_I4:
13804                 return OP_LOADI4_MEMBASE;
13805         case CEE_LDIND_U4:
13806                 return OP_LOADU4_MEMBASE;
13807         case CEE_LDIND_I:
13808                 return OP_LOAD_MEMBASE;
13809         case CEE_LDIND_REF:
13810                 return OP_LOAD_MEMBASE;
13811         case CEE_LDIND_I8:
13812                 return OP_LOADI8_MEMBASE;
13813         case CEE_LDIND_R4:
13814                 return OP_LOADR4_MEMBASE;
13815         case CEE_LDIND_R8:
13816                 return OP_LOADR8_MEMBASE;
13817         default:
13818                 g_assert_not_reached ();
13819         }
13820
13821         return -1;
13822 }
13823
13824 static int
13825 stind_to_store_membase (int opcode)
13826 {
13827         switch (opcode) {
13828         case CEE_STIND_I1:
13829                 return OP_STOREI1_MEMBASE_REG;
13830         case CEE_STIND_I2:
13831                 return OP_STOREI2_MEMBASE_REG;
13832         case CEE_STIND_I4:
13833                 return OP_STOREI4_MEMBASE_REG;
13834         case CEE_STIND_I:
13835         case CEE_STIND_REF:
13836                 return OP_STORE_MEMBASE_REG;
13837         case CEE_STIND_I8:
13838                 return OP_STOREI8_MEMBASE_REG;
13839         case CEE_STIND_R4:
13840                 return OP_STORER4_MEMBASE_REG;
13841         case CEE_STIND_R8:
13842                 return OP_STORER8_MEMBASE_REG;
13843         default:
13844                 g_assert_not_reached ();
13845         }
13846
13847         return -1;
13848 }
13849
13850 int
13851 mono_load_membase_to_load_mem (int opcode)
13852 {
13853         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
13854 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13855         switch (opcode) {
13856         case OP_LOAD_MEMBASE:
13857                 return OP_LOAD_MEM;
13858         case OP_LOADU1_MEMBASE:
13859                 return OP_LOADU1_MEM;
13860         case OP_LOADU2_MEMBASE:
13861                 return OP_LOADU2_MEM;
13862         case OP_LOADI4_MEMBASE:
13863                 return OP_LOADI4_MEM;
13864         case OP_LOADU4_MEMBASE:
13865                 return OP_LOADU4_MEM;
13866 #if SIZEOF_REGISTER == 8
13867         case OP_LOADI8_MEMBASE:
13868                 return OP_LOADI8_MEM;
13869 #endif
13870         }
13871 #endif
13872
13873         return -1;
13874 }
13875
13876 static inline int
13877 op_to_op_dest_membase (int store_opcode, int opcode)
13878 {
13879 #if defined(TARGET_X86)
13880         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
13881                 return -1;
13882
13883         switch (opcode) {
13884         case OP_IADD:
13885                 return OP_X86_ADD_MEMBASE_REG;
13886         case OP_ISUB:
13887                 return OP_X86_SUB_MEMBASE_REG;
13888         case OP_IAND:
13889                 return OP_X86_AND_MEMBASE_REG;
13890         case OP_IOR:
13891                 return OP_X86_OR_MEMBASE_REG;
13892         case OP_IXOR:
13893                 return OP_X86_XOR_MEMBASE_REG;
13894         case OP_ADD_IMM:
13895         case OP_IADD_IMM:
13896                 return OP_X86_ADD_MEMBASE_IMM;
13897         case OP_SUB_IMM:
13898         case OP_ISUB_IMM:
13899                 return OP_X86_SUB_MEMBASE_IMM;
13900         case OP_AND_IMM:
13901         case OP_IAND_IMM:
13902                 return OP_X86_AND_MEMBASE_IMM;
13903         case OP_OR_IMM:
13904         case OP_IOR_IMM:
13905                 return OP_X86_OR_MEMBASE_IMM;
13906         case OP_XOR_IMM:
13907         case OP_IXOR_IMM:
13908                 return OP_X86_XOR_MEMBASE_IMM;
13909         case OP_MOVE:
13910                 return OP_NOP;
13911         }
13912 #endif
13913
13914 #if defined(TARGET_AMD64)
13915         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
13916                 return -1;
13917
13918         switch (opcode) {
13919         case OP_IADD:
13920                 return OP_X86_ADD_MEMBASE_REG;
13921         case OP_ISUB:
13922                 return OP_X86_SUB_MEMBASE_REG;
13923         case OP_IAND:
13924                 return OP_X86_AND_MEMBASE_REG;
13925         case OP_IOR:
13926                 return OP_X86_OR_MEMBASE_REG;
13927         case OP_IXOR:
13928                 return OP_X86_XOR_MEMBASE_REG;
13929         case OP_IADD_IMM:
13930                 return OP_X86_ADD_MEMBASE_IMM;
13931         case OP_ISUB_IMM:
13932                 return OP_X86_SUB_MEMBASE_IMM;
13933         case OP_IAND_IMM:
13934                 return OP_X86_AND_MEMBASE_IMM;
13935         case OP_IOR_IMM:
13936                 return OP_X86_OR_MEMBASE_IMM;
13937         case OP_IXOR_IMM:
13938                 return OP_X86_XOR_MEMBASE_IMM;
13939         case OP_LADD:
13940                 return OP_AMD64_ADD_MEMBASE_REG;
13941         case OP_LSUB:
13942                 return OP_AMD64_SUB_MEMBASE_REG;
13943         case OP_LAND:
13944                 return OP_AMD64_AND_MEMBASE_REG;
13945         case OP_LOR:
13946                 return OP_AMD64_OR_MEMBASE_REG;
13947         case OP_LXOR:
13948                 return OP_AMD64_XOR_MEMBASE_REG;
13949         case OP_ADD_IMM:
13950         case OP_LADD_IMM:
13951                 return OP_AMD64_ADD_MEMBASE_IMM;
13952         case OP_SUB_IMM:
13953         case OP_LSUB_IMM:
13954                 return OP_AMD64_SUB_MEMBASE_IMM;
13955         case OP_AND_IMM:
13956         case OP_LAND_IMM:
13957                 return OP_AMD64_AND_MEMBASE_IMM;
13958         case OP_OR_IMM:
13959         case OP_LOR_IMM:
13960                 return OP_AMD64_OR_MEMBASE_IMM;
13961         case OP_XOR_IMM:
13962         case OP_LXOR_IMM:
13963                 return OP_AMD64_XOR_MEMBASE_IMM;
13964         case OP_MOVE:
13965                 return OP_NOP;
13966         }
13967 #endif
13968
13969         return -1;
13970 }
13971
13972 static inline int
13973 op_to_op_store_membase (int store_opcode, int opcode)
13974 {
13975 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13976         switch (opcode) {
13977         case OP_ICEQ:
13978                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13979                         return OP_X86_SETEQ_MEMBASE;
13980         case OP_CNE:
13981                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13982                         return OP_X86_SETNE_MEMBASE;
13983         }
13984 #endif
13985
13986         return -1;
13987 }
13988
13989 static inline int
13990 op_to_op_src1_membase (MonoCompile *cfg, int load_opcode, int opcode)
13991 {
13992 #ifdef TARGET_X86
13993         /* FIXME: This has sign extension issues */
13994         /*
13995         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13996                 return OP_X86_COMPARE_MEMBASE8_IMM;
13997         */
13998
13999         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
14000                 return -1;
14001
14002         switch (opcode) {
14003         case OP_X86_PUSH:
14004                 return OP_X86_PUSH_MEMBASE;
14005         case OP_COMPARE_IMM:
14006         case OP_ICOMPARE_IMM:
14007                 return OP_X86_COMPARE_MEMBASE_IMM;
14008         case OP_COMPARE:
14009         case OP_ICOMPARE:
14010                 return OP_X86_COMPARE_MEMBASE_REG;
14011         }
14012 #endif
14013
14014 #ifdef TARGET_AMD64
14015         /* FIXME: This has sign extension issues */
14016         /*
14017         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
14018                 return OP_X86_COMPARE_MEMBASE8_IMM;
14019         */
14020
14021         switch (opcode) {
14022         case OP_X86_PUSH:
14023                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
14024                         return OP_X86_PUSH_MEMBASE;
14025                 break;
14026                 /* FIXME: This only works for 32 bit immediates
14027         case OP_COMPARE_IMM:
14028         case OP_LCOMPARE_IMM:
14029                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
14030                         return OP_AMD64_COMPARE_MEMBASE_IMM;
14031                 */
14032         case OP_ICOMPARE_IMM:
14033                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
14034                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
14035                 break;
14036         case OP_COMPARE:
14037         case OP_LCOMPARE:
14038                 if (cfg->backend->ilp32 && load_opcode == OP_LOAD_MEMBASE)
14039                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
14040                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
14041                         return OP_AMD64_COMPARE_MEMBASE_REG;
14042                 break;
14043         case OP_ICOMPARE:
14044                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
14045                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
14046                 break;
14047         }
14048 #endif
14049
14050         return -1;
14051 }
14052
14053 static inline int
14054 op_to_op_src2_membase (MonoCompile *cfg, int load_opcode, int opcode)
14055 {
14056 #ifdef TARGET_X86
14057         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
14058                 return -1;
14059         
14060         switch (opcode) {
14061         case OP_COMPARE:
14062         case OP_ICOMPARE:
14063                 return OP_X86_COMPARE_REG_MEMBASE;
14064         case OP_IADD:
14065                 return OP_X86_ADD_REG_MEMBASE;
14066         case OP_ISUB:
14067                 return OP_X86_SUB_REG_MEMBASE;
14068         case OP_IAND:
14069                 return OP_X86_AND_REG_MEMBASE;
14070         case OP_IOR:
14071                 return OP_X86_OR_REG_MEMBASE;
14072         case OP_IXOR:
14073                 return OP_X86_XOR_REG_MEMBASE;
14074         }
14075 #endif
14076
14077 #ifdef TARGET_AMD64
14078         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && cfg->backend->ilp32)) {
14079                 switch (opcode) {
14080                 case OP_ICOMPARE:
14081                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
14082                 case OP_IADD:
14083                         return OP_X86_ADD_REG_MEMBASE;
14084                 case OP_ISUB:
14085                         return OP_X86_SUB_REG_MEMBASE;
14086                 case OP_IAND:
14087                         return OP_X86_AND_REG_MEMBASE;
14088                 case OP_IOR:
14089                         return OP_X86_OR_REG_MEMBASE;
14090                 case OP_IXOR:
14091                         return OP_X86_XOR_REG_MEMBASE;
14092                 }
14093         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32)) {
14094                 switch (opcode) {
14095                 case OP_COMPARE:
14096                 case OP_LCOMPARE:
14097                         return OP_AMD64_COMPARE_REG_MEMBASE;
14098                 case OP_LADD:
14099                         return OP_AMD64_ADD_REG_MEMBASE;
14100                 case OP_LSUB:
14101                         return OP_AMD64_SUB_REG_MEMBASE;
14102                 case OP_LAND:
14103                         return OP_AMD64_AND_REG_MEMBASE;
14104                 case OP_LOR:
14105                         return OP_AMD64_OR_REG_MEMBASE;
14106                 case OP_LXOR:
14107                         return OP_AMD64_XOR_REG_MEMBASE;
14108                 }
14109         }
14110 #endif
14111
14112         return -1;
14113 }
14114
14115 int
14116 mono_op_to_op_imm_noemul (int opcode)
14117 {
14118         switch (opcode) {
14119 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
14120         case OP_LSHR:
14121         case OP_LSHL:
14122         case OP_LSHR_UN:
14123                 return -1;
14124 #endif
14125 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
14126         case OP_IDIV:
14127         case OP_IDIV_UN:
14128         case OP_IREM:
14129         case OP_IREM_UN:
14130                 return -1;
14131 #endif
14132 #if defined(MONO_ARCH_EMULATE_MUL_DIV)
14133         case OP_IMUL:
14134                 return -1;
14135 #endif
14136         default:
14137                 return mono_op_to_op_imm (opcode);
14138         }
14139 }
14140
14141 /**
14142  * mono_handle_global_vregs:
14143  *
14144  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
14145  * for them.
14146  */
14147 void
14148 mono_handle_global_vregs (MonoCompile *cfg)
14149 {
14150         gint32 *vreg_to_bb;
14151         MonoBasicBlock *bb;
14152         int i, pos;
14153
14154         vreg_to_bb = (gint32 *)mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
14155
14156 #ifdef MONO_ARCH_SIMD_INTRINSICS
14157         if (cfg->uses_simd_intrinsics)
14158                 mono_simd_simplify_indirection (cfg);
14159 #endif
14160
14161         /* Find local vregs used in more than one bb */
14162         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
14163                 MonoInst *ins = bb->code;       
14164                 int block_num = bb->block_num;
14165
14166                 if (cfg->verbose_level > 2)
14167                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
14168
14169                 cfg->cbb = bb;
14170                 for (; ins; ins = ins->next) {
14171                         const char *spec = INS_INFO (ins->opcode);
14172                         int regtype = 0, regindex;
14173                         gint32 prev_bb;
14174
14175                         if (G_UNLIKELY (cfg->verbose_level > 2))
14176                                 mono_print_ins (ins);
14177
14178                         g_assert (ins->opcode >= MONO_CEE_LAST);
14179
14180                         for (regindex = 0; regindex < 4; regindex ++) {
14181                                 int vreg = 0;
14182
14183                                 if (regindex == 0) {
14184                                         regtype = spec [MONO_INST_DEST];
14185                                         if (regtype == ' ')
14186                                                 continue;
14187                                         vreg = ins->dreg;
14188                                 } else if (regindex == 1) {
14189                                         regtype = spec [MONO_INST_SRC1];
14190                                         if (regtype == ' ')
14191                                                 continue;
14192                                         vreg = ins->sreg1;
14193                                 } else if (regindex == 2) {
14194                                         regtype = spec [MONO_INST_SRC2];
14195                                         if (regtype == ' ')
14196                                                 continue;
14197                                         vreg = ins->sreg2;
14198                                 } else if (regindex == 3) {
14199                                         regtype = spec [MONO_INST_SRC3];
14200                                         if (regtype == ' ')
14201                                                 continue;
14202                                         vreg = ins->sreg3;
14203                                 }
14204
14205 #if SIZEOF_REGISTER == 4
14206                                 /* In the LLVM case, the long opcodes are not decomposed */
14207                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
14208                                         /*
14209                                          * Since some instructions reference the original long vreg,
14210                                          * and some reference the two component vregs, it is quite hard
14211                                          * to determine when it needs to be global. So be conservative.
14212                                          */
14213                                         if (!get_vreg_to_inst (cfg, vreg)) {
14214                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
14215
14216                                                 if (cfg->verbose_level > 2)
14217                                                         printf ("LONG VREG R%d made global.\n", vreg);
14218                                         }
14219
14220                                         /*
14221                                          * Make the component vregs volatile since the optimizations can
14222                                          * get confused otherwise.
14223                                          */
14224                                         get_vreg_to_inst (cfg, MONO_LVREG_LS (vreg))->flags |= MONO_INST_VOLATILE;
14225                                         get_vreg_to_inst (cfg, MONO_LVREG_MS (vreg))->flags |= MONO_INST_VOLATILE;
14226                                 }
14227 #endif
14228
14229                                 g_assert (vreg != -1);
14230
14231                                 prev_bb = vreg_to_bb [vreg];
14232                                 if (prev_bb == 0) {
14233                                         /* 0 is a valid block num */
14234                                         vreg_to_bb [vreg] = block_num + 1;
14235                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
14236                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
14237                                                 continue;
14238
14239                                         if (!get_vreg_to_inst (cfg, vreg)) {
14240                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14241                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
14242
14243                                                 switch (regtype) {
14244                                                 case 'i':
14245                                                         if (vreg_is_ref (cfg, vreg))
14246                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg);
14247                                                         else
14248                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
14249                                                         break;
14250                                                 case 'l':
14251                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
14252                                                         break;
14253                                                 case 'f':
14254                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
14255                                                         break;
14256                                                 case 'v':
14257                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
14258                                                         break;
14259                                                 default:
14260                                                         g_assert_not_reached ();
14261                                                 }
14262                                         }
14263
14264                                         /* Flag as having been used in more than one bb */
14265                                         vreg_to_bb [vreg] = -1;
14266                                 }
14267                         }
14268                 }
14269         }
14270
14271         /* If a variable is used in only one bblock, convert it into a local vreg */
14272         for (i = 0; i < cfg->num_varinfo; i++) {
14273                 MonoInst *var = cfg->varinfo [i];
14274                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
14275
14276                 switch (var->type) {
14277                 case STACK_I4:
14278                 case STACK_OBJ:
14279                 case STACK_PTR:
14280                 case STACK_MP:
14281                 case STACK_VTYPE:
14282 #if SIZEOF_REGISTER == 8
14283                 case STACK_I8:
14284 #endif
14285 #if !defined(TARGET_X86)
14286                 /* Enabling this screws up the fp stack on x86 */
14287                 case STACK_R8:
14288 #endif
14289                         if (mono_arch_is_soft_float ())
14290                                 break;
14291
14292                         /*
14293                         if (var->type == STACK_VTYPE && cfg->gsharedvt && mini_is_gsharedvt_variable_type (var->inst_vtype))
14294                                 break;
14295                         */
14296
14297                         /* Arguments are implicitly global */
14298                         /* Putting R4 vars into registers doesn't work currently */
14299                         /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
14300                         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) {
14301                                 /* 
14302                                  * Make that the variable's liveness interval doesn't contain a call, since
14303                                  * that would cause the lvreg to be spilled, making the whole optimization
14304                                  * useless.
14305                                  */
14306                                 /* This is too slow for JIT compilation */
14307 #if 0
14308                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
14309                                         MonoInst *ins;
14310                                         int def_index, call_index, ins_index;
14311                                         gboolean spilled = FALSE;
14312
14313                                         def_index = -1;
14314                                         call_index = -1;
14315                                         ins_index = 0;
14316                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
14317                                                 const char *spec = INS_INFO (ins->opcode);
14318
14319                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
14320                                                         def_index = ins_index;
14321
14322                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
14323                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
14324                                                         if (call_index > def_index) {
14325                                                                 spilled = TRUE;
14326                                                                 break;
14327                                                         }
14328                                                 }
14329
14330                                                 if (MONO_IS_CALL (ins))
14331                                                         call_index = ins_index;
14332
14333                                                 ins_index ++;
14334                                         }
14335
14336                                         if (spilled)
14337                                                 break;
14338                                 }
14339 #endif
14340
14341                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14342                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
14343                                 var->flags |= MONO_INST_IS_DEAD;
14344                                 cfg->vreg_to_inst [var->dreg] = NULL;
14345                         }
14346                         break;
14347                 }
14348         }
14349
14350         /* 
14351          * Compress the varinfo and vars tables so the liveness computation is faster and
14352          * takes up less space.
14353          */
14354         pos = 0;
14355         for (i = 0; i < cfg->num_varinfo; ++i) {
14356                 MonoInst *var = cfg->varinfo [i];
14357                 if (pos < i && cfg->locals_start == i)
14358                         cfg->locals_start = pos;
14359                 if (!(var->flags & MONO_INST_IS_DEAD)) {
14360                         if (pos < i) {
14361                                 cfg->varinfo [pos] = cfg->varinfo [i];
14362                                 cfg->varinfo [pos]->inst_c0 = pos;
14363                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
14364                                 cfg->vars [pos].idx = pos;
14365 #if SIZEOF_REGISTER == 4
14366                                 if (cfg->varinfo [pos]->type == STACK_I8) {
14367                                         /* Modify the two component vars too */
14368                                         MonoInst *var1;
14369
14370                                         var1 = get_vreg_to_inst (cfg, MONO_LVREG_LS (cfg->varinfo [pos]->dreg));
14371                                         var1->inst_c0 = pos;
14372                                         var1 = get_vreg_to_inst (cfg, MONO_LVREG_MS (cfg->varinfo [pos]->dreg));
14373                                         var1->inst_c0 = pos;
14374                                 }
14375 #endif
14376                         }
14377                         pos ++;
14378                 }
14379         }
14380         cfg->num_varinfo = pos;
14381         if (cfg->locals_start > cfg->num_varinfo)
14382                 cfg->locals_start = cfg->num_varinfo;
14383 }
14384
14385 /*
14386  * mono_allocate_gsharedvt_vars:
14387  *
14388  *   Allocate variables with gsharedvt types to entries in the MonoGSharedVtMethodRuntimeInfo.entries array.
14389  * Initialize cfg->gsharedvt_vreg_to_idx with the mapping between vregs and indexes.
14390  */
14391 void
14392 mono_allocate_gsharedvt_vars (MonoCompile *cfg)
14393 {
14394         int i;
14395
14396         cfg->gsharedvt_vreg_to_idx = (int *)mono_mempool_alloc0 (cfg->mempool, sizeof (int) * cfg->next_vreg);
14397
14398         for (i = 0; i < cfg->num_varinfo; ++i) {
14399                 MonoInst *ins = cfg->varinfo [i];
14400                 int idx;
14401
14402                 if (mini_is_gsharedvt_variable_type (ins->inst_vtype)) {
14403                         if (i >= cfg->locals_start) {
14404                                 /* Local */
14405                                 idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
14406                                 cfg->gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
14407                                 ins->opcode = OP_GSHAREDVT_LOCAL;
14408                                 ins->inst_imm = idx;
14409                         } else {
14410                                 /* Arg */
14411                                 cfg->gsharedvt_vreg_to_idx [ins->dreg] = -1;
14412                                 ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
14413                         }
14414                 }
14415         }
14416 }
14417
14418 /**
14419  * mono_spill_global_vars:
14420  *
14421  *   Generate spill code for variables which are not allocated to registers, 
14422  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
14423  * code is generated which could be optimized by the local optimization passes.
14424  */
14425 void
14426 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
14427 {
14428         MonoBasicBlock *bb;
14429         char spec2 [16];
14430         int orig_next_vreg;
14431         guint32 *vreg_to_lvreg;
14432         guint32 *lvregs;
14433         guint32 i, lvregs_len;
14434         gboolean dest_has_lvreg = FALSE;
14435         MonoStackType stacktypes [128];
14436         MonoInst **live_range_start, **live_range_end;
14437         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
14438
14439         *need_local_opts = FALSE;
14440
14441         memset (spec2, 0, sizeof (spec2));
14442
14443         /* FIXME: Move this function to mini.c */
14444         stacktypes ['i'] = STACK_PTR;
14445         stacktypes ['l'] = STACK_I8;
14446         stacktypes ['f'] = STACK_R8;
14447 #ifdef MONO_ARCH_SIMD_INTRINSICS
14448         stacktypes ['x'] = STACK_VTYPE;
14449 #endif
14450
14451 #if SIZEOF_REGISTER == 4
14452         /* Create MonoInsts for longs */
14453         for (i = 0; i < cfg->num_varinfo; i++) {
14454                 MonoInst *ins = cfg->varinfo [i];
14455
14456                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
14457                         switch (ins->type) {
14458                         case STACK_R8:
14459                         case STACK_I8: {
14460                                 MonoInst *tree;
14461
14462                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
14463                                         break;
14464
14465                                 g_assert (ins->opcode == OP_REGOFFSET);
14466
14467                                 tree = get_vreg_to_inst (cfg, MONO_LVREG_LS (ins->dreg));
14468                                 g_assert (tree);
14469                                 tree->opcode = OP_REGOFFSET;
14470                                 tree->inst_basereg = ins->inst_basereg;
14471                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
14472
14473                                 tree = get_vreg_to_inst (cfg, MONO_LVREG_MS (ins->dreg));
14474                                 g_assert (tree);
14475                                 tree->opcode = OP_REGOFFSET;
14476                                 tree->inst_basereg = ins->inst_basereg;
14477                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
14478                                 break;
14479                         }
14480                         default:
14481                                 break;
14482                         }
14483                 }
14484         }
14485 #endif
14486
14487         if (cfg->compute_gc_maps) {
14488                 /* registers need liveness info even for !non refs */
14489                 for (i = 0; i < cfg->num_varinfo; i++) {
14490                         MonoInst *ins = cfg->varinfo [i];
14491
14492                         if (ins->opcode == OP_REGVAR)
14493                                 ins->flags |= MONO_INST_GC_TRACK;
14494                 }
14495         }
14496                 
14497         /* FIXME: widening and truncation */
14498
14499         /*
14500          * As an optimization, when a variable allocated to the stack is first loaded into 
14501          * an lvreg, we will remember the lvreg and use it the next time instead of loading
14502          * the variable again.
14503          */
14504         orig_next_vreg = cfg->next_vreg;
14505         vreg_to_lvreg = (guint32 *)mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
14506         lvregs = (guint32 *)mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
14507         lvregs_len = 0;
14508
14509         /* 
14510          * These arrays contain the first and last instructions accessing a given
14511          * variable.
14512          * Since we emit bblocks in the same order we process them here, and we
14513          * don't split live ranges, these will precisely describe the live range of
14514          * the variable, i.e. the instruction range where a valid value can be found
14515          * in the variables location.
14516          * The live range is computed using the liveness info computed by the liveness pass.
14517          * We can't use vmv->range, since that is an abstract live range, and we need
14518          * one which is instruction precise.
14519          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
14520          */
14521         /* FIXME: Only do this if debugging info is requested */
14522         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
14523         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
14524         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
14525         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
14526         
14527         /* Add spill loads/stores */
14528         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
14529                 MonoInst *ins;
14530
14531                 if (cfg->verbose_level > 2)
14532                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
14533
14534                 /* Clear vreg_to_lvreg array */
14535                 for (i = 0; i < lvregs_len; i++)
14536                         vreg_to_lvreg [lvregs [i]] = 0;
14537                 lvregs_len = 0;
14538
14539                 cfg->cbb = bb;
14540                 MONO_BB_FOR_EACH_INS (bb, ins) {
14541                         const char *spec = INS_INFO (ins->opcode);
14542                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
14543                         gboolean store, no_lvreg;
14544                         int sregs [MONO_MAX_SRC_REGS];
14545
14546                         if (G_UNLIKELY (cfg->verbose_level > 2))
14547                                 mono_print_ins (ins);
14548
14549                         if (ins->opcode == OP_NOP)
14550                                 continue;
14551
14552                         /* 
14553                          * We handle LDADDR here as well, since it can only be decomposed
14554                          * when variable addresses are known.
14555                          */
14556                         if (ins->opcode == OP_LDADDR) {
14557                                 MonoInst *var = (MonoInst *)ins->inst_p0;
14558
14559                                 if (var->opcode == OP_VTARG_ADDR) {
14560                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
14561                                         MonoInst *vtaddr = var->inst_left;
14562                                         if (vtaddr->opcode == OP_REGVAR) {
14563                                                 ins->opcode = OP_MOVE;
14564                                                 ins->sreg1 = vtaddr->dreg;
14565                                         }
14566                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
14567                                                 ins->opcode = OP_LOAD_MEMBASE;
14568                                                 ins->inst_basereg = vtaddr->inst_basereg;
14569                                                 ins->inst_offset = vtaddr->inst_offset;
14570                                         } else
14571                                                 NOT_IMPLEMENTED;
14572                                 } else if (cfg->gsharedvt && cfg->gsharedvt_vreg_to_idx [var->dreg] < 0) {
14573                                         /* gsharedvt arg passed by ref */
14574                                         g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
14575
14576                                         ins->opcode = OP_LOAD_MEMBASE;
14577                                         ins->inst_basereg = var->inst_basereg;
14578                                         ins->inst_offset = var->inst_offset;
14579                                 } else if (cfg->gsharedvt && cfg->gsharedvt_vreg_to_idx [var->dreg]) {
14580                                         MonoInst *load, *load2, *load3;
14581                                         int idx = cfg->gsharedvt_vreg_to_idx [var->dreg] - 1;
14582                                         int reg1, reg2, reg3;
14583                                         MonoInst *info_var = cfg->gsharedvt_info_var;
14584                                         MonoInst *locals_var = cfg->gsharedvt_locals_var;
14585
14586                                         /*
14587                                          * gsharedvt local.
14588                                          * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
14589                                          */
14590
14591                                         g_assert (var->opcode == OP_GSHAREDVT_LOCAL);
14592
14593                                         g_assert (info_var);
14594                                         g_assert (locals_var);
14595
14596                                         /* Mark the instruction used to compute the locals var as used */
14597                                         cfg->gsharedvt_locals_var_ins = NULL;
14598
14599                                         /* Load the offset */
14600                                         if (info_var->opcode == OP_REGOFFSET) {
14601                                                 reg1 = alloc_ireg (cfg);
14602                                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, reg1, info_var->inst_basereg, info_var->inst_offset);
14603                                         } else if (info_var->opcode == OP_REGVAR) {
14604                                                 load = NULL;
14605                                                 reg1 = info_var->dreg;
14606                                         } else {
14607                                                 g_assert_not_reached ();
14608                                         }
14609                                         reg2 = alloc_ireg (cfg);
14610                                         NEW_LOAD_MEMBASE (cfg, load2, OP_LOADI4_MEMBASE, reg2, reg1, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
14611                                         /* Load the locals area address */
14612                                         reg3 = alloc_ireg (cfg);
14613                                         if (locals_var->opcode == OP_REGOFFSET) {
14614                                                 NEW_LOAD_MEMBASE (cfg, load3, OP_LOAD_MEMBASE, reg3, locals_var->inst_basereg, locals_var->inst_offset);
14615                                         } else if (locals_var->opcode == OP_REGVAR) {
14616                                                 NEW_UNALU (cfg, load3, OP_MOVE, reg3, locals_var->dreg);
14617                                         } else {
14618                                                 g_assert_not_reached ();
14619                                         }
14620                                         /* Compute the address */
14621                                         ins->opcode = OP_PADD;
14622                                         ins->sreg1 = reg3;
14623                                         ins->sreg2 = reg2;
14624
14625                                         mono_bblock_insert_before_ins (bb, ins, load3);
14626                                         mono_bblock_insert_before_ins (bb, load3, load2);
14627                                         if (load)
14628                                                 mono_bblock_insert_before_ins (bb, load2, load);
14629                                 } else {
14630                                         g_assert (var->opcode == OP_REGOFFSET);
14631
14632                                         ins->opcode = OP_ADD_IMM;
14633                                         ins->sreg1 = var->inst_basereg;
14634                                         ins->inst_imm = var->inst_offset;
14635                                 }
14636
14637                                 *need_local_opts = TRUE;
14638                                 spec = INS_INFO (ins->opcode);
14639                         }
14640
14641                         if (ins->opcode < MONO_CEE_LAST) {
14642                                 mono_print_ins (ins);
14643                                 g_assert_not_reached ();
14644                         }
14645
14646                         /*
14647                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
14648                          * src register.
14649                          * FIXME:
14650                          */
14651                         if (MONO_IS_STORE_MEMBASE (ins)) {
14652                                 tmp_reg = ins->dreg;
14653                                 ins->dreg = ins->sreg2;
14654                                 ins->sreg2 = tmp_reg;
14655                                 store = TRUE;
14656
14657                                 spec2 [MONO_INST_DEST] = ' ';
14658                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14659                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14660                                 spec2 [MONO_INST_SRC3] = ' ';
14661                                 spec = spec2;
14662                         } else if (MONO_IS_STORE_MEMINDEX (ins))
14663                                 g_assert_not_reached ();
14664                         else
14665                                 store = FALSE;
14666                         no_lvreg = FALSE;
14667
14668                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
14669                                 printf ("\t %.3s %d", spec, ins->dreg);
14670                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
14671                                 for (srcindex = 0; srcindex < num_sregs; ++srcindex)
14672                                         printf (" %d", sregs [srcindex]);
14673                                 printf ("\n");
14674                         }
14675
14676                         /***************/
14677                         /*    DREG     */
14678                         /***************/
14679                         regtype = spec [MONO_INST_DEST];
14680                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
14681                         prev_dreg = -1;
14682
14683                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
14684                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
14685                                 MonoInst *store_ins;
14686                                 int store_opcode;
14687                                 MonoInst *def_ins = ins;
14688                                 int dreg = ins->dreg; /* The original vreg */
14689
14690                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
14691
14692                                 if (var->opcode == OP_REGVAR) {
14693                                         ins->dreg = var->dreg;
14694                                 } 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)) {
14695                                         /* 
14696                                          * Instead of emitting a load+store, use a _membase opcode.
14697                                          */
14698                                         g_assert (var->opcode == OP_REGOFFSET);
14699                                         if (ins->opcode == OP_MOVE) {
14700                                                 NULLIFY_INS (ins);
14701                                                 def_ins = NULL;
14702                                         } else {
14703                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
14704                                                 ins->inst_basereg = var->inst_basereg;
14705                                                 ins->inst_offset = var->inst_offset;
14706                                                 ins->dreg = -1;
14707                                         }
14708                                         spec = INS_INFO (ins->opcode);
14709                                 } else {
14710                                         guint32 lvreg;
14711
14712                                         g_assert (var->opcode == OP_REGOFFSET);
14713
14714                                         prev_dreg = ins->dreg;
14715
14716                                         /* Invalidate any previous lvreg for this vreg */
14717                                         vreg_to_lvreg [ins->dreg] = 0;
14718
14719                                         lvreg = 0;
14720
14721                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
14722                                                 regtype = 'l';
14723                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
14724                                         }
14725
14726                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
14727
14728 #if SIZEOF_REGISTER != 8
14729                                         if (regtype == 'l') {
14730                                                 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));
14731                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14732                                                 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));
14733                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14734                                                 def_ins = store_ins;
14735                                         }
14736                                         else
14737 #endif
14738                                         {
14739                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
14740
14741                                                 /* Try to fuse the store into the instruction itself */
14742                                                 /* FIXME: Add more instructions */
14743                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
14744                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
14745                                                         ins->inst_imm = ins->inst_c0;
14746                                                         ins->inst_destbasereg = var->inst_basereg;
14747                                                         ins->inst_offset = var->inst_offset;
14748                                                         spec = INS_INFO (ins->opcode);
14749                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE) || (ins->opcode == OP_RMOVE))) {
14750                                                         ins->opcode = store_opcode;
14751                                                         ins->inst_destbasereg = var->inst_basereg;
14752                                                         ins->inst_offset = var->inst_offset;
14753
14754                                                         no_lvreg = TRUE;
14755
14756                                                         tmp_reg = ins->dreg;
14757                                                         ins->dreg = ins->sreg2;
14758                                                         ins->sreg2 = tmp_reg;
14759                                                         store = TRUE;
14760
14761                                                         spec2 [MONO_INST_DEST] = ' ';
14762                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14763                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14764                                                         spec2 [MONO_INST_SRC3] = ' ';
14765                                                         spec = spec2;
14766                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
14767                                                         // FIXME: The backends expect the base reg to be in inst_basereg
14768                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
14769                                                         ins->dreg = -1;
14770                                                         ins->inst_basereg = var->inst_basereg;
14771                                                         ins->inst_offset = var->inst_offset;
14772                                                         spec = INS_INFO (ins->opcode);
14773                                                 } else {
14774                                                         /* printf ("INS: "); mono_print_ins (ins); */
14775                                                         /* Create a store instruction */
14776                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
14777
14778                                                         /* Insert it after the instruction */
14779                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
14780
14781                                                         def_ins = store_ins;
14782
14783                                                         /* 
14784                                                          * We can't assign ins->dreg to var->dreg here, since the
14785                                                          * sregs could use it. So set a flag, and do it after
14786                                                          * the sregs.
14787                                                          */
14788                                                         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)))
14789                                                                 dest_has_lvreg = TRUE;
14790                                                 }
14791                                         }
14792                                 }
14793
14794                                 if (def_ins && !live_range_start [dreg]) {
14795                                         live_range_start [dreg] = def_ins;
14796                                         live_range_start_bb [dreg] = bb;
14797                                 }
14798
14799                                 if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) {
14800                                         MonoInst *tmp;
14801
14802                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
14803                                         tmp->inst_c1 = dreg;
14804                                         mono_bblock_insert_after_ins (bb, def_ins, tmp);
14805                                 }
14806                         }
14807
14808                         /************/
14809                         /*  SREGS   */
14810                         /************/
14811                         num_sregs = mono_inst_get_src_registers (ins, sregs);
14812                         for (srcindex = 0; srcindex < 3; ++srcindex) {
14813                                 regtype = spec [MONO_INST_SRC1 + srcindex];
14814                                 sreg = sregs [srcindex];
14815
14816                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
14817                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
14818                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
14819                                         MonoInst *use_ins = ins;
14820                                         MonoInst *load_ins;
14821                                         guint32 load_opcode;
14822
14823                                         if (var->opcode == OP_REGVAR) {
14824                                                 sregs [srcindex] = var->dreg;
14825                                                 //mono_inst_set_src_registers (ins, sregs);
14826                                                 live_range_end [sreg] = use_ins;
14827                                                 live_range_end_bb [sreg] = bb;
14828
14829                                                 if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14830                                                         MonoInst *tmp;
14831
14832                                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14833                                                         /* var->dreg is a hreg */
14834                                                         tmp->inst_c1 = sreg;
14835                                                         mono_bblock_insert_after_ins (bb, ins, tmp);
14836                                                 }
14837
14838                                                 continue;
14839                                         }
14840
14841                                         g_assert (var->opcode == OP_REGOFFSET);
14842                                                 
14843                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
14844
14845                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
14846
14847                                         if (vreg_to_lvreg [sreg]) {
14848                                                 g_assert (vreg_to_lvreg [sreg] != -1);
14849
14850                                                 /* The variable is already loaded to an lvreg */
14851                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14852                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
14853                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
14854                                                 //mono_inst_set_src_registers (ins, sregs);
14855                                                 continue;
14856                                         }
14857
14858                                         /* Try to fuse the load into the instruction */
14859                                         if ((srcindex == 0) && (op_to_op_src1_membase (cfg, load_opcode, ins->opcode) != -1)) {
14860                                                 ins->opcode = op_to_op_src1_membase (cfg, load_opcode, ins->opcode);
14861                                                 sregs [0] = var->inst_basereg;
14862                                                 //mono_inst_set_src_registers (ins, sregs);
14863                                                 ins->inst_offset = var->inst_offset;
14864                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (cfg, load_opcode, ins->opcode) != -1)) {
14865                                                 ins->opcode = op_to_op_src2_membase (cfg, load_opcode, ins->opcode);
14866                                                 sregs [1] = var->inst_basereg;
14867                                                 //mono_inst_set_src_registers (ins, sregs);
14868                                                 ins->inst_offset = var->inst_offset;
14869                                         } else {
14870                                                 if (MONO_IS_REAL_MOVE (ins)) {
14871                                                         ins->opcode = OP_NOP;
14872                                                         sreg = ins->dreg;
14873                                                 } else {
14874                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
14875
14876                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
14877
14878                                                         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) {
14879                                                                 if (var->dreg == prev_dreg) {
14880                                                                         /*
14881                                                                          * sreg refers to the value loaded by the load
14882                                                                          * emitted below, but we need to use ins->dreg
14883                                                                          * since it refers to the store emitted earlier.
14884                                                                          */
14885                                                                         sreg = ins->dreg;
14886                                                                 }
14887                                                                 g_assert (sreg != -1);
14888                                                                 vreg_to_lvreg [var->dreg] = sreg;
14889                                                                 g_assert (lvregs_len < 1024);
14890                                                                 lvregs [lvregs_len ++] = var->dreg;
14891                                                         }
14892                                                 }
14893
14894                                                 sregs [srcindex] = sreg;
14895                                                 //mono_inst_set_src_registers (ins, sregs);
14896
14897 #if SIZEOF_REGISTER != 8
14898                                                 if (regtype == 'l') {
14899                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, MONO_LVREG_MS (sreg), var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
14900                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14901                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, MONO_LVREG_LS (sreg), var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
14902                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14903                                                         use_ins = load_ins;
14904                                                 }
14905                                                 else
14906 #endif
14907                                                 {
14908 #if SIZEOF_REGISTER == 4
14909                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
14910 #endif
14911                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
14912                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14913                                                         use_ins = load_ins;
14914                                                 }
14915                                         }
14916
14917                                         if (var->dreg < orig_next_vreg) {
14918                                                 live_range_end [var->dreg] = use_ins;
14919                                                 live_range_end_bb [var->dreg] = bb;
14920                                         }
14921
14922                                         if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14923                                                 MonoInst *tmp;
14924
14925                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14926                                                 tmp->inst_c1 = var->dreg;
14927                                                 mono_bblock_insert_after_ins (bb, ins, tmp);
14928                                         }
14929                                 }
14930                         }
14931                         mono_inst_set_src_registers (ins, sregs);
14932
14933                         if (dest_has_lvreg) {
14934                                 g_assert (ins->dreg != -1);
14935                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
14936                                 g_assert (lvregs_len < 1024);
14937                                 lvregs [lvregs_len ++] = prev_dreg;
14938                                 dest_has_lvreg = FALSE;
14939                         }
14940
14941                         if (store) {
14942                                 tmp_reg = ins->dreg;
14943                                 ins->dreg = ins->sreg2;
14944                                 ins->sreg2 = tmp_reg;
14945                         }
14946
14947                         if (MONO_IS_CALL (ins)) {
14948                                 /* Clear vreg_to_lvreg array */
14949                                 for (i = 0; i < lvregs_len; i++)
14950                                         vreg_to_lvreg [lvregs [i]] = 0;
14951                                 lvregs_len = 0;
14952                         } else if (ins->opcode == OP_NOP) {
14953                                 ins->dreg = -1;
14954                                 MONO_INST_NULLIFY_SREGS (ins);
14955                         }
14956
14957                         if (cfg->verbose_level > 2)
14958                                 mono_print_ins_index (1, ins);
14959                 }
14960
14961                 /* Extend the live range based on the liveness info */
14962                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
14963                         for (i = 0; i < cfg->num_varinfo; i ++) {
14964                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
14965
14966                                 if (vreg_is_volatile (cfg, vi->vreg))
14967                                         /* The liveness info is incomplete */
14968                                         continue;
14969
14970                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
14971                                         /* Live from at least the first ins of this bb */
14972                                         live_range_start [vi->vreg] = bb->code;
14973                                         live_range_start_bb [vi->vreg] = bb;
14974                                 }
14975
14976                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
14977                                         /* Live at least until the last ins of this bb */
14978                                         live_range_end [vi->vreg] = bb->last_ins;
14979                                         live_range_end_bb [vi->vreg] = bb;
14980                                 }
14981                         }
14982                 }
14983         }
14984         
14985         /*
14986          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
14987          * by storing the current native offset into MonoMethodVar->live_range_start/end.
14988          */
14989         if (cfg->backend->have_liverange_ops && cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
14990                 for (i = 0; i < cfg->num_varinfo; ++i) {
14991                         int vreg = MONO_VARINFO (cfg, i)->vreg;
14992                         MonoInst *ins;
14993
14994                         if (live_range_start [vreg]) {
14995                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
14996                                 ins->inst_c0 = i;
14997                                 ins->inst_c1 = vreg;
14998                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
14999                         }
15000                         if (live_range_end [vreg]) {
15001                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
15002                                 ins->inst_c0 = i;
15003                                 ins->inst_c1 = vreg;
15004                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
15005                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
15006                                 else
15007                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
15008                         }
15009                 }
15010         }
15011
15012         if (cfg->gsharedvt_locals_var_ins) {
15013                 /* Nullify if unused */
15014                 cfg->gsharedvt_locals_var_ins->opcode = OP_PCONST;
15015                 cfg->gsharedvt_locals_var_ins->inst_imm = 0;
15016         }
15017
15018         g_free (live_range_start);
15019         g_free (live_range_end);
15020         g_free (live_range_start_bb);
15021         g_free (live_range_end_bb);
15022 }
15023
15024 /**
15025  * FIXME:
15026  * - use 'iadd' instead of 'int_add'
15027  * - handling ovf opcodes: decompose in method_to_ir.
15028  * - unify iregs/fregs
15029  *   -> partly done, the missing parts are:
15030  *   - a more complete unification would involve unifying the hregs as well, so
15031  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
15032  *     would no longer map to the machine hregs, so the code generators would need to
15033  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
15034  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
15035  *     fp/non-fp branches speeds it up by about 15%.
15036  * - use sext/zext opcodes instead of shifts
15037  * - add OP_ICALL
15038  * - get rid of TEMPLOADs if possible and use vregs instead
15039  * - clean up usage of OP_P/OP_ opcodes
15040  * - cleanup usage of DUMMY_USE
15041  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
15042  *   stack
15043  * - set the stack type and allocate a dreg in the EMIT_NEW macros
15044  * - get rid of all the <foo>2 stuff when the new JIT is ready.
15045  * - make sure handle_stack_args () is called before the branch is emitted
15046  * - when the new IR is done, get rid of all unused stuff
15047  * - COMPARE/BEQ as separate instructions or unify them ?
15048  *   - keeping them separate allows specialized compare instructions like
15049  *     compare_imm, compare_membase
15050  *   - most back ends unify fp compare+branch, fp compare+ceq
15051  * - integrate mono_save_args into inline_method
15052  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
15053  * - handle long shift opts on 32 bit platforms somehow: they require 
15054  *   3 sregs (2 for arg1 and 1 for arg2)
15055  * - make byref a 'normal' type.
15056  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
15057  *   variable if needed.
15058  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
15059  *   like inline_method.
15060  * - remove inlining restrictions
15061  * - fix LNEG and enable cfold of INEG
15062  * - generalize x86 optimizations like ldelema as a peephole optimization
15063  * - add store_mem_imm for amd64
15064  * - optimize the loading of the interruption flag in the managed->native wrappers
15065  * - avoid special handling of OP_NOP in passes
15066  * - move code inserting instructions into one function/macro.
15067  * - try a coalescing phase after liveness analysis
15068  * - add float -> vreg conversion + local optimizations on !x86
15069  * - figure out how to handle decomposed branches during optimizations, ie.
15070  *   compare+branch, op_jump_table+op_br etc.
15071  * - promote RuntimeXHandles to vregs
15072  * - vtype cleanups:
15073  *   - add a NEW_VARLOADA_VREG macro
15074  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
15075  *   accessing vtype fields.
15076  * - get rid of I8CONST on 64 bit platforms
15077  * - dealing with the increase in code size due to branches created during opcode
15078  *   decomposition:
15079  *   - use extended basic blocks
15080  *     - all parts of the JIT
15081  *     - handle_global_vregs () && local regalloc
15082  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
15083  * - sources of increase in code size:
15084  *   - vtypes
15085  *   - long compares
15086  *   - isinst and castclass
15087  *   - lvregs not allocated to global registers even if used multiple times
15088  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
15089  *   meaningful.
15090  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
15091  * - add all micro optimizations from the old JIT
15092  * - put tree optimizations into the deadce pass
15093  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
15094  *   specific function.
15095  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
15096  *   fcompare + branchCC.
15097  * - create a helper function for allocating a stack slot, taking into account 
15098  *   MONO_CFG_HAS_SPILLUP.
15099  * - merge r68207.
15100  * - merge the ia64 switch changes.
15101  * - optimize mono_regstate2_alloc_int/float.
15102  * - fix the pessimistic handling of variables accessed in exception handler blocks.
15103  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
15104  *   parts of the tree could be separated by other instructions, killing the tree
15105  *   arguments, or stores killing loads etc. Also, should we fold loads into other
15106  *   instructions if the result of the load is used multiple times ?
15107  * - make the REM_IMM optimization in mini-x86.c arch-independent.
15108  * - LAST MERGE: 108395.
15109  * - when returning vtypes in registers, generate IR and append it to the end of the
15110  *   last bb instead of doing it in the epilog.
15111  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
15112  */
15113
15114 /*
15115
15116 NOTES
15117 -----
15118
15119 - When to decompose opcodes:
15120   - earlier: this makes some optimizations hard to implement, since the low level IR
15121   no longer contains the neccessary information. But it is easier to do.
15122   - later: harder to implement, enables more optimizations.
15123 - Branches inside bblocks:
15124   - created when decomposing complex opcodes. 
15125     - branches to another bblock: harmless, but not tracked by the branch 
15126       optimizations, so need to branch to a label at the start of the bblock.
15127     - branches to inside the same bblock: very problematic, trips up the local
15128       reg allocator. Can be fixed by spitting the current bblock, but that is a
15129       complex operation, since some local vregs can become global vregs etc.
15130 - Local/global vregs:
15131   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
15132     local register allocator.
15133   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
15134     structure, created by mono_create_var (). Assigned to hregs or the stack by
15135     the global register allocator.
15136 - When to do optimizations like alu->alu_imm:
15137   - earlier -> saves work later on since the IR will be smaller/simpler
15138   - later -> can work on more instructions
15139 - Handling of valuetypes:
15140   - When a vtype is pushed on the stack, a new temporary is created, an 
15141     instruction computing its address (LDADDR) is emitted and pushed on
15142     the stack. Need to optimize cases when the vtype is used immediately as in
15143     argument passing, stloc etc.
15144 - Instead of the to_end stuff in the old JIT, simply call the function handling
15145   the values on the stack before emitting the last instruction of the bb.
15146 */
15147
15148 #endif /* DISABLE_JIT */