[mono-config] use right type for result of strlen
[mono.git] / mono / mini / method-to-ir.c
1 /*
2  * method-to-ir.c: Convert CIL to the JIT internal representation
3  *
4  * Author:
5  *   Paolo Molaro (lupus@ximian.com)
6  *   Dietmar Maurer (dietmar@ximian.com)
7  *
8  * (C) 2002 Ximian, Inc.
9  * Copyright 2003-2010 Novell, Inc (http://www.novell.com)
10  * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
11  */
12
13 #include <config.h>
14
15 #ifndef DISABLE_JIT
16
17 #include <signal.h>
18
19 #ifdef HAVE_UNISTD_H
20 #include <unistd.h>
21 #endif
22
23 #include <math.h>
24 #include <string.h>
25 #include <ctype.h>
26
27 #ifdef HAVE_SYS_TIME_H
28 #include <sys/time.h>
29 #endif
30
31 #ifdef HAVE_ALLOCA_H
32 #include <alloca.h>
33 #endif
34
35 #include <mono/utils/memcheck.h>
36 #include "mini.h"
37 #include <mono/metadata/abi-details.h>
38 #include <mono/metadata/assembly.h>
39 #include <mono/metadata/attrdefs.h>
40 #include <mono/metadata/loader.h>
41 #include <mono/metadata/tabledefs.h>
42 #include <mono/metadata/class.h>
43 #include <mono/metadata/object.h>
44 #include <mono/metadata/exception.h>
45 #include <mono/metadata/opcodes.h>
46 #include <mono/metadata/mono-endian.h>
47 #include <mono/metadata/tokentype.h>
48 #include <mono/metadata/tabledefs.h>
49 #include <mono/metadata/marshal.h>
50 #include <mono/metadata/debug-helpers.h>
51 #include <mono/metadata/mono-debug.h>
52 #include <mono/metadata/mono-debug-debugger.h>
53 #include <mono/metadata/gc-internal.h>
54 #include <mono/metadata/security-manager.h>
55 #include <mono/metadata/threads-types.h>
56 #include <mono/metadata/security-core-clr.h>
57 #include <mono/metadata/monitor.h>
58 #include <mono/metadata/profiler-private.h>
59 #include <mono/metadata/profiler.h>
60 #include <mono/metadata/debug-mono-symfile.h>
61 #include <mono/utils/mono-compiler.h>
62 #include <mono/utils/mono-memory-model.h>
63 #include <mono/metadata/mono-basic-block.h>
64
65 #include "trace.h"
66
67 #include "ir-emit.h"
68
69 #include "jit-icalls.h"
70 #include "jit.h"
71 #include "debugger-agent.h"
72 #include "seq-points.h"
73
74 #define BRANCH_COST 10
75 #define INLINE_LENGTH_LIMIT 20
76
77 /* These have 'cfg' as an implicit argument */
78 #define INLINE_FAILURE(msg) do {                                                                        \
79         if ((cfg->method != cfg->current_method) && (cfg->current_method->wrapper_type == MONO_WRAPPER_NONE)) { \
80                 inline_failure (cfg, msg);                                                                              \
81                 goto exception_exit;                                                                                    \
82         } \
83         } while (0)
84 #define CHECK_CFG_EXCEPTION do {\
85                 if (cfg->exception_type != MONO_EXCEPTION_NONE) \
86                         goto exception_exit;                                            \
87         } while (0)
88 #define METHOD_ACCESS_FAILURE(method, cmethod) do {                     \
89                 method_access_failure ((cfg), (method), (cmethod));                     \
90                 goto exception_exit;                                                                            \
91         } while (0)
92 #define FIELD_ACCESS_FAILURE(method, field) do {                                        \
93                 field_access_failure ((cfg), (method), (field));                        \
94                 goto exception_exit;    \
95         } while (0)
96 #define GENERIC_SHARING_FAILURE(opcode) do {            \
97                 if (cfg->gshared) {                                                                     \
98                         gshared_failure (cfg, opcode, __FILE__, __LINE__);      \
99                         goto exception_exit;    \
100                 }                       \
101         } while (0)
102 #define GSHAREDVT_FAILURE(opcode) do {          \
103         if (cfg->gsharedvt) {                                                                                           \
104                 gsharedvt_failure (cfg, opcode, __FILE__, __LINE__);                    \
105                 goto exception_exit;                                                                                    \
106         }                                                                                                                                       \
107         } while (0)
108 #define OUT_OF_MEMORY_FAILURE do {      \
109                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_OUT_OF_MEMORY);             \
110                 goto exception_exit;    \
111         } while (0)
112 #define DISABLE_AOT(cfg) do { \
113                 if ((cfg)->verbose_level >= 2)                                            \
114                         printf ("AOT disabled: %s:%d\n", __FILE__, __LINE__);   \
115                 (cfg)->disable_aot = TRUE;                                                        \
116         } while (0)
117 #define LOAD_ERROR do { \
118                 break_on_unverified ();                                                         \
119                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD); \
120                 goto exception_exit;                                                                    \
121         } while (0)
122
123 #define TYPE_LOAD_ERROR(klass) do { \
124                 cfg->exception_ptr = klass; \
125                 LOAD_ERROR;                                     \
126         } while (0)
127
128 #define CHECK_CFG_ERROR do {\
129                 if (!mono_error_ok (&cfg->error)) { \
130                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);        \
131                         goto mono_error_exit; \
132                 } \
133         } while (0)
134
135 /* Determine whenever 'ins' represents a load of the 'this' argument */
136 #define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && ((ins)->opcode == OP_MOVE) && ((ins)->sreg1 == cfg->args [0]->dreg))
137
138 static int ldind_to_load_membase (int opcode);
139 static int stind_to_store_membase (int opcode);
140
141 int mono_op_to_op_imm (int opcode);
142 int mono_op_to_op_imm_noemul (int opcode);
143
144 MONO_API MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
145
146 static int inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
147                                                   guchar *ip, guint real_offset, gboolean inline_always);
148
149 /* helper methods signatures */
150 static MonoMethodSignature *helper_sig_domain_get;
151 static MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline;
152 static MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline;
153 static MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline_llvm;
154 static MonoMethodSignature *helper_sig_monitor_enter_v4_trampoline_llvm;
155
156 /*
157  * Instruction metadata
158  */
159 #ifdef MINI_OP
160 #undef MINI_OP
161 #endif
162 #ifdef MINI_OP3
163 #undef MINI_OP3
164 #endif
165 #define MINI_OP(a,b,dest,src1,src2) dest, src1, src2, ' ',
166 #define MINI_OP3(a,b,dest,src1,src2,src3) dest, src1, src2, src3,
167 #define NONE ' '
168 #define IREG 'i'
169 #define FREG 'f'
170 #define VREG 'v'
171 #define XREG 'x'
172 #if SIZEOF_REGISTER == 8 && SIZEOF_REGISTER == SIZEOF_VOID_P
173 #define LREG IREG
174 #else
175 #define LREG 'l'
176 #endif
177 /* keep in sync with the enum in mini.h */
178 const char
179 ins_info[] = {
180 #include "mini-ops.h"
181 };
182 #undef MINI_OP
183 #undef MINI_OP3
184
185 #define MINI_OP(a,b,dest,src1,src2) ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0)),
186 #define MINI_OP3(a,b,dest,src1,src2,src3) ((src3) != NONE ? 3 : ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0))),
187 /* 
188  * This should contain the index of the last sreg + 1. This is not the same
189  * as the number of sregs for opcodes like IA64_CMP_EQ_IMM.
190  */
191 const gint8 ins_sreg_counts[] = {
192 #include "mini-ops.h"
193 };
194 #undef MINI_OP
195 #undef MINI_OP3
196
197 #define MONO_INIT_VARINFO(vi,id) do { \
198         (vi)->range.first_use.pos.bid = 0xffff; \
199         (vi)->reg = -1; \
200         (vi)->idx = (id); \
201 } while (0)
202
203 guint32
204 mono_alloc_ireg (MonoCompile *cfg)
205 {
206         return alloc_ireg (cfg);
207 }
208
209 guint32
210 mono_alloc_lreg (MonoCompile *cfg)
211 {
212         return alloc_lreg (cfg);
213 }
214
215 guint32
216 mono_alloc_freg (MonoCompile *cfg)
217 {
218         return alloc_freg (cfg);
219 }
220
221 guint32
222 mono_alloc_preg (MonoCompile *cfg)
223 {
224         return alloc_preg (cfg);
225 }
226
227 guint32
228 mono_alloc_dreg (MonoCompile *cfg, MonoStackType stack_type)
229 {
230         return alloc_dreg (cfg, stack_type);
231 }
232
233 /*
234  * mono_alloc_ireg_ref:
235  *
236  *   Allocate an IREG, and mark it as holding a GC ref.
237  */
238 guint32
239 mono_alloc_ireg_ref (MonoCompile *cfg)
240 {
241         return alloc_ireg_ref (cfg);
242 }
243
244 /*
245  * mono_alloc_ireg_mp:
246  *
247  *   Allocate an IREG, and mark it as holding a managed pointer.
248  */
249 guint32
250 mono_alloc_ireg_mp (MonoCompile *cfg)
251 {
252         return alloc_ireg_mp (cfg);
253 }
254
255 /*
256  * mono_alloc_ireg_copy:
257  *
258  *   Allocate an IREG with the same GC type as VREG.
259  */
260 guint32
261 mono_alloc_ireg_copy (MonoCompile *cfg, guint32 vreg)
262 {
263         if (vreg_is_ref (cfg, vreg))
264                 return alloc_ireg_ref (cfg);
265         else if (vreg_is_mp (cfg, vreg))
266                 return alloc_ireg_mp (cfg);
267         else
268                 return alloc_ireg (cfg);
269 }
270
271 guint
272 mono_type_to_regmove (MonoCompile *cfg, MonoType *type)
273 {
274         if (type->byref)
275                 return OP_MOVE;
276
277         type = mini_get_underlying_type (type);
278 handle_enum:
279         switch (type->type) {
280         case MONO_TYPE_I1:
281         case MONO_TYPE_U1:
282                 return OP_MOVE;
283         case MONO_TYPE_I2:
284         case MONO_TYPE_U2:
285                 return OP_MOVE;
286         case MONO_TYPE_I4:
287         case MONO_TYPE_U4:
288                 return OP_MOVE;
289         case MONO_TYPE_I:
290         case MONO_TYPE_U:
291         case MONO_TYPE_PTR:
292         case MONO_TYPE_FNPTR:
293                 return OP_MOVE;
294         case MONO_TYPE_CLASS:
295         case MONO_TYPE_STRING:
296         case MONO_TYPE_OBJECT:
297         case MONO_TYPE_SZARRAY:
298         case MONO_TYPE_ARRAY:    
299                 return OP_MOVE;
300         case MONO_TYPE_I8:
301         case MONO_TYPE_U8:
302 #if SIZEOF_REGISTER == 8
303                 return OP_MOVE;
304 #else
305                 return OP_LMOVE;
306 #endif
307         case MONO_TYPE_R4:
308                 return cfg->r4fp ? OP_RMOVE : OP_FMOVE;
309         case MONO_TYPE_R8:
310                 return OP_FMOVE;
311         case MONO_TYPE_VALUETYPE:
312                 if (type->data.klass->enumtype) {
313                         type = mono_class_enum_basetype (type->data.klass);
314                         goto handle_enum;
315                 }
316                 if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
317                         return OP_XMOVE;
318                 return OP_VMOVE;
319         case MONO_TYPE_TYPEDBYREF:
320                 return OP_VMOVE;
321         case MONO_TYPE_GENERICINST:
322                 type = &type->data.generic_class->container_class->byval_arg;
323                 goto handle_enum;
324         case MONO_TYPE_VAR:
325         case MONO_TYPE_MVAR:
326                 g_assert (cfg->gshared);
327                 if (mini_type_var_is_vt (type))
328                         return OP_VMOVE;
329                 else
330                         return mono_type_to_regmove (cfg, mini_get_underlying_type (type));
331         default:
332                 g_error ("unknown type 0x%02x in type_to_regstore", type->type);
333         }
334         return -1;
335 }
336
337 void
338 mono_print_bb (MonoBasicBlock *bb, const char *msg)
339 {
340         int i;
341         MonoInst *tree;
342
343         printf ("\n%s %d: [IN: ", msg, bb->block_num);
344         for (i = 0; i < bb->in_count; ++i)
345                 printf (" BB%d(%d)", bb->in_bb [i]->block_num, bb->in_bb [i]->dfn);
346         printf (", OUT: ");
347         for (i = 0; i < bb->out_count; ++i)
348                 printf (" BB%d(%d)", bb->out_bb [i]->block_num, bb->out_bb [i]->dfn);
349         printf (" ]\n");
350         for (tree = bb->code; tree; tree = tree->next)
351                 mono_print_ins_index (-1, tree);
352 }
353
354 void
355 mono_create_helper_signatures (void)
356 {
357         helper_sig_domain_get = mono_create_icall_signature ("ptr");
358         helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
359         helper_sig_monitor_enter_exit_trampoline = mono_create_icall_signature ("void");
360         helper_sig_monitor_enter_exit_trampoline_llvm = mono_create_icall_signature ("void object");
361         helper_sig_monitor_enter_v4_trampoline_llvm = mono_create_icall_signature ("void object ptr");
362 }
363
364 static MONO_NEVER_INLINE void
365 break_on_unverified (void)
366 {
367         if (mini_get_debug_options ()->break_on_unverified)
368                 G_BREAKPOINT ();
369 }
370
371 static MONO_NEVER_INLINE void
372 method_access_failure (MonoCompile *cfg, MonoMethod *method, MonoMethod *cil_method)
373 {
374         char *method_fname = mono_method_full_name (method, TRUE);
375         char *cil_method_fname = mono_method_full_name (cil_method, TRUE);
376         mono_cfg_set_exception (cfg, MONO_EXCEPTION_METHOD_ACCESS);
377         cfg->exception_message = g_strdup_printf ("Method `%s' is inaccessible from method `%s'\n", cil_method_fname, method_fname);
378         g_free (method_fname);
379         g_free (cil_method_fname);
380 }
381
382 static MONO_NEVER_INLINE void
383 field_access_failure (MonoCompile *cfg, MonoMethod *method, MonoClassField *field)
384 {
385         char *method_fname = mono_method_full_name (method, TRUE);
386         char *field_fname = mono_field_full_name (field);
387         mono_cfg_set_exception (cfg, MONO_EXCEPTION_FIELD_ACCESS);
388         cfg->exception_message = g_strdup_printf ("Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname);
389         g_free (method_fname);
390         g_free (field_fname);
391 }
392
393 static MONO_NEVER_INLINE void
394 inline_failure (MonoCompile *cfg, const char *msg)
395 {
396         if (cfg->verbose_level >= 2)
397                 printf ("inline failed: %s\n", msg);
398         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INLINE_FAILED);
399 }
400
401 static MONO_NEVER_INLINE void
402 gshared_failure (MonoCompile *cfg, int opcode, const char *file, int line)
403 {
404         if (cfg->verbose_level > 2)                                                                                     \
405                 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);
406         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
407 }
408
409 static MONO_NEVER_INLINE void
410 gsharedvt_failure (MonoCompile *cfg, int opcode, const char *file, int line)
411 {
412         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);
413         if (cfg->verbose_level >= 2)
414                 printf ("%s\n", cfg->exception_message);
415         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
416 }
417
418 /*
419  * When using gsharedvt, some instatiations might be verifiable, and some might be not. i.e. 
420  * foo<T> (int i) { ldarg.0; box T; }
421  */
422 #define UNVERIFIED do { \
423         if (cfg->gsharedvt) { \
424                 if (cfg->verbose_level > 2)                                                                     \
425                         printf ("gsharedvt method failed to verify, falling back to instantiation.\n"); \
426                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED); \
427                 goto exception_exit;                                                                                    \
428         }                                                                                                                                       \
429         break_on_unverified ();                                                                                         \
430         goto unverified;                                                                                                        \
431 } while (0)
432
433 #define GET_BBLOCK(cfg,tblock,ip) do {  \
434                 (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
435                 if (!(tblock)) {        \
436                         if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
437             NEW_BBLOCK (cfg, (tblock)); \
438                         (tblock)->cil_code = (ip);      \
439                         ADD_BBLOCK (cfg, (tblock));     \
440                 } \
441         } while (0)
442
443 #if defined(TARGET_X86) || defined(TARGET_AMD64)
444 #define EMIT_NEW_X86_LEA(cfg,dest,sr1,sr2,shift,imm) do { \
445                 MONO_INST_NEW (cfg, dest, OP_X86_LEA); \
446                 (dest)->dreg = alloc_ireg_mp ((cfg)); \
447                 (dest)->sreg1 = (sr1); \
448                 (dest)->sreg2 = (sr2); \
449                 (dest)->inst_imm = (imm); \
450                 (dest)->backend.shift_amount = (shift); \
451                 MONO_ADD_INS ((cfg)->cbb, (dest)); \
452         } while (0)
453 #endif
454
455 /* Emit conversions so both operands of a binary opcode are of the same type */
456 static void
457 add_widen_op (MonoCompile *cfg, MonoInst *ins, MonoInst **arg1_ref, MonoInst **arg2_ref)
458 {
459         MonoInst *arg1 = *arg1_ref;
460         MonoInst *arg2 = *arg2_ref;
461
462         if (cfg->r4fp &&
463                 ((arg1->type == STACK_R4 && arg2->type == STACK_R8) ||
464                  (arg1->type == STACK_R8 && arg2->type == STACK_R4))) {
465                 MonoInst *conv;
466
467                 /* Mixing r4/r8 is allowed by the spec */
468                 if (arg1->type == STACK_R4) {
469                         int dreg = alloc_freg (cfg);
470
471                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg1->dreg);
472                         conv->type = STACK_R8;
473                         ins->sreg1 = dreg;
474                         *arg1_ref = conv;
475                 }
476                 if (arg2->type == STACK_R4) {
477                         int dreg = alloc_freg (cfg);
478
479                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg2->dreg);
480                         conv->type = STACK_R8;
481                         ins->sreg2 = dreg;
482                         *arg2_ref = conv;
483                 }
484         }
485
486 #if SIZEOF_REGISTER == 8
487         /* FIXME: Need to add many more cases */
488         if ((arg1)->type == STACK_PTR && (arg2)->type == STACK_I4) {
489                 MonoInst *widen;
490
491                 int dr = alloc_preg (cfg);
492                 EMIT_NEW_UNALU (cfg, widen, OP_SEXT_I4, dr, (arg2)->dreg);
493                 (ins)->sreg2 = widen->dreg;
494         }
495 #endif
496 }
497
498 #define ADD_BINOP(op) do {      \
499                 MONO_INST_NEW (cfg, ins, (op)); \
500                 sp -= 2;        \
501                 ins->sreg1 = sp [0]->dreg;      \
502                 ins->sreg2 = sp [1]->dreg;      \
503                 type_from_op (cfg, ins, sp [0], sp [1]);        \
504                 CHECK_TYPE (ins);       \
505                 /* Have to insert a widening op */               \
506         add_widen_op (cfg, ins, &sp [0], &sp [1]);               \
507         ins->dreg = alloc_dreg ((cfg), (ins)->type); \
508         MONO_ADD_INS ((cfg)->cbb, (ins)); \
509         *sp++ = mono_decompose_opcode ((cfg), (ins));   \
510         } while (0)
511
512 #define ADD_UNOP(op) do {       \
513                 MONO_INST_NEW (cfg, ins, (op)); \
514                 sp--;   \
515                 ins->sreg1 = sp [0]->dreg;      \
516                 type_from_op (cfg, ins, sp [0], NULL);  \
517                 CHECK_TYPE (ins);       \
518         (ins)->dreg = alloc_dreg ((cfg), (ins)->type); \
519         MONO_ADD_INS ((cfg)->cbb, (ins)); \
520                 *sp++ = mono_decompose_opcode (cfg, ins);       \
521         } while (0)
522
523 #define ADD_BINCOND(next_block) do {    \
524                 MonoInst *cmp;  \
525                 sp -= 2; \
526                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
527                 cmp->sreg1 = sp [0]->dreg;      \
528                 cmp->sreg2 = sp [1]->dreg;      \
529                 type_from_op (cfg, cmp, sp [0], sp [1]);        \
530                 CHECK_TYPE (cmp);       \
531                 add_widen_op (cfg, cmp, &sp [0], &sp [1]);                                              \
532                 type_from_op (cfg, ins, sp [0], sp [1]);                                                        \
533                 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);      \
534                 GET_BBLOCK (cfg, tblock, target);               \
535                 link_bblock (cfg, cfg->cbb, tblock);    \
536                 ins->inst_true_bb = tblock;     \
537                 if ((next_block)) {     \
538                         link_bblock (cfg, cfg->cbb, (next_block));      \
539                         ins->inst_false_bb = (next_block);      \
540                         start_new_bblock = 1;   \
541                 } else {        \
542                         GET_BBLOCK (cfg, tblock, ip);           \
543                         link_bblock (cfg, cfg->cbb, tblock);    \
544                         ins->inst_false_bb = tblock;    \
545                         start_new_bblock = 2;   \
546                 }       \
547                 if (sp != stack_start) {                                                                        \
548                     handle_stack_args (cfg, stack_start, sp - stack_start); \
549                         CHECK_UNVERIFIABLE (cfg); \
550                 } \
551         MONO_ADD_INS (cfg->cbb, cmp); \
552                 MONO_ADD_INS (cfg->cbb, ins);   \
553         } while (0)
554
555 /* *
556  * link_bblock: Links two basic blocks
557  *
558  * links two basic blocks in the control flow graph, the 'from'
559  * argument is the starting block and the 'to' argument is the block
560  * the control flow ends to after 'from'.
561  */
562 static void
563 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
564 {
565         MonoBasicBlock **newa;
566         int i, found;
567
568 #if 0
569         if (from->cil_code) {
570                 if (to->cil_code)
571                         printf ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
572                 else
573                         printf ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
574         } else {
575                 if (to->cil_code)
576                         printf ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
577                 else
578                         printf ("edge from entry to exit\n");
579         }
580 #endif
581
582         found = FALSE;
583         for (i = 0; i < from->out_count; ++i) {
584                 if (to == from->out_bb [i]) {
585                         found = TRUE;
586                         break;
587                 }
588         }
589         if (!found) {
590                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
591                 for (i = 0; i < from->out_count; ++i) {
592                         newa [i] = from->out_bb [i];
593                 }
594                 newa [i] = to;
595                 from->out_count++;
596                 from->out_bb = newa;
597         }
598
599         found = FALSE;
600         for (i = 0; i < to->in_count; ++i) {
601                 if (from == to->in_bb [i]) {
602                         found = TRUE;
603                         break;
604                 }
605         }
606         if (!found) {
607                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
608                 for (i = 0; i < to->in_count; ++i) {
609                         newa [i] = to->in_bb [i];
610                 }
611                 newa [i] = from;
612                 to->in_count++;
613                 to->in_bb = newa;
614         }
615 }
616
617 void
618 mono_link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
619 {
620         link_bblock (cfg, from, to);
621 }
622
623 /**
624  * mono_find_block_region:
625  *
626  *   We mark each basic block with a region ID. We use that to avoid BB
627  *   optimizations when blocks are in different regions.
628  *
629  * Returns:
630  *   A region token that encodes where this region is, and information
631  *   about the clause owner for this block.
632  *
633  *   The region encodes the try/catch/filter clause that owns this block
634  *   as well as the type.  -1 is a special value that represents a block
635  *   that is in none of try/catch/filter.
636  */
637 static int
638 mono_find_block_region (MonoCompile *cfg, int offset)
639 {
640         MonoMethodHeader *header = cfg->header;
641         MonoExceptionClause *clause;
642         int i;
643
644         for (i = 0; i < header->num_clauses; ++i) {
645                 clause = &header->clauses [i];
646                 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
647                     (offset < (clause->handler_offset)))
648                         return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
649                            
650                 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
651                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
652                                 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
653                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
654                                 return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
655                         else
656                                 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
657                 }
658         }
659         for (i = 0; i < header->num_clauses; ++i) {
660                 clause = &header->clauses [i];
661
662                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
663                         return ((i + 1) << 8) | clause->flags;
664         }
665
666         return -1;
667 }
668
669 static GList*
670 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
671 {
672         MonoMethodHeader *header = cfg->header;
673         MonoExceptionClause *clause;
674         int i;
675         GList *res = NULL;
676
677         for (i = 0; i < header->num_clauses; ++i) {
678                 clause = &header->clauses [i];
679                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
680                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
681                         if (clause->flags == type)
682                                 res = g_list_append (res, clause);
683                 }
684         }
685         return res;
686 }
687
688 static void
689 mono_create_spvar_for_region (MonoCompile *cfg, int region)
690 {
691         MonoInst *var;
692
693         var = g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
694         if (var)
695                 return;
696
697         var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
698         /* prevent it from being register allocated */
699         var->flags |= MONO_INST_VOLATILE;
700
701         g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
702 }
703
704 MonoInst *
705 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
706 {
707         return g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
708 }
709
710 static MonoInst*
711 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
712 {
713         MonoInst *var;
714
715         var = g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
716         if (var)
717                 return var;
718
719         var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
720         /* prevent it from being register allocated */
721         var->flags |= MONO_INST_VOLATILE;
722
723         g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
724
725         return var;
726 }
727
728 /*
729  * Returns the type used in the eval stack when @type is loaded.
730  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
731  */
732 void
733 type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
734 {
735         MonoClass *klass;
736
737         type = mini_get_underlying_type (type);
738         inst->klass = klass = mono_class_from_mono_type (type);
739         if (type->byref) {
740                 inst->type = STACK_MP;
741                 return;
742         }
743
744 handle_enum:
745         switch (type->type) {
746         case MONO_TYPE_VOID:
747                 inst->type = STACK_INV;
748                 return;
749         case MONO_TYPE_I1:
750         case MONO_TYPE_U1:
751         case MONO_TYPE_I2:
752         case MONO_TYPE_U2:
753         case MONO_TYPE_I4:
754         case MONO_TYPE_U4:
755                 inst->type = STACK_I4;
756                 return;
757         case MONO_TYPE_I:
758         case MONO_TYPE_U:
759         case MONO_TYPE_PTR:
760         case MONO_TYPE_FNPTR:
761                 inst->type = STACK_PTR;
762                 return;
763         case MONO_TYPE_CLASS:
764         case MONO_TYPE_STRING:
765         case MONO_TYPE_OBJECT:
766         case MONO_TYPE_SZARRAY:
767         case MONO_TYPE_ARRAY:    
768                 inst->type = STACK_OBJ;
769                 return;
770         case MONO_TYPE_I8:
771         case MONO_TYPE_U8:
772                 inst->type = STACK_I8;
773                 return;
774         case MONO_TYPE_R4:
775                 inst->type = cfg->r4_stack_type;
776                 break;
777         case MONO_TYPE_R8:
778                 inst->type = STACK_R8;
779                 return;
780         case MONO_TYPE_VALUETYPE:
781                 if (type->data.klass->enumtype) {
782                         type = mono_class_enum_basetype (type->data.klass);
783                         goto handle_enum;
784                 } else {
785                         inst->klass = klass;
786                         inst->type = STACK_VTYPE;
787                         return;
788                 }
789         case MONO_TYPE_TYPEDBYREF:
790                 inst->klass = mono_defaults.typed_reference_class;
791                 inst->type = STACK_VTYPE;
792                 return;
793         case MONO_TYPE_GENERICINST:
794                 type = &type->data.generic_class->container_class->byval_arg;
795                 goto handle_enum;
796         case MONO_TYPE_VAR:
797         case MONO_TYPE_MVAR:
798                 g_assert (cfg->gshared);
799                 if (mini_is_gsharedvt_type (type)) {
800                         g_assert (cfg->gsharedvt);
801                         inst->type = STACK_VTYPE;
802                 } else {
803                         type_to_eval_stack_type (cfg, mini_get_underlying_type (type), inst);
804                 }
805                 return;
806         default:
807                 g_error ("unknown type 0x%02x in eval stack type", type->type);
808         }
809 }
810
811 /*
812  * The following tables are used to quickly validate the IL code in type_from_op ().
813  */
814 static const char
815 bin_num_table [STACK_MAX] [STACK_MAX] = {
816         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
817         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
818         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
819         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
820         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV, STACK_R8},
821         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
822         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
823         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
824         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4}
825 };
826
827 static const char 
828 neg_table [] = {
829         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4
830 };
831
832 /* reduce the size of this table */
833 static const char
834 bin_int_table [STACK_MAX] [STACK_MAX] = {
835         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
836         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
837         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
838         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
839         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
840         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
841         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
842         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
843 };
844
845 static const char
846 bin_comp_table [STACK_MAX] [STACK_MAX] = {
847 /*      Inv i  L  p  F  &  O  vt r4 */
848         {0},
849         {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
850         {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
851         {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
852         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* F, R8 */
853         {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
854         {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
855         {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
856         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* r, r4 */
857 };
858
859 /* reduce the size of this table */
860 static const char
861 shift_table [STACK_MAX] [STACK_MAX] = {
862         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
863         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
864         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
865         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
866         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
867         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
868         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
869         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
870 };
871
872 /*
873  * Tables to map from the non-specific opcode to the matching
874  * type-specific opcode.
875  */
876 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
877 static const guint16
878 binops_op_map [STACK_MAX] = {
879         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
880 };
881
882 /* handles from CEE_NEG to CEE_CONV_U8 */
883 static const guint16
884 unops_op_map [STACK_MAX] = {
885         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
886 };
887
888 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
889 static const guint16
890 ovfops_op_map [STACK_MAX] = {
891         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
892 };
893
894 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
895 static const guint16
896 ovf2ops_op_map [STACK_MAX] = {
897         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
898 };
899
900 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
901 static const guint16
902 ovf3ops_op_map [STACK_MAX] = {
903         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
904 };
905
906 /* handles from CEE_BEQ to CEE_BLT_UN */
907 static const guint16
908 beqops_op_map [STACK_MAX] = {
909         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
910 };
911
912 /* handles from CEE_CEQ to CEE_CLT_UN */
913 static const guint16
914 ceqops_op_map [STACK_MAX] = {
915         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
916 };
917
918 /*
919  * Sets ins->type (the type on the eval stack) according to the
920  * type of the opcode and the arguments to it.
921  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
922  *
923  * FIXME: this function sets ins->type unconditionally in some cases, but
924  * it should set it to invalid for some types (a conv.x on an object)
925  */
926 static void
927 type_from_op (MonoCompile *cfg, MonoInst *ins, MonoInst *src1, MonoInst *src2)
928 {
929         switch (ins->opcode) {
930         /* binops */
931         case CEE_ADD:
932         case CEE_SUB:
933         case CEE_MUL:
934         case CEE_DIV:
935         case CEE_REM:
936                 /* FIXME: check unverifiable args for STACK_MP */
937                 ins->type = bin_num_table [src1->type] [src2->type];
938                 ins->opcode += binops_op_map [ins->type];
939                 break;
940         case CEE_DIV_UN:
941         case CEE_REM_UN:
942         case CEE_AND:
943         case CEE_OR:
944         case CEE_XOR:
945                 ins->type = bin_int_table [src1->type] [src2->type];
946                 ins->opcode += binops_op_map [ins->type];
947                 break;
948         case CEE_SHL:
949         case CEE_SHR:
950         case CEE_SHR_UN:
951                 ins->type = shift_table [src1->type] [src2->type];
952                 ins->opcode += binops_op_map [ins->type];
953                 break;
954         case OP_COMPARE:
955         case OP_LCOMPARE:
956         case OP_ICOMPARE:
957                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
958                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
959                         ins->opcode = OP_LCOMPARE;
960                 else if (src1->type == STACK_R4)
961                         ins->opcode = OP_RCOMPARE;
962                 else if (src1->type == STACK_R8)
963                         ins->opcode = OP_FCOMPARE;
964                 else
965                         ins->opcode = OP_ICOMPARE;
966                 break;
967         case OP_ICOMPARE_IMM:
968                 ins->type = bin_comp_table [src1->type] [src1->type] ? STACK_I4 : STACK_INV;
969                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
970                         ins->opcode = OP_LCOMPARE_IMM;          
971                 break;
972         case CEE_BEQ:
973         case CEE_BGE:
974         case CEE_BGT:
975         case CEE_BLE:
976         case CEE_BLT:
977         case CEE_BNE_UN:
978         case CEE_BGE_UN:
979         case CEE_BGT_UN:
980         case CEE_BLE_UN:
981         case CEE_BLT_UN:
982                 ins->opcode += beqops_op_map [src1->type];
983                 break;
984         case OP_CEQ:
985                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
986                 ins->opcode += ceqops_op_map [src1->type];
987                 break;
988         case OP_CGT:
989         case OP_CGT_UN:
990         case OP_CLT:
991         case OP_CLT_UN:
992                 ins->type = (bin_comp_table [src1->type] [src2->type] & 1) ? STACK_I4: STACK_INV;
993                 ins->opcode += ceqops_op_map [src1->type];
994                 break;
995         /* unops */
996         case CEE_NEG:
997                 ins->type = neg_table [src1->type];
998                 ins->opcode += unops_op_map [ins->type];
999                 break;
1000         case CEE_NOT:
1001                 if (src1->type >= STACK_I4 && src1->type <= STACK_PTR)
1002                         ins->type = src1->type;
1003                 else
1004                         ins->type = STACK_INV;
1005                 ins->opcode += unops_op_map [ins->type];
1006                 break;
1007         case CEE_CONV_I1:
1008         case CEE_CONV_I2:
1009         case CEE_CONV_I4:
1010         case CEE_CONV_U4:
1011                 ins->type = STACK_I4;
1012                 ins->opcode += unops_op_map [src1->type];
1013                 break;
1014         case CEE_CONV_R_UN:
1015                 ins->type = STACK_R8;
1016                 switch (src1->type) {
1017                 case STACK_I4:
1018                 case STACK_PTR:
1019                         ins->opcode = OP_ICONV_TO_R_UN;
1020                         break;
1021                 case STACK_I8:
1022                         ins->opcode = OP_LCONV_TO_R_UN; 
1023                         break;
1024                 }
1025                 break;
1026         case CEE_CONV_OVF_I1:
1027         case CEE_CONV_OVF_U1:
1028         case CEE_CONV_OVF_I2:
1029         case CEE_CONV_OVF_U2:
1030         case CEE_CONV_OVF_I4:
1031         case CEE_CONV_OVF_U4:
1032                 ins->type = STACK_I4;
1033                 ins->opcode += ovf3ops_op_map [src1->type];
1034                 break;
1035         case CEE_CONV_OVF_I_UN:
1036         case CEE_CONV_OVF_U_UN:
1037                 ins->type = STACK_PTR;
1038                 ins->opcode += ovf2ops_op_map [src1->type];
1039                 break;
1040         case CEE_CONV_OVF_I1_UN:
1041         case CEE_CONV_OVF_I2_UN:
1042         case CEE_CONV_OVF_I4_UN:
1043         case CEE_CONV_OVF_U1_UN:
1044         case CEE_CONV_OVF_U2_UN:
1045         case CEE_CONV_OVF_U4_UN:
1046                 ins->type = STACK_I4;
1047                 ins->opcode += ovf2ops_op_map [src1->type];
1048                 break;
1049         case CEE_CONV_U:
1050                 ins->type = STACK_PTR;
1051                 switch (src1->type) {
1052                 case STACK_I4:
1053                         ins->opcode = OP_ICONV_TO_U;
1054                         break;
1055                 case STACK_PTR:
1056                 case STACK_MP:
1057 #if SIZEOF_VOID_P == 8
1058                         ins->opcode = OP_LCONV_TO_U;
1059 #else
1060                         ins->opcode = OP_MOVE;
1061 #endif
1062                         break;
1063                 case STACK_I8:
1064                         ins->opcode = OP_LCONV_TO_U;
1065                         break;
1066                 case STACK_R8:
1067                         ins->opcode = OP_FCONV_TO_U;
1068                         break;
1069                 }
1070                 break;
1071         case CEE_CONV_I8:
1072         case CEE_CONV_U8:
1073                 ins->type = STACK_I8;
1074                 ins->opcode += unops_op_map [src1->type];
1075                 break;
1076         case CEE_CONV_OVF_I8:
1077         case CEE_CONV_OVF_U8:
1078                 ins->type = STACK_I8;
1079                 ins->opcode += ovf3ops_op_map [src1->type];
1080                 break;
1081         case CEE_CONV_OVF_U8_UN:
1082         case CEE_CONV_OVF_I8_UN:
1083                 ins->type = STACK_I8;
1084                 ins->opcode += ovf2ops_op_map [src1->type];
1085                 break;
1086         case CEE_CONV_R4:
1087                 ins->type = cfg->r4_stack_type;
1088                 ins->opcode += unops_op_map [src1->type];
1089                 break;
1090         case CEE_CONV_R8:
1091                 ins->type = STACK_R8;
1092                 ins->opcode += unops_op_map [src1->type];
1093                 break;
1094         case OP_CKFINITE:
1095                 ins->type = STACK_R8;           
1096                 break;
1097         case CEE_CONV_U2:
1098         case CEE_CONV_U1:
1099                 ins->type = STACK_I4;
1100                 ins->opcode += ovfops_op_map [src1->type];
1101                 break;
1102         case CEE_CONV_I:
1103         case CEE_CONV_OVF_I:
1104         case CEE_CONV_OVF_U:
1105                 ins->type = STACK_PTR;
1106                 ins->opcode += ovfops_op_map [src1->type];
1107                 break;
1108         case CEE_ADD_OVF:
1109         case CEE_ADD_OVF_UN:
1110         case CEE_MUL_OVF:
1111         case CEE_MUL_OVF_UN:
1112         case CEE_SUB_OVF:
1113         case CEE_SUB_OVF_UN:
1114                 ins->type = bin_num_table [src1->type] [src2->type];
1115                 ins->opcode += ovfops_op_map [src1->type];
1116                 if (ins->type == STACK_R8)
1117                         ins->type = STACK_INV;
1118                 break;
1119         case OP_LOAD_MEMBASE:
1120                 ins->type = STACK_PTR;
1121                 break;
1122         case OP_LOADI1_MEMBASE:
1123         case OP_LOADU1_MEMBASE:
1124         case OP_LOADI2_MEMBASE:
1125         case OP_LOADU2_MEMBASE:
1126         case OP_LOADI4_MEMBASE:
1127         case OP_LOADU4_MEMBASE:
1128                 ins->type = STACK_PTR;
1129                 break;
1130         case OP_LOADI8_MEMBASE:
1131                 ins->type = STACK_I8;
1132                 break;
1133         case OP_LOADR4_MEMBASE:
1134                 ins->type = cfg->r4_stack_type;
1135                 break;
1136         case OP_LOADR8_MEMBASE:
1137                 ins->type = STACK_R8;
1138                 break;
1139         default:
1140                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1141                 break;
1142         }
1143
1144         if (ins->type == STACK_MP)
1145                 ins->klass = mono_defaults.object_class;
1146 }
1147
1148 static const char 
1149 ldind_type [] = {
1150         STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
1151 };
1152
1153 #if 0
1154
1155 static const char
1156 param_table [STACK_MAX] [STACK_MAX] = {
1157         {0},
1158 };
1159
1160 static int
1161 check_values_to_signature (MonoInst *args, MonoType *this, MonoMethodSignature *sig) {
1162         int i;
1163
1164         if (sig->hasthis) {
1165                 switch (args->type) {
1166                 case STACK_I4:
1167                 case STACK_I8:
1168                 case STACK_R8:
1169                 case STACK_VTYPE:
1170                 case STACK_INV:
1171                         return 0;
1172                 }
1173                 args++;
1174         }
1175         for (i = 0; i < sig->param_count; ++i) {
1176                 switch (args [i].type) {
1177                 case STACK_INV:
1178                         return 0;
1179                 case STACK_MP:
1180                         if (!sig->params [i]->byref)
1181                                 return 0;
1182                         continue;
1183                 case STACK_OBJ:
1184                         if (sig->params [i]->byref)
1185                                 return 0;
1186                         switch (sig->params [i]->type) {
1187                         case MONO_TYPE_CLASS:
1188                         case MONO_TYPE_STRING:
1189                         case MONO_TYPE_OBJECT:
1190                         case MONO_TYPE_SZARRAY:
1191                         case MONO_TYPE_ARRAY:
1192                                 break;
1193                         default:
1194                                 return 0;
1195                         }
1196                         continue;
1197                 case STACK_R8:
1198                         if (sig->params [i]->byref)
1199                                 return 0;
1200                         if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1201                                 return 0;
1202                         continue;
1203                 case STACK_PTR:
1204                 case STACK_I4:
1205                 case STACK_I8:
1206                 case STACK_VTYPE:
1207                         break;
1208                 }
1209                 /*if (!param_table [args [i].type] [sig->params [i]->type])
1210                         return 0;*/
1211         }
1212         return 1;
1213 }
1214 #endif
1215
1216 /*
1217  * When we need a pointer to the current domain many times in a method, we
1218  * call mono_domain_get() once and we store the result in a local variable.
1219  * This function returns the variable that represents the MonoDomain*.
1220  */
1221 inline static MonoInst *
1222 mono_get_domainvar (MonoCompile *cfg)
1223 {
1224         if (!cfg->domainvar)
1225                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1226         return cfg->domainvar;
1227 }
1228
1229 /*
1230  * The got_var contains the address of the Global Offset Table when AOT 
1231  * compiling.
1232  */
1233 MonoInst *
1234 mono_get_got_var (MonoCompile *cfg)
1235 {
1236 #ifdef MONO_ARCH_NEED_GOT_VAR
1237         if (!cfg->compile_aot)
1238                 return NULL;
1239         if (!cfg->got_var) {
1240                 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1241         }
1242         return cfg->got_var;
1243 #else
1244         return NULL;
1245 #endif
1246 }
1247
1248 static MonoInst *
1249 mono_get_vtable_var (MonoCompile *cfg)
1250 {
1251         g_assert (cfg->gshared);
1252
1253         if (!cfg->rgctx_var) {
1254                 cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1255                 /* force the var to be stack allocated */
1256                 cfg->rgctx_var->flags |= MONO_INST_VOLATILE;
1257         }
1258
1259         return cfg->rgctx_var;
1260 }
1261
1262 static MonoType*
1263 type_from_stack_type (MonoInst *ins) {
1264         switch (ins->type) {
1265         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1266         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1267         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1268         case STACK_R4: return &mono_defaults.single_class->byval_arg;
1269         case STACK_R8: return &mono_defaults.double_class->byval_arg;
1270         case STACK_MP:
1271                 return &ins->klass->this_arg;
1272         case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1273         case STACK_VTYPE: return &ins->klass->byval_arg;
1274         default:
1275                 g_error ("stack type %d to monotype not handled\n", ins->type);
1276         }
1277         return NULL;
1278 }
1279
1280 static G_GNUC_UNUSED int
1281 type_to_stack_type (MonoCompile *cfg, MonoType *t)
1282 {
1283         t = mono_type_get_underlying_type (t);
1284         switch (t->type) {
1285         case MONO_TYPE_I1:
1286         case MONO_TYPE_U1:
1287         case MONO_TYPE_I2:
1288         case MONO_TYPE_U2:
1289         case MONO_TYPE_I4:
1290         case MONO_TYPE_U4:
1291                 return STACK_I4;
1292         case MONO_TYPE_I:
1293         case MONO_TYPE_U:
1294         case MONO_TYPE_PTR:
1295         case MONO_TYPE_FNPTR:
1296                 return STACK_PTR;
1297         case MONO_TYPE_CLASS:
1298         case MONO_TYPE_STRING:
1299         case MONO_TYPE_OBJECT:
1300         case MONO_TYPE_SZARRAY:
1301         case MONO_TYPE_ARRAY:    
1302                 return STACK_OBJ;
1303         case MONO_TYPE_I8:
1304         case MONO_TYPE_U8:
1305                 return STACK_I8;
1306         case MONO_TYPE_R4:
1307                 return cfg->r4_stack_type;
1308         case MONO_TYPE_R8:
1309                 return STACK_R8;
1310         case MONO_TYPE_VALUETYPE:
1311         case MONO_TYPE_TYPEDBYREF:
1312                 return STACK_VTYPE;
1313         case MONO_TYPE_GENERICINST:
1314                 if (mono_type_generic_inst_is_valuetype (t))
1315                         return STACK_VTYPE;
1316                 else
1317                         return STACK_OBJ;
1318                 break;
1319         default:
1320                 g_assert_not_reached ();
1321         }
1322
1323         return -1;
1324 }
1325
1326 static MonoClass*
1327 array_access_to_klass (int opcode)
1328 {
1329         switch (opcode) {
1330         case CEE_LDELEM_U1:
1331                 return mono_defaults.byte_class;
1332         case CEE_LDELEM_U2:
1333                 return mono_defaults.uint16_class;
1334         case CEE_LDELEM_I:
1335         case CEE_STELEM_I:
1336                 return mono_defaults.int_class;
1337         case CEE_LDELEM_I1:
1338         case CEE_STELEM_I1:
1339                 return mono_defaults.sbyte_class;
1340         case CEE_LDELEM_I2:
1341         case CEE_STELEM_I2:
1342                 return mono_defaults.int16_class;
1343         case CEE_LDELEM_I4:
1344         case CEE_STELEM_I4:
1345                 return mono_defaults.int32_class;
1346         case CEE_LDELEM_U4:
1347                 return mono_defaults.uint32_class;
1348         case CEE_LDELEM_I8:
1349         case CEE_STELEM_I8:
1350                 return mono_defaults.int64_class;
1351         case CEE_LDELEM_R4:
1352         case CEE_STELEM_R4:
1353                 return mono_defaults.single_class;
1354         case CEE_LDELEM_R8:
1355         case CEE_STELEM_R8:
1356                 return mono_defaults.double_class;
1357         case CEE_LDELEM_REF:
1358         case CEE_STELEM_REF:
1359                 return mono_defaults.object_class;
1360         default:
1361                 g_assert_not_reached ();
1362         }
1363         return NULL;
1364 }
1365
1366 /*
1367  * We try to share variables when possible
1368  */
1369 static MonoInst *
1370 mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
1371 {
1372         MonoInst *res;
1373         int pos, vnum;
1374
1375         /* inlining can result in deeper stacks */ 
1376         if (slot >= cfg->header->max_stack)
1377                 return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1378
1379         pos = ins->type - 1 + slot * STACK_MAX;
1380
1381         switch (ins->type) {
1382         case STACK_I4:
1383         case STACK_I8:
1384         case STACK_R8:
1385         case STACK_PTR:
1386         case STACK_MP:
1387         case STACK_OBJ:
1388                 if ((vnum = cfg->intvars [pos]))
1389                         return cfg->varinfo [vnum];
1390                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1391                 cfg->intvars [pos] = res->inst_c0;
1392                 break;
1393         default:
1394                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1395         }
1396         return res;
1397 }
1398
1399 static void
1400 mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
1401 {
1402         /* 
1403          * Don't use this if a generic_context is set, since that means AOT can't
1404          * look up the method using just the image+token.
1405          * table == 0 means this is a reference made from a wrapper.
1406          */
1407         if (cfg->compile_aot && !cfg->generic_context && (mono_metadata_token_table (token) > 0)) {
1408                 MonoJumpInfoToken *jump_info_token = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
1409                 jump_info_token->image = image;
1410                 jump_info_token->token = token;
1411                 g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
1412         }
1413 }
1414
1415 /*
1416  * This function is called to handle items that are left on the evaluation stack
1417  * at basic block boundaries. What happens is that we save the values to local variables
1418  * and we reload them later when first entering the target basic block (with the
1419  * handle_loaded_temps () function).
1420  * A single joint point will use the same variables (stored in the array bb->out_stack or
1421  * bb->in_stack, if the basic block is before or after the joint point).
1422  *
1423  * This function needs to be called _before_ emitting the last instruction of
1424  * the bb (i.e. before emitting a branch).
1425  * If the stack merge fails at a join point, cfg->unverifiable is set.
1426  */
1427 static void
1428 handle_stack_args (MonoCompile *cfg, MonoInst **sp, int count)
1429 {
1430         int i, bindex;
1431         MonoBasicBlock *bb = cfg->cbb;
1432         MonoBasicBlock *outb;
1433         MonoInst *inst, **locals;
1434         gboolean found;
1435
1436         if (!count)
1437                 return;
1438         if (cfg->verbose_level > 3)
1439                 printf ("%d item(s) on exit from B%d\n", count, bb->block_num);
1440         if (!bb->out_scount) {
1441                 bb->out_scount = count;
1442                 //printf ("bblock %d has out:", bb->block_num);
1443                 found = FALSE;
1444                 for (i = 0; i < bb->out_count; ++i) {
1445                         outb = bb->out_bb [i];
1446                         /* exception handlers are linked, but they should not be considered for stack args */
1447                         if (outb->flags & BB_EXCEPTION_HANDLER)
1448                                 continue;
1449                         //printf (" %d", outb->block_num);
1450                         if (outb->in_stack) {
1451                                 found = TRUE;
1452                                 bb->out_stack = outb->in_stack;
1453                                 break;
1454                         }
1455                 }
1456                 //printf ("\n");
1457                 if (!found) {
1458                         bb->out_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1459                         for (i = 0; i < count; ++i) {
1460                                 /* 
1461                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
1462                                  * stack slot and if they are of the same type.
1463                                  * This won't cause conflicts since if 'local' is used to 
1464                                  * store one of the values in the in_stack of a bblock, then
1465                                  * the same variable will be used for the same outgoing stack 
1466                                  * slot as well. 
1467                                  * This doesn't work when inlining methods, since the bblocks
1468                                  * in the inlined methods do not inherit their in_stack from
1469                                  * the bblock they are inlined to. See bug #58863 for an
1470                                  * example.
1471                                  */
1472                                 if (cfg->inlined_method)
1473                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1474                                 else
1475                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
1476                         }
1477                 }
1478         }
1479
1480         for (i = 0; i < bb->out_count; ++i) {
1481                 outb = bb->out_bb [i];
1482                 /* exception handlers are linked, but they should not be considered for stack args */
1483                 if (outb->flags & BB_EXCEPTION_HANDLER)
1484                         continue;
1485                 if (outb->in_scount) {
1486                         if (outb->in_scount != bb->out_scount) {
1487                                 cfg->unverifiable = TRUE;
1488                                 return;
1489                         }
1490                         continue; /* check they are the same locals */
1491                 }
1492                 outb->in_scount = count;
1493                 outb->in_stack = bb->out_stack;
1494         }
1495
1496         locals = bb->out_stack;
1497         cfg->cbb = bb;
1498         for (i = 0; i < count; ++i) {
1499                 EMIT_NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
1500                 inst->cil_code = sp [i]->cil_code;
1501                 sp [i] = locals [i];
1502                 if (cfg->verbose_level > 3)
1503                         printf ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
1504         }
1505
1506         /*
1507          * It is possible that the out bblocks already have in_stack assigned, and
1508          * the in_stacks differ. In this case, we will store to all the different 
1509          * in_stacks.
1510          */
1511
1512         found = TRUE;
1513         bindex = 0;
1514         while (found) {
1515                 /* Find a bblock which has a different in_stack */
1516                 found = FALSE;
1517                 while (bindex < bb->out_count) {
1518                         outb = bb->out_bb [bindex];
1519                         /* exception handlers are linked, but they should not be considered for stack args */
1520                         if (outb->flags & BB_EXCEPTION_HANDLER) {
1521                                 bindex++;
1522                                 continue;
1523                         }
1524                         if (outb->in_stack != locals) {
1525                                 for (i = 0; i < count; ++i) {
1526                                         EMIT_NEW_TEMPSTORE (cfg, inst, outb->in_stack [i]->inst_c0, sp [i]);
1527                                         inst->cil_code = sp [i]->cil_code;
1528                                         sp [i] = locals [i];
1529                                         if (cfg->verbose_level > 3)
1530                                                 printf ("storing %d to temp %d\n", i, (int)outb->in_stack [i]->inst_c0);
1531                                 }
1532                                 locals = outb->in_stack;
1533                                 found = TRUE;
1534                                 break;
1535                         }
1536                         bindex ++;
1537                 }
1538         }
1539 }
1540
1541 static void
1542 mini_emit_interface_bitmap_check (MonoCompile *cfg, int intf_bit_reg, int base_reg, int offset, MonoClass *klass)
1543 {
1544         int ibitmap_reg = alloc_preg (cfg);
1545 #ifdef COMPRESSED_INTERFACE_BITMAP
1546         MonoInst *args [2];
1547         MonoInst *res, *ins;
1548         NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, ibitmap_reg, base_reg, offset);
1549         MONO_ADD_INS (cfg->cbb, ins);
1550         args [0] = ins;
1551         if (cfg->compile_aot)
1552                 EMIT_NEW_AOTCONST (cfg, args [1], MONO_PATCH_INFO_IID, klass);
1553         else
1554                 EMIT_NEW_ICONST (cfg, args [1], klass->interface_id);
1555         res = mono_emit_jit_icall (cfg, mono_class_interface_match, args);
1556         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, intf_bit_reg, res->dreg);
1557 #else
1558         int ibitmap_byte_reg = alloc_preg (cfg);
1559
1560         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, base_reg, offset);
1561
1562         if (cfg->compile_aot) {
1563                 int iid_reg = alloc_preg (cfg);
1564                 int shifted_iid_reg = alloc_preg (cfg);
1565                 int ibitmap_byte_address_reg = alloc_preg (cfg);
1566                 int masked_iid_reg = alloc_preg (cfg);
1567                 int iid_one_bit_reg = alloc_preg (cfg);
1568                 int iid_bit_reg = alloc_preg (cfg);
1569                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1570                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, shifted_iid_reg, iid_reg, 3);
1571                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ibitmap_byte_address_reg, ibitmap_reg, shifted_iid_reg);
1572                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, ibitmap_byte_reg, ibitmap_byte_address_reg, 0);
1573                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, masked_iid_reg, iid_reg, 7);
1574                 MONO_EMIT_NEW_ICONST (cfg, iid_one_bit_reg, 1);
1575                 MONO_EMIT_NEW_BIALU (cfg, OP_ISHL, iid_bit_reg, iid_one_bit_reg, masked_iid_reg);
1576                 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, intf_bit_reg, ibitmap_byte_reg, iid_bit_reg);
1577         } else {
1578                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, klass->interface_id >> 3);
1579                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (klass->interface_id & 7));
1580         }
1581 #endif
1582 }
1583
1584 /* 
1585  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoClass
1586  * stored in "klass_reg" implements the interface "klass".
1587  */
1588 static void
1589 mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass_reg, MonoClass *klass)
1590 {
1591         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, interface_bitmap), klass);
1592 }
1593
1594 /* 
1595  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoVTable
1596  * stored in "vtable_reg" implements the interface "klass".
1597  */
1598 static void
1599 mini_emit_load_intf_bit_reg_vtable (MonoCompile *cfg, int intf_bit_reg, int vtable_reg, MonoClass *klass)
1600 {
1601         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, interface_bitmap), klass);
1602 }
1603
1604 /* 
1605  * Emit code which checks whenever the interface id of @klass is smaller than
1606  * than the value given by max_iid_reg.
1607 */
1608 static void
1609 mini_emit_max_iid_check (MonoCompile *cfg, int max_iid_reg, MonoClass *klass,
1610                                                  MonoBasicBlock *false_target)
1611 {
1612         if (cfg->compile_aot) {
1613                 int iid_reg = alloc_preg (cfg);
1614                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1615                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, max_iid_reg, iid_reg);
1616         }
1617         else
1618                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, max_iid_reg, klass->interface_id);
1619         if (false_target)
1620                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1621         else
1622                 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1623 }
1624
1625 /* Same as above, but obtains max_iid from a vtable */
1626 static void
1627 mini_emit_max_iid_check_vtable (MonoCompile *cfg, int vtable_reg, MonoClass *klass,
1628                                                                  MonoBasicBlock *false_target)
1629 {
1630         int max_iid_reg = alloc_preg (cfg);
1631                 
1632         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, max_interface_id));
1633         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1634 }
1635
1636 /* Same as above, but obtains max_iid from a klass */
1637 static void
1638 mini_emit_max_iid_check_class (MonoCompile *cfg, int klass_reg, MonoClass *klass,
1639                                                                  MonoBasicBlock *false_target)
1640 {
1641         int max_iid_reg = alloc_preg (cfg);
1642
1643         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, max_interface_id));
1644         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1645 }
1646
1647 static void
1648 mini_emit_isninst_cast_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_ins, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1649 {
1650         int idepth_reg = alloc_preg (cfg);
1651         int stypes_reg = alloc_preg (cfg);
1652         int stype = alloc_preg (cfg);
1653
1654         mono_class_setup_supertypes (klass);
1655
1656         if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1657                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1658                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1659                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1660         }
1661         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1662         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1663         if (klass_ins) {
1664                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, klass_ins->dreg);
1665         } else if (cfg->compile_aot) {
1666                 int const_reg = alloc_preg (cfg);
1667                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1668                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, const_reg);
1669         } else {
1670                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, stype, klass);
1671         }
1672         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, true_target);
1673 }
1674
1675 static void
1676 mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1677 {
1678         mini_emit_isninst_cast_inst (cfg, klass_reg, klass, NULL, false_target, true_target);
1679 }
1680
1681 static void
1682 mini_emit_iface_cast (MonoCompile *cfg, int vtable_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1683 {
1684         int intf_reg = alloc_preg (cfg);
1685
1686         mini_emit_max_iid_check_vtable (cfg, vtable_reg, klass, false_target);
1687         mini_emit_load_intf_bit_reg_vtable (cfg, intf_reg, vtable_reg, klass);
1688         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_reg, 0);
1689         if (true_target)
1690                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1691         else
1692                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");               
1693 }
1694
1695 /*
1696  * Variant of the above that takes a register to the class, not the vtable.
1697  */
1698 static void
1699 mini_emit_iface_class_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1700 {
1701         int intf_bit_reg = alloc_preg (cfg);
1702
1703         mini_emit_max_iid_check_class (cfg, klass_reg, klass, false_target);
1704         mini_emit_load_intf_bit_reg_class (cfg, intf_bit_reg, klass_reg, klass);
1705         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_bit_reg, 0);
1706         if (true_target)
1707                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1708         else
1709                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
1710 }
1711
1712 static inline void
1713 mini_emit_class_check_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_inst)
1714 {
1715         if (klass_inst) {
1716                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_inst->dreg);
1717         } else if (cfg->compile_aot) {
1718                 int const_reg = alloc_preg (cfg);
1719                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1720                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1721         } else {
1722                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1723         }
1724         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1725 }
1726
1727 static inline void
1728 mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass)
1729 {
1730         mini_emit_class_check_inst (cfg, klass_reg, klass, NULL);
1731 }
1732
1733 static inline void
1734 mini_emit_class_check_branch (MonoCompile *cfg, int klass_reg, MonoClass *klass, int branch_op, MonoBasicBlock *target)
1735 {
1736         if (cfg->compile_aot) {
1737                 int const_reg = alloc_preg (cfg);
1738                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1739                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1740         } else {
1741                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1742         }
1743         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, branch_op, target);
1744 }
1745
1746 static void
1747 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null);
1748         
1749 static void
1750 mini_emit_castclass_inst (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoInst *klass_inst, MonoBasicBlock *object_is_null)
1751 {
1752         if (klass->rank) {
1753                 int rank_reg = alloc_preg (cfg);
1754                 int eclass_reg = alloc_preg (cfg);
1755
1756                 g_assert (!klass_inst);
1757                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, rank));
1758                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
1759                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1760                 //              MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
1761                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
1762                 if (klass->cast_class == mono_defaults.object_class) {
1763                         int parent_reg = alloc_preg (cfg);
1764                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
1765                         mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, object_is_null);
1766                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1767                 } else if (klass->cast_class == mono_defaults.enum_class->parent) {
1768                         mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, object_is_null);
1769                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1770                 } else if (klass->cast_class == mono_defaults.enum_class) {
1771                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1772                 } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1773                         mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, NULL, NULL);
1774                 } else {
1775                         // Pass -1 as obj_reg to skip the check below for arrays of arrays
1776                         mini_emit_castclass (cfg, -1, eclass_reg, klass->cast_class, object_is_null);
1777                 }
1778
1779                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY) && (obj_reg != -1)) {
1780                         /* Check that the object is a vector too */
1781                         int bounds_reg = alloc_preg (cfg);
1782                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
1783                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
1784                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1785                 }
1786         } else {
1787                 int idepth_reg = alloc_preg (cfg);
1788                 int stypes_reg = alloc_preg (cfg);
1789                 int stype = alloc_preg (cfg);
1790
1791                 mono_class_setup_supertypes (klass);
1792
1793                 if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1794                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1795                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1796                         MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1797                 }
1798                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1799                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1800                 mini_emit_class_check_inst (cfg, stype, klass, klass_inst);
1801         }
1802 }
1803
1804 static void
1805 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null)
1806 {
1807         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, NULL, object_is_null);
1808 }
1809
1810 static void 
1811 mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align)
1812 {
1813         int val_reg;
1814
1815         g_assert (val == 0);
1816
1817         if (align == 0)
1818                 align = 4;
1819
1820         if ((size <= SIZEOF_REGISTER) && (size <= align)) {
1821                 switch (size) {
1822                 case 1:
1823                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, destreg, offset, val);
1824                         return;
1825                 case 2:
1826                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI2_MEMBASE_IMM, destreg, offset, val);
1827                         return;
1828                 case 4:
1829                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI4_MEMBASE_IMM, destreg, offset, val);
1830                         return;
1831 #if SIZEOF_REGISTER == 8
1832                 case 8:
1833                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI8_MEMBASE_IMM, destreg, offset, val);
1834                         return;
1835 #endif
1836                 }
1837         }
1838
1839         val_reg = alloc_preg (cfg);
1840
1841         if (SIZEOF_REGISTER == 8)
1842                 MONO_EMIT_NEW_I8CONST (cfg, val_reg, val);
1843         else
1844                 MONO_EMIT_NEW_ICONST (cfg, val_reg, val);
1845
1846         if (align < 4) {
1847                 /* This could be optimized further if neccesary */
1848                 while (size >= 1) {
1849                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1850                         offset += 1;
1851                         size -= 1;
1852                 }
1853                 return;
1854         }       
1855
1856 #if !NO_UNALIGNED_ACCESS
1857         if (SIZEOF_REGISTER == 8) {
1858                 if (offset % 8) {
1859                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1860                         offset += 4;
1861                         size -= 4;
1862                 }
1863                 while (size >= 8) {
1864                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, offset, val_reg);
1865                         offset += 8;
1866                         size -= 8;
1867                 }
1868         }       
1869 #endif
1870
1871         while (size >= 4) {
1872                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1873                 offset += 4;
1874                 size -= 4;
1875         }
1876         while (size >= 2) {
1877                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, val_reg);
1878                 offset += 2;
1879                 size -= 2;
1880         }
1881         while (size >= 1) {
1882                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1883                 offset += 1;
1884                 size -= 1;
1885         }
1886 }
1887
1888 void 
1889 mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align)
1890 {
1891         int cur_reg;
1892
1893         if (align == 0)
1894                 align = 4;
1895
1896         /*FIXME arbitrary hack to avoid unbound code expansion.*/
1897         g_assert (size < 10000);
1898
1899         if (align < 4) {
1900                 /* This could be optimized further if neccesary */
1901                 while (size >= 1) {
1902                         cur_reg = alloc_preg (cfg);
1903                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1904                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1905                         doffset += 1;
1906                         soffset += 1;
1907                         size -= 1;
1908                 }
1909         }
1910
1911 #if !NO_UNALIGNED_ACCESS
1912         if (SIZEOF_REGISTER == 8) {
1913                 while (size >= 8) {
1914                         cur_reg = alloc_preg (cfg);
1915                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI8_MEMBASE, cur_reg, srcreg, soffset);
1916                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, doffset, cur_reg);
1917                         doffset += 8;
1918                         soffset += 8;
1919                         size -= 8;
1920                 }
1921         }       
1922 #endif
1923
1924         while (size >= 4) {
1925                 cur_reg = alloc_preg (cfg);
1926                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, cur_reg, srcreg, soffset);
1927                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, doffset, cur_reg);
1928                 doffset += 4;
1929                 soffset += 4;
1930                 size -= 4;
1931         }
1932         while (size >= 2) {
1933                 cur_reg = alloc_preg (cfg);
1934                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, cur_reg, srcreg, soffset);
1935                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, doffset, cur_reg);
1936                 doffset += 2;
1937                 soffset += 2;
1938                 size -= 2;
1939         }
1940         while (size >= 1) {
1941                 cur_reg = alloc_preg (cfg);
1942                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1943                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1944                 doffset += 1;
1945                 soffset += 1;
1946                 size -= 1;
1947         }
1948 }
1949
1950 static void
1951 emit_tls_set (MonoCompile *cfg, int sreg1, int tls_key)
1952 {
1953         MonoInst *ins, *c;
1954
1955         if (cfg->compile_aot) {
1956                 EMIT_NEW_TLS_OFFSETCONST (cfg, c, tls_key);
1957                 MONO_INST_NEW (cfg, ins, OP_TLS_SET_REG);
1958                 ins->sreg1 = sreg1;
1959                 ins->sreg2 = c->dreg;
1960                 MONO_ADD_INS (cfg->cbb, ins);
1961         } else {
1962                 MONO_INST_NEW (cfg, ins, OP_TLS_SET);
1963                 ins->sreg1 = sreg1;
1964                 ins->inst_offset = mini_get_tls_offset (tls_key);
1965                 MONO_ADD_INS (cfg->cbb, ins);
1966         }
1967 }
1968
1969 /*
1970  * emit_push_lmf:
1971  *
1972  *   Emit IR to push the current LMF onto the LMF stack.
1973  */
1974 static void
1975 emit_push_lmf (MonoCompile *cfg)
1976 {
1977         /*
1978          * Emit IR to push the LMF:
1979          * lmf_addr = <lmf_addr from tls>
1980          * lmf->lmf_addr = lmf_addr
1981          * lmf->prev_lmf = *lmf_addr
1982          * *lmf_addr = lmf
1983          */
1984         int lmf_reg, prev_lmf_reg;
1985         MonoInst *ins, *lmf_ins;
1986
1987         if (!cfg->lmf_ir)
1988                 return;
1989
1990         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
1991                 /* Load current lmf */
1992                 lmf_ins = mono_get_lmf_intrinsic (cfg);
1993                 g_assert (lmf_ins);
1994                 MONO_ADD_INS (cfg->cbb, lmf_ins);
1995                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
1996                 lmf_reg = ins->dreg;
1997                 /* Save previous_lmf */
1998                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), lmf_ins->dreg);
1999                 /* Set new LMF */
2000                 emit_tls_set (cfg, lmf_reg, TLS_KEY_LMF);
2001         } else {
2002                 /*
2003                  * Store lmf_addr in a variable, so it can be allocated to a global register.
2004                  */
2005                 if (!cfg->lmf_addr_var)
2006                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2007
2008 #ifdef HOST_WIN32
2009                 ins = mono_get_jit_tls_intrinsic (cfg);
2010                 if (ins) {
2011                         int jit_tls_dreg = ins->dreg;
2012
2013                         MONO_ADD_INS (cfg->cbb, ins);
2014                         lmf_reg = alloc_preg (cfg);
2015                         EMIT_NEW_BIALU_IMM (cfg, lmf_ins, OP_PADD_IMM, lmf_reg, jit_tls_dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2016                 } else {
2017                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2018                 }
2019 #else
2020                 lmf_ins = mono_get_lmf_addr_intrinsic (cfg);
2021                 if (lmf_ins) {
2022                         MONO_ADD_INS (cfg->cbb, lmf_ins);
2023                 } else {
2024 #ifdef TARGET_IOS
2025                         MonoInst *args [16], *jit_tls_ins, *ins;
2026
2027                         /* Inline mono_get_lmf_addr () */
2028                         /* jit_tls = pthread_getspecific (mono_jit_tls_id); lmf_addr = &jit_tls->lmf; */
2029
2030                         /* Load mono_jit_tls_id */
2031                         if (cfg->compile_aot)
2032                                 EMIT_NEW_AOTCONST (cfg, args [0], MONO_PATCH_INFO_JIT_TLS_ID, NULL);
2033                         else
2034                                 EMIT_NEW_ICONST (cfg, args [0], mono_jit_tls_id);
2035                         /* call pthread_getspecific () */
2036                         jit_tls_ins = mono_emit_jit_icall (cfg, pthread_getspecific, args);
2037                         /* lmf_addr = &jit_tls->lmf */
2038                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, cfg->lmf_addr_var->dreg, jit_tls_ins->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2039                         lmf_ins = ins;
2040 #else
2041                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2042 #endif
2043                 }
2044 #endif
2045                 lmf_ins->dreg = cfg->lmf_addr_var->dreg;
2046
2047                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2048                 lmf_reg = ins->dreg;
2049
2050                 prev_lmf_reg = alloc_preg (cfg);
2051                 /* Save previous_lmf */
2052                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, cfg->lmf_addr_var->dreg, 0);
2053                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), prev_lmf_reg);
2054                 /* Set new lmf */
2055                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, cfg->lmf_addr_var->dreg, 0, lmf_reg);
2056         }
2057 }
2058
2059 /*
2060  * emit_pop_lmf:
2061  *
2062  *   Emit IR to pop the current LMF from the LMF stack.
2063  */
2064 static void
2065 emit_pop_lmf (MonoCompile *cfg)
2066 {
2067         int lmf_reg, lmf_addr_reg, prev_lmf_reg;
2068         MonoInst *ins;
2069
2070         if (!cfg->lmf_ir)
2071                 return;
2072
2073         EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2074         lmf_reg = ins->dreg;
2075
2076         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
2077                 /* Load previous_lmf */
2078                 prev_lmf_reg = alloc_preg (cfg);
2079                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2080                 /* Set new LMF */
2081                 emit_tls_set (cfg, prev_lmf_reg, TLS_KEY_LMF);
2082         } else {
2083                 /*
2084                  * Emit IR to pop the LMF:
2085                  * *(lmf->lmf_addr) = lmf->prev_lmf
2086                  */
2087                 /* This could be called before emit_push_lmf () */
2088                 if (!cfg->lmf_addr_var)
2089                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2090                 lmf_addr_reg = cfg->lmf_addr_var->dreg;
2091
2092                 prev_lmf_reg = alloc_preg (cfg);
2093                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2094                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_addr_reg, 0, prev_lmf_reg);
2095         }
2096 }
2097
2098 static void
2099 emit_instrumentation_call (MonoCompile *cfg, void *func)
2100 {
2101         MonoInst *iargs [1];
2102
2103         /*
2104          * Avoid instrumenting inlined methods since it can
2105          * distort profiling results.
2106          */
2107         if (cfg->method != cfg->current_method)
2108                 return;
2109
2110         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
2111                 EMIT_NEW_METHODCONST (cfg, iargs [0], cfg->method);
2112                 mono_emit_jit_icall (cfg, func, iargs);
2113         }
2114 }
2115
2116 static int
2117 ret_type_to_call_opcode (MonoCompile *cfg, MonoType *type, int calli, int virt)
2118 {
2119 handle_enum:
2120         type = mini_get_underlying_type (type);
2121         switch (type->type) {
2122         case MONO_TYPE_VOID:
2123                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALL_MEMBASE: OP_VOIDCALL;
2124         case MONO_TYPE_I1:
2125         case MONO_TYPE_U1:
2126         case MONO_TYPE_I2:
2127         case MONO_TYPE_U2:
2128         case MONO_TYPE_I4:
2129         case MONO_TYPE_U4:
2130                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2131         case MONO_TYPE_I:
2132         case MONO_TYPE_U:
2133         case MONO_TYPE_PTR:
2134         case MONO_TYPE_FNPTR:
2135                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2136         case MONO_TYPE_CLASS:
2137         case MONO_TYPE_STRING:
2138         case MONO_TYPE_OBJECT:
2139         case MONO_TYPE_SZARRAY:
2140         case MONO_TYPE_ARRAY:    
2141                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2142         case MONO_TYPE_I8:
2143         case MONO_TYPE_U8:
2144                 return calli? OP_LCALL_REG: virt? OP_LCALL_MEMBASE: OP_LCALL;
2145         case MONO_TYPE_R4:
2146                 if (cfg->r4fp)
2147                         return calli? OP_RCALL_REG: virt? OP_RCALL_MEMBASE: OP_RCALL;
2148                 else
2149                         return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2150         case MONO_TYPE_R8:
2151                 return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2152         case MONO_TYPE_VALUETYPE:
2153                 if (type->data.klass->enumtype) {
2154                         type = mono_class_enum_basetype (type->data.klass);
2155                         goto handle_enum;
2156                 } else
2157                         return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2158         case MONO_TYPE_TYPEDBYREF:
2159                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2160         case MONO_TYPE_GENERICINST:
2161                 type = &type->data.generic_class->container_class->byval_arg;
2162                 goto handle_enum;
2163         case MONO_TYPE_VAR:
2164         case MONO_TYPE_MVAR:
2165                 /* gsharedvt */
2166                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2167         default:
2168                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
2169         }
2170         return -1;
2171 }
2172
2173 /*
2174  * target_type_is_incompatible:
2175  * @cfg: MonoCompile context
2176  *
2177  * Check that the item @arg on the evaluation stack can be stored
2178  * in the target type (can be a local, or field, etc).
2179  * The cfg arg can be used to check if we need verification or just
2180  * validity checks.
2181  *
2182  * Returns: non-0 value if arg can't be stored on a target.
2183  */
2184 static int
2185 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
2186 {
2187         MonoType *simple_type;
2188         MonoClass *klass;
2189
2190         if (target->byref) {
2191                 /* FIXME: check that the pointed to types match */
2192                 if (arg->type == STACK_MP)
2193                         return arg->klass != mono_class_from_mono_type (target);
2194                 if (arg->type == STACK_PTR)
2195                         return 0;
2196                 return 1;
2197         }
2198
2199         simple_type = mini_get_underlying_type (target);
2200         switch (simple_type->type) {
2201         case MONO_TYPE_VOID:
2202                 return 1;
2203         case MONO_TYPE_I1:
2204         case MONO_TYPE_U1:
2205         case MONO_TYPE_I2:
2206         case MONO_TYPE_U2:
2207         case MONO_TYPE_I4:
2208         case MONO_TYPE_U4:
2209                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2210                         return 1;
2211                 return 0;
2212         case MONO_TYPE_PTR:
2213                 /* STACK_MP is needed when setting pinned locals */
2214                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2215                         return 1;
2216                 return 0;
2217         case MONO_TYPE_I:
2218         case MONO_TYPE_U:
2219         case MONO_TYPE_FNPTR:
2220                 /* 
2221                  * Some opcodes like ldloca returns 'transient pointers' which can be stored in
2222                  * in native int. (#688008).
2223                  */
2224                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2225                         return 1;
2226                 return 0;
2227         case MONO_TYPE_CLASS:
2228         case MONO_TYPE_STRING:
2229         case MONO_TYPE_OBJECT:
2230         case MONO_TYPE_SZARRAY:
2231         case MONO_TYPE_ARRAY:    
2232                 if (arg->type != STACK_OBJ)
2233                         return 1;
2234                 /* FIXME: check type compatibility */
2235                 return 0;
2236         case MONO_TYPE_I8:
2237         case MONO_TYPE_U8:
2238                 if (arg->type != STACK_I8)
2239                         return 1;
2240                 return 0;
2241         case MONO_TYPE_R4:
2242                 if (arg->type != cfg->r4_stack_type)
2243                         return 1;
2244                 return 0;
2245         case MONO_TYPE_R8:
2246                 if (arg->type != STACK_R8)
2247                         return 1;
2248                 return 0;
2249         case MONO_TYPE_VALUETYPE:
2250                 if (arg->type != STACK_VTYPE)
2251                         return 1;
2252                 klass = mono_class_from_mono_type (simple_type);
2253                 if (klass != arg->klass)
2254                         return 1;
2255                 return 0;
2256         case MONO_TYPE_TYPEDBYREF:
2257                 if (arg->type != STACK_VTYPE)
2258                         return 1;
2259                 klass = mono_class_from_mono_type (simple_type);
2260                 if (klass != arg->klass)
2261                         return 1;
2262                 return 0;
2263         case MONO_TYPE_GENERICINST:
2264                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
2265                         if (arg->type != STACK_VTYPE)
2266                                 return 1;
2267                         klass = mono_class_from_mono_type (simple_type);
2268                         /* The second cases is needed when doing partial sharing */
2269                         if (klass != arg->klass && mono_class_from_mono_type (target) != arg->klass)
2270                                 return 1;
2271                         return 0;
2272                 } else {
2273                         if (arg->type != STACK_OBJ)
2274                                 return 1;
2275                         /* FIXME: check type compatibility */
2276                         return 0;
2277                 }
2278         case MONO_TYPE_VAR:
2279         case MONO_TYPE_MVAR:
2280                 g_assert (cfg->gshared);
2281                 if (mini_type_var_is_vt (simple_type)) {
2282                         if (arg->type != STACK_VTYPE)
2283                                 return 1;
2284                 } else {
2285                         if (arg->type != STACK_OBJ)
2286                                 return 1;
2287                 }
2288                 return 0;
2289         default:
2290                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
2291         }
2292         return 1;
2293 }
2294
2295 /*
2296  * Prepare arguments for passing to a function call.
2297  * Return a non-zero value if the arguments can't be passed to the given
2298  * signature.
2299  * The type checks are not yet complete and some conversions may need
2300  * casts on 32 or 64 bit architectures.
2301  *
2302  * FIXME: implement this using target_type_is_incompatible ()
2303  */
2304 static int
2305 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2306 {
2307         MonoType *simple_type;
2308         int i;
2309
2310         if (sig->hasthis) {
2311                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2312                         return 1;
2313                 args++;
2314         }
2315         for (i = 0; i < sig->param_count; ++i) {
2316                 if (sig->params [i]->byref) {
2317                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2318                                 return 1;
2319                         continue;
2320                 }
2321                 simple_type = mini_get_underlying_type (sig->params [i]);
2322 handle_enum:
2323                 switch (simple_type->type) {
2324                 case MONO_TYPE_VOID:
2325                         return 1;
2326                         continue;
2327                 case MONO_TYPE_I1:
2328                 case MONO_TYPE_U1:
2329                 case MONO_TYPE_I2:
2330                 case MONO_TYPE_U2:
2331                 case MONO_TYPE_I4:
2332                 case MONO_TYPE_U4:
2333                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2334                                 return 1;
2335                         continue;
2336                 case MONO_TYPE_I:
2337                 case MONO_TYPE_U:
2338                 case MONO_TYPE_PTR:
2339                 case MONO_TYPE_FNPTR:
2340                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2341                                 return 1;
2342                         continue;
2343                 case MONO_TYPE_CLASS:
2344                 case MONO_TYPE_STRING:
2345                 case MONO_TYPE_OBJECT:
2346                 case MONO_TYPE_SZARRAY:
2347                 case MONO_TYPE_ARRAY:    
2348                         if (args [i]->type != STACK_OBJ)
2349                                 return 1;
2350                         continue;
2351                 case MONO_TYPE_I8:
2352                 case MONO_TYPE_U8:
2353                         if (args [i]->type != STACK_I8)
2354                                 return 1;
2355                         continue;
2356                 case MONO_TYPE_R4:
2357                         if (args [i]->type != cfg->r4_stack_type)
2358                                 return 1;
2359                         continue;
2360                 case MONO_TYPE_R8:
2361                         if (args [i]->type != STACK_R8)
2362                                 return 1;
2363                         continue;
2364                 case MONO_TYPE_VALUETYPE:
2365                         if (simple_type->data.klass->enumtype) {
2366                                 simple_type = mono_class_enum_basetype (simple_type->data.klass);
2367                                 goto handle_enum;
2368                         }
2369                         if (args [i]->type != STACK_VTYPE)
2370                                 return 1;
2371                         continue;
2372                 case MONO_TYPE_TYPEDBYREF:
2373                         if (args [i]->type != STACK_VTYPE)
2374                                 return 1;
2375                         continue;
2376                 case MONO_TYPE_GENERICINST:
2377                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2378                         goto handle_enum;
2379                 case MONO_TYPE_VAR:
2380                 case MONO_TYPE_MVAR:
2381                         /* gsharedvt */
2382                         if (args [i]->type != STACK_VTYPE)
2383                                 return 1;
2384                         continue;
2385                 default:
2386                         g_error ("unknown type 0x%02x in check_call_signature",
2387                                  simple_type->type);
2388                 }
2389         }
2390         return 0;
2391 }
2392
2393 static int
2394 callvirt_to_call (int opcode)
2395 {
2396         switch (opcode) {
2397         case OP_CALL_MEMBASE:
2398                 return OP_CALL;
2399         case OP_VOIDCALL_MEMBASE:
2400                 return OP_VOIDCALL;
2401         case OP_FCALL_MEMBASE:
2402                 return OP_FCALL;
2403         case OP_RCALL_MEMBASE:
2404                 return OP_RCALL;
2405         case OP_VCALL_MEMBASE:
2406                 return OP_VCALL;
2407         case OP_LCALL_MEMBASE:
2408                 return OP_LCALL;
2409         default:
2410                 g_assert_not_reached ();
2411         }
2412
2413         return -1;
2414 }
2415
2416 /* Either METHOD or IMT_ARG needs to be set */
2417 static void
2418 emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoMethod *method, MonoInst *imt_arg)
2419 {
2420         int method_reg;
2421
2422         if (COMPILE_LLVM (cfg)) {
2423                 method_reg = alloc_preg (cfg);
2424
2425                 if (imt_arg) {
2426                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2427                 } else if (cfg->compile_aot) {
2428                         MONO_EMIT_NEW_AOTCONST (cfg, method_reg, method, MONO_PATCH_INFO_METHODCONST);
2429                 } else {
2430                         MonoInst *ins;
2431                         MONO_INST_NEW (cfg, ins, OP_PCONST);
2432                         ins->inst_p0 = method;
2433                         ins->dreg = method_reg;
2434                         MONO_ADD_INS (cfg->cbb, ins);
2435                 }
2436
2437 #ifdef ENABLE_LLVM
2438                 call->imt_arg_reg = method_reg;
2439 #endif
2440         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2441                 return;
2442         }
2443
2444         method_reg = alloc_preg (cfg);
2445
2446         if (imt_arg) {
2447                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2448         } else if (cfg->compile_aot) {
2449                 MONO_EMIT_NEW_AOTCONST (cfg, method_reg, method, MONO_PATCH_INFO_METHODCONST);
2450         } else {
2451                 MonoInst *ins;
2452                 MONO_INST_NEW (cfg, ins, OP_PCONST);
2453                 ins->inst_p0 = method;
2454                 ins->dreg = method_reg;
2455                 MONO_ADD_INS (cfg->cbb, ins);
2456         }
2457
2458         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2459 }
2460
2461 static MonoJumpInfo *
2462 mono_patch_info_new (MonoMemPool *mp, int ip, MonoJumpInfoType type, gconstpointer target)
2463 {
2464         MonoJumpInfo *ji = mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
2465
2466         ji->ip.i = ip;
2467         ji->type = type;
2468         ji->data.target = target;
2469
2470         return ji;
2471 }
2472
2473 static int
2474 mini_class_check_context_used (MonoCompile *cfg, MonoClass *klass)
2475 {
2476         if (cfg->gshared)
2477                 return mono_class_check_context_used (klass);
2478         else
2479                 return 0;
2480 }
2481
2482 static int
2483 mini_method_check_context_used (MonoCompile *cfg, MonoMethod *method)
2484 {
2485         if (cfg->gshared)
2486                 return mono_method_check_context_used (method);
2487         else
2488                 return 0;
2489 }
2490
2491 /*
2492  * check_method_sharing:
2493  *
2494  *   Check whenever the vtable or an mrgctx needs to be passed when calling CMETHOD.
2495  */
2496 static void
2497 check_method_sharing (MonoCompile *cfg, MonoMethod *cmethod, gboolean *out_pass_vtable, gboolean *out_pass_mrgctx)
2498 {
2499         gboolean pass_vtable = FALSE;
2500         gboolean pass_mrgctx = FALSE;
2501
2502         if (((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
2503                 (cmethod->klass->generic_class || cmethod->klass->generic_container)) {
2504                 gboolean sharable = FALSE;
2505
2506                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE))
2507                         sharable = TRUE;
2508
2509                 /*
2510                  * Pass vtable iff target method might
2511                  * be shared, which means that sharing
2512                  * is enabled for its class and its
2513                  * context is sharable (and it's not a
2514                  * generic method).
2515                  */
2516                 if (sharable && !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
2517                         pass_vtable = TRUE;
2518         }
2519
2520         if (mini_method_get_context (cmethod) &&
2521                 mini_method_get_context (cmethod)->method_inst) {
2522                 g_assert (!pass_vtable);
2523
2524                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE)) {
2525                         pass_mrgctx = TRUE;
2526                 } else {
2527                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (mono_method_signature (cmethod)))
2528                                 pass_mrgctx = TRUE;
2529                 }
2530         }
2531
2532         if (out_pass_vtable)
2533                 *out_pass_vtable = pass_vtable;
2534         if (out_pass_mrgctx)
2535                 *out_pass_mrgctx = pass_mrgctx;
2536 }
2537
2538 inline static MonoCallInst *
2539 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
2540                                          MonoInst **args, int calli, int virtual, int tail, int rgctx, int unbox_trampoline)
2541 {
2542         MonoType *sig_ret;
2543         MonoCallInst *call;
2544 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2545         int i;
2546 #endif
2547
2548         if (tail) {
2549                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
2550
2551                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
2552         } else
2553                 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (cfg, sig->ret, calli, virtual));
2554
2555         call->args = args;
2556         call->signature = sig;
2557         call->rgctx_reg = rgctx;
2558         sig_ret = mini_get_underlying_type (sig->ret);
2559
2560         type_to_eval_stack_type ((cfg), sig_ret, &call->inst);
2561
2562         if (tail) {
2563                 if (mini_type_is_vtype (sig_ret)) {
2564                         call->vret_var = cfg->vret_addr;
2565                         //g_assert_not_reached ();
2566                 }
2567         } else if (mini_type_is_vtype (sig_ret)) {
2568                 MonoInst *temp = mono_compile_create_var (cfg, sig_ret, OP_LOCAL);
2569                 MonoInst *loada;
2570
2571                 temp->backend.is_pinvoke = sig->pinvoke;
2572
2573                 /*
2574                  * We use a new opcode OP_OUTARG_VTRETADDR instead of LDADDR for emitting the
2575                  * address of return value to increase optimization opportunities.
2576                  * Before vtype decomposition, the dreg of the call ins itself represents the
2577                  * fact the call modifies the return value. After decomposition, the call will
2578                  * be transformed into one of the OP_VOIDCALL opcodes, and the VTRETADDR opcode
2579                  * will be transformed into an LDADDR.
2580                  */
2581                 MONO_INST_NEW (cfg, loada, OP_OUTARG_VTRETADDR);
2582                 loada->dreg = alloc_preg (cfg);
2583                 loada->inst_p0 = temp;
2584                 /* We reference the call too since call->dreg could change during optimization */
2585                 loada->inst_p1 = call;
2586                 MONO_ADD_INS (cfg->cbb, loada);
2587
2588                 call->inst.dreg = temp->dreg;
2589
2590                 call->vret_var = loada;
2591         } else if (!MONO_TYPE_IS_VOID (sig_ret))
2592                 call->inst.dreg = alloc_dreg (cfg, call->inst.type);
2593
2594 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2595         if (COMPILE_SOFT_FLOAT (cfg)) {
2596                 /* 
2597                  * If the call has a float argument, we would need to do an r8->r4 conversion using 
2598                  * an icall, but that cannot be done during the call sequence since it would clobber
2599                  * the call registers + the stack. So we do it before emitting the call.
2600                  */
2601                 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2602                         MonoType *t;
2603                         MonoInst *in = call->args [i];
2604
2605                         if (i >= sig->hasthis)
2606                                 t = sig->params [i - sig->hasthis];
2607                         else
2608                                 t = &mono_defaults.int_class->byval_arg;
2609                         t = mono_type_get_underlying_type (t);
2610
2611                         if (!t->byref && t->type == MONO_TYPE_R4) {
2612                                 MonoInst *iargs [1];
2613                                 MonoInst *conv;
2614
2615                                 iargs [0] = in;
2616                                 conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
2617
2618                                 /* The result will be in an int vreg */
2619                                 call->args [i] = conv;
2620                         }
2621                 }
2622         }
2623 #endif
2624
2625         call->need_unbox_trampoline = unbox_trampoline;
2626
2627 #ifdef ENABLE_LLVM
2628         if (COMPILE_LLVM (cfg))
2629                 mono_llvm_emit_call (cfg, call);
2630         else
2631                 mono_arch_emit_call (cfg, call);
2632 #else
2633         mono_arch_emit_call (cfg, call);
2634 #endif
2635
2636         cfg->param_area = MAX (cfg->param_area, call->stack_usage);
2637         cfg->flags |= MONO_CFG_HAS_CALLS;
2638         
2639         return call;
2640 }
2641
2642 static void
2643 set_rgctx_arg (MonoCompile *cfg, MonoCallInst *call, int rgctx_reg, MonoInst *rgctx_arg)
2644 {
2645 #ifdef MONO_ARCH_RGCTX_REG
2646         mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
2647         cfg->uses_rgctx_reg = TRUE;
2648         call->rgctx_reg = TRUE;
2649 #ifdef ENABLE_LLVM
2650         call->rgctx_arg_reg = rgctx_reg;
2651 #endif
2652 #else
2653         NOT_IMPLEMENTED;
2654 #endif
2655 }       
2656
2657 inline static MonoInst*
2658 mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg)
2659 {
2660         MonoCallInst *call;
2661         MonoInst *ins;
2662         int rgctx_reg = -1;
2663         gboolean check_sp = FALSE;
2664
2665         if (cfg->check_pinvoke_callconv && cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
2666                 WrapperInfo *info = mono_marshal_get_wrapper_info (cfg->method);
2667
2668                 if (info && info->subtype == WRAPPER_SUBTYPE_PINVOKE)
2669                         check_sp = TRUE;
2670         }
2671
2672         if (rgctx_arg) {
2673                 rgctx_reg = mono_alloc_preg (cfg);
2674                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2675         }
2676
2677         if (check_sp) {
2678                 if (!cfg->stack_inbalance_var)
2679                         cfg->stack_inbalance_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2680
2681                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2682                 ins->dreg = cfg->stack_inbalance_var->dreg;
2683                 MONO_ADD_INS (cfg->cbb, ins);
2684         }
2685
2686         call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE, FALSE);
2687
2688         call->inst.sreg1 = addr->dreg;
2689
2690         if (imt_arg)
2691                 emit_imt_argument (cfg, call, NULL, imt_arg);
2692
2693         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2694
2695         if (check_sp) {
2696                 int sp_reg;
2697
2698                 sp_reg = mono_alloc_preg (cfg);
2699
2700                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2701                 ins->dreg = sp_reg;
2702                 MONO_ADD_INS (cfg->cbb, ins);
2703
2704                 /* Restore the stack so we don't crash when throwing the exception */
2705                 MONO_INST_NEW (cfg, ins, OP_SET_SP);
2706                 ins->sreg1 = cfg->stack_inbalance_var->dreg;
2707                 MONO_ADD_INS (cfg->cbb, ins);
2708
2709                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, cfg->stack_inbalance_var->dreg, sp_reg);
2710                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ExecutionEngineException");
2711         }
2712
2713         if (rgctx_arg)
2714                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2715
2716         return (MonoInst*)call;
2717 }
2718
2719 static MonoInst*
2720 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2721
2722 static MonoInst*
2723 emit_get_rgctx_method (MonoCompile *cfg, int context_used, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type);
2724 static MonoInst*
2725 emit_get_rgctx_klass (MonoCompile *cfg, int context_used, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2726
2727 static MonoInst*
2728 mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig, gboolean tail,
2729                                                         MonoInst **args, MonoInst *this, MonoInst *imt_arg, MonoInst *rgctx_arg)
2730 {
2731 #ifndef DISABLE_REMOTING
2732         gboolean might_be_remote = FALSE;
2733 #endif
2734         gboolean virtual = this != NULL;
2735         gboolean enable_for_aot = TRUE;
2736         int context_used;
2737         MonoCallInst *call;
2738         int rgctx_reg = 0;
2739         gboolean need_unbox_trampoline;
2740
2741         if (!sig)
2742                 sig = mono_method_signature (method);
2743
2744         if (rgctx_arg) {
2745                 rgctx_reg = mono_alloc_preg (cfg);
2746                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2747         }
2748
2749         if (method->string_ctor) {
2750                 /* Create the real signature */
2751                 /* FIXME: Cache these */
2752                 MonoMethodSignature *ctor_sig = mono_metadata_signature_dup_mempool (cfg->mempool, sig);
2753                 ctor_sig->ret = &mono_defaults.string_class->byval_arg;
2754
2755                 sig = ctor_sig;
2756         }
2757
2758         context_used = mini_method_check_context_used (cfg, method);
2759
2760 #ifndef DISABLE_REMOTING
2761         might_be_remote = this && sig->hasthis &&
2762                 (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) &&
2763                 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && (!MONO_CHECK_THIS (this) || context_used);
2764
2765         if (might_be_remote && context_used) {
2766                 MonoInst *addr;
2767
2768                 g_assert (cfg->gshared);
2769
2770                 addr = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK);
2771
2772                 return mono_emit_calli (cfg, sig, args, addr, NULL, NULL);
2773         }
2774 #endif
2775
2776         need_unbox_trampoline = method->klass == mono_defaults.object_class || (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
2777
2778         call = mono_emit_call_args (cfg, sig, args, FALSE, virtual, tail, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline);
2779
2780 #ifndef DISABLE_REMOTING
2781         if (might_be_remote)
2782                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2783         else
2784 #endif
2785                 call->method = method;
2786         call->inst.flags |= MONO_INST_HAS_METHOD;
2787         call->inst.inst_left = this;
2788         call->tail_call = tail;
2789
2790         if (virtual) {
2791                 int vtable_reg, slot_reg, this_reg;
2792                 int offset;
2793
2794                 this_reg = this->dreg;
2795
2796                 if ((method->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (method->name, "Invoke")) {
2797                         MonoInst *dummy_use;
2798
2799                         MONO_EMIT_NULL_CHECK (cfg, this_reg);
2800
2801                         /* Make a call to delegate->invoke_impl */
2802                         call->inst.inst_basereg = this_reg;
2803                         call->inst.inst_offset = MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl);
2804                         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2805
2806                         /* We must emit a dummy use here because the delegate trampoline will
2807                         replace the 'this' argument with the delegate target making this activation
2808                         no longer a root for the delegate.
2809                         This is an issue for delegates that target collectible code such as dynamic
2810                         methods of GC'able assemblies.
2811
2812                         For a test case look into #667921.
2813
2814                         FIXME: a dummy use is not the best way to do it as the local register allocator
2815                         will put it on a caller save register and spil it around the call. 
2816                         Ideally, we would either put it on a callee save register or only do the store part.  
2817                          */
2818                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, args [0]);
2819
2820                         return (MonoInst*)call;
2821                 }
2822
2823                 if ((!cfg->compile_aot || enable_for_aot) && 
2824                         (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || 
2825                          (MONO_METHOD_IS_FINAL (method) &&
2826                           method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)) &&
2827                         !(mono_class_is_marshalbyref (method->klass) && context_used)) {
2828                         /* 
2829                          * the method is not virtual, we just need to ensure this is not null
2830                          * and then we can call the method directly.
2831                          */
2832 #ifndef DISABLE_REMOTING
2833                         if (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) {
2834                                 /* 
2835                                  * The check above ensures method is not gshared, this is needed since
2836                                  * gshared methods can't have wrappers.
2837                                  */
2838                                 method = call->method = mono_marshal_get_remoting_invoke_with_check (method);
2839                         }
2840 #endif
2841
2842                         if (!method->string_ctor)
2843                                 MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2844
2845                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2846                 } else if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && MONO_METHOD_IS_FINAL (method)) {
2847                         /*
2848                          * the method is virtual, but we can statically dispatch since either
2849                          * it's class or the method itself are sealed.
2850                          * But first we need to ensure it's not a null reference.
2851                          */
2852                         MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2853
2854                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2855                 } else {
2856                         vtable_reg = alloc_preg (cfg);
2857                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2858                         if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2859                                 guint32 imt_slot = mono_method_get_imt_slot (method);
2860                                 emit_imt_argument (cfg, call, call->method, imt_arg);
2861                                 slot_reg = vtable_reg;
2862                                 offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
2863                         } else {
2864                                 slot_reg = vtable_reg;
2865                                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) +
2866                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
2867                                 if (imt_arg) {
2868                                         g_assert (mono_method_signature (method)->generic_param_count);
2869                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2870                                 }
2871                         }
2872
2873                         call->inst.sreg1 = slot_reg;
2874                         call->inst.inst_offset = offset;
2875                         call->virtual = TRUE;
2876                 }
2877         }
2878
2879         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2880
2881         if (rgctx_arg)
2882                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2883
2884         return (MonoInst*)call;
2885 }
2886
2887 MonoInst*
2888 mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoInst **args, MonoInst *this)
2889 {
2890         return mono_emit_method_call_full (cfg, method, mono_method_signature (method), FALSE, args, this, NULL, NULL);
2891 }
2892
2893 MonoInst*
2894 mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig,
2895                                            MonoInst **args)
2896 {
2897         MonoCallInst *call;
2898
2899         g_assert (sig);
2900
2901         call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE, FALSE, FALSE);
2902         call->fptr = func;
2903
2904         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2905
2906         return (MonoInst*)call;
2907 }
2908
2909 MonoInst*
2910 mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args)
2911 {
2912         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2913
2914         g_assert (info);
2915
2916         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2917 }
2918
2919 /*
2920  * mono_emit_abs_call:
2921  *
2922  *   Emit a call to the runtime function described by PATCH_TYPE and DATA.
2923  */
2924 inline static MonoInst*
2925 mono_emit_abs_call (MonoCompile *cfg, MonoJumpInfoType patch_type, gconstpointer data, 
2926                                         MonoMethodSignature *sig, MonoInst **args)
2927 {
2928         MonoJumpInfo *ji = mono_patch_info_new (cfg->mempool, 0, patch_type, data);
2929         MonoInst *ins;
2930
2931         /* 
2932          * We pass ji as the call address, the PATCH_INFO_ABS resolving code will
2933          * handle it.
2934          */
2935         if (cfg->abs_patches == NULL)
2936                 cfg->abs_patches = g_hash_table_new (NULL, NULL);
2937         g_hash_table_insert (cfg->abs_patches, ji, ji);
2938         ins = mono_emit_native_call (cfg, ji, sig, args);
2939         ((MonoCallInst*)ins)->fptr_is_patch = TRUE;
2940         return ins;
2941 }
2942
2943 static gboolean
2944 direct_icalls_enabled (MonoCompile *cfg)
2945 {
2946         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
2947 #ifdef TARGET_AMD64
2948         if (cfg->compile_llvm)
2949                 return FALSE;
2950 #endif
2951         if (cfg->gen_sdb_seq_points || cfg->disable_direct_icalls)
2952                 return FALSE;
2953         return TRUE;
2954 }
2955
2956 MonoInst*
2957 mono_emit_jit_icall_by_info (MonoCompile *cfg, MonoJitICallInfo *info, MonoInst **args)
2958 {
2959         /*
2960          * Call the jit icall without a wrapper if possible.
2961          * The wrapper is needed for the following reasons:
2962          * - to handle exceptions thrown using mono_raise_exceptions () from the
2963          *   icall function. The EH code needs the lmf frame pushed by the
2964          *   wrapper to be able to unwind back to managed code.
2965          * - to be able to do stack walks for asynchronously suspended
2966          *   threads when debugging.
2967          */
2968         if (info->no_raise && direct_icalls_enabled (cfg)) {
2969                 char *name;
2970                 int costs;
2971
2972                 if (!info->wrapper_method) {
2973                         name = g_strdup_printf ("__icall_wrapper_%s", info->name);
2974                         info->wrapper_method = mono_marshal_get_icall_wrapper (info->sig, name, info->func, TRUE);
2975                         g_free (name);
2976                         mono_memory_barrier ();
2977                 }
2978
2979                 /*
2980                  * Inline the wrapper method, which is basically a call to the C icall, and
2981                  * an exception check.
2982                  */
2983                 costs = inline_method (cfg, info->wrapper_method, NULL,
2984                                                            args, NULL, cfg->real_offset, TRUE);
2985                 g_assert (costs > 0);
2986                 g_assert (!MONO_TYPE_IS_VOID (info->sig->ret));
2987
2988                 return args [0];
2989         } else {
2990                 return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2991         }
2992 }
2993  
2994 static MonoInst*
2995 mono_emit_widen_call_res (MonoCompile *cfg, MonoInst *ins, MonoMethodSignature *fsig)
2996 {
2997         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
2998                 if ((fsig->pinvoke || LLVM_ENABLED) && !fsig->ret->byref) {
2999                         int widen_op = -1;
3000
3001                         /* 
3002                          * Native code might return non register sized integers 
3003                          * without initializing the upper bits.
3004                          */
3005                         switch (mono_type_to_load_membase (cfg, fsig->ret)) {
3006                         case OP_LOADI1_MEMBASE:
3007                                 widen_op = OP_ICONV_TO_I1;
3008                                 break;
3009                         case OP_LOADU1_MEMBASE:
3010                                 widen_op = OP_ICONV_TO_U1;
3011                                 break;
3012                         case OP_LOADI2_MEMBASE:
3013                                 widen_op = OP_ICONV_TO_I2;
3014                                 break;
3015                         case OP_LOADU2_MEMBASE:
3016                                 widen_op = OP_ICONV_TO_U2;
3017                                 break;
3018                         default:
3019                                 break;
3020                         }
3021
3022                         if (widen_op != -1) {
3023                                 int dreg = alloc_preg (cfg);
3024                                 MonoInst *widen;
3025
3026                                 EMIT_NEW_UNALU (cfg, widen, widen_op, dreg, ins->dreg);
3027                                 widen->type = ins->type;
3028                                 ins = widen;
3029                         }
3030                 }
3031         }
3032
3033         return ins;
3034 }
3035
3036 static MonoMethod*
3037 get_memcpy_method (void)
3038 {
3039         static MonoMethod *memcpy_method = NULL;
3040         if (!memcpy_method) {
3041                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
3042                 if (!memcpy_method)
3043                         g_error ("Old corlib found. Install a new one");
3044         }
3045         return memcpy_method;
3046 }
3047
3048 static void
3049 create_write_barrier_bitmap (MonoCompile *cfg, MonoClass *klass, unsigned *wb_bitmap, int offset)
3050 {
3051         MonoClassField *field;
3052         gpointer iter = NULL;
3053
3054         while ((field = mono_class_get_fields (klass, &iter))) {
3055                 int foffset;
3056
3057                 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3058                         continue;
3059                 foffset = klass->valuetype ? field->offset - sizeof (MonoObject): field->offset;
3060                 if (mini_type_is_reference (mono_field_get_type (field))) {
3061                         g_assert ((foffset % SIZEOF_VOID_P) == 0);
3062                         *wb_bitmap |= 1 << ((offset + foffset) / SIZEOF_VOID_P);
3063                 } else {
3064                         MonoClass *field_class = mono_class_from_mono_type (field->type);
3065                         if (field_class->has_references)
3066                                 create_write_barrier_bitmap (cfg, field_class, wb_bitmap, offset + foffset);
3067                 }
3068         }
3069 }
3070
3071 static void
3072 emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value)
3073 {
3074         int card_table_shift_bits;
3075         gpointer card_table_mask;
3076         guint8 *card_table;
3077         MonoInst *dummy_use;
3078         int nursery_shift_bits;
3079         size_t nursery_size;
3080         gboolean has_card_table_wb = FALSE;
3081
3082         if (!cfg->gen_write_barriers)
3083                 return;
3084
3085         card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
3086
3087         mono_gc_get_nursery (&nursery_shift_bits, &nursery_size);
3088
3089 #ifdef MONO_ARCH_HAVE_CARD_TABLE_WBARRIER
3090         has_card_table_wb = TRUE;
3091 #endif
3092
3093         if (has_card_table_wb && !cfg->compile_aot && card_table && nursery_shift_bits > 0 && !COMPILE_LLVM (cfg)) {
3094                 MonoInst *wbarrier;
3095
3096                 MONO_INST_NEW (cfg, wbarrier, OP_CARD_TABLE_WBARRIER);
3097                 wbarrier->sreg1 = ptr->dreg;
3098                 wbarrier->sreg2 = value->dreg;
3099                 MONO_ADD_INS (cfg->cbb, wbarrier);
3100         } else if (card_table && !cfg->compile_aot && !mono_gc_card_table_nursery_check ()) {
3101                 int offset_reg = alloc_preg (cfg);
3102                 int card_reg  = alloc_preg (cfg);
3103                 MonoInst *ins;
3104
3105                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, offset_reg, ptr->dreg, card_table_shift_bits);
3106                 if (card_table_mask)
3107                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, offset_reg, offset_reg, card_table_mask);
3108
3109                 /*We can't use PADD_IMM since the cardtable might end up in high addresses and amd64 doesn't support
3110                  * IMM's larger than 32bits.
3111                  */
3112                 if (cfg->compile_aot) {
3113                         MONO_EMIT_NEW_AOTCONST (cfg, card_reg, NULL, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR);
3114                 } else {
3115                         MONO_INST_NEW (cfg, ins, OP_PCONST);
3116                         ins->inst_p0 = card_table;
3117                         ins->dreg = card_reg;
3118                         MONO_ADD_INS (cfg->cbb, ins);
3119                 }
3120
3121                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, offset_reg, offset_reg, card_reg);
3122                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, offset_reg, 0, 1);
3123         } else {
3124                 MonoMethod *write_barrier = mono_gc_get_write_barrier ();
3125                 mono_emit_method_call (cfg, write_barrier, &ptr, NULL);
3126         }
3127
3128         EMIT_NEW_DUMMY_USE (cfg, dummy_use, value);
3129 }
3130
3131 static gboolean
3132 mono_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align)
3133 {
3134         int dest_ptr_reg, tmp_reg, destreg, srcreg, offset;
3135         unsigned need_wb = 0;
3136
3137         if (align == 0)
3138                 align = 4;
3139
3140         /*types with references can't have alignment smaller than sizeof(void*) */
3141         if (align < SIZEOF_VOID_P)
3142                 return FALSE;
3143
3144         /*This value cannot be bigger than 32 due to the way we calculate the required wb bitmap.*/
3145         if (size > 32 * SIZEOF_VOID_P)
3146                 return FALSE;
3147
3148         create_write_barrier_bitmap (cfg, klass, &need_wb, 0);
3149
3150         /* We don't unroll more than 5 stores to avoid code bloat. */
3151         if (size > 5 * SIZEOF_VOID_P) {
3152                 /*This is harmless and simplify mono_gc_wbarrier_value_copy_bitmap */
3153                 size += (SIZEOF_VOID_P - 1);
3154                 size &= ~(SIZEOF_VOID_P - 1);
3155
3156                 EMIT_NEW_ICONST (cfg, iargs [2], size);
3157                 EMIT_NEW_ICONST (cfg, iargs [3], need_wb);
3158                 mono_emit_jit_icall (cfg, mono_gc_wbarrier_value_copy_bitmap, iargs);
3159                 return TRUE;
3160         }
3161
3162         destreg = iargs [0]->dreg;
3163         srcreg = iargs [1]->dreg;
3164         offset = 0;
3165
3166         dest_ptr_reg = alloc_preg (cfg);
3167         tmp_reg = alloc_preg (cfg);
3168
3169         /*tmp = dreg*/
3170         EMIT_NEW_UNALU (cfg, iargs [0], OP_MOVE, dest_ptr_reg, destreg);
3171
3172         while (size >= SIZEOF_VOID_P) {
3173                 MonoInst *load_inst;
3174                 MONO_INST_NEW (cfg, load_inst, OP_LOAD_MEMBASE);
3175                 load_inst->dreg = tmp_reg;
3176                 load_inst->inst_basereg = srcreg;
3177                 load_inst->inst_offset = offset;
3178                 MONO_ADD_INS (cfg->cbb, load_inst);
3179
3180                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, dest_ptr_reg, 0, tmp_reg);
3181
3182                 if (need_wb & 0x1)
3183                         emit_write_barrier (cfg, iargs [0], load_inst);
3184
3185                 offset += SIZEOF_VOID_P;
3186                 size -= SIZEOF_VOID_P;
3187                 need_wb >>= 1;
3188
3189                 /*tmp += sizeof (void*)*/
3190                 if (size >= SIZEOF_VOID_P) {
3191                         NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dest_ptr_reg, dest_ptr_reg, SIZEOF_VOID_P);
3192                         MONO_ADD_INS (cfg->cbb, iargs [0]);
3193                 }
3194         }
3195
3196         /* Those cannot be references since size < sizeof (void*) */
3197         while (size >= 4) {
3198                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tmp_reg, srcreg, offset);
3199                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, tmp_reg);
3200                 offset += 4;
3201                 size -= 4;
3202         }
3203
3204         while (size >= 2) {
3205                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmp_reg, srcreg, offset);
3206                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, tmp_reg);
3207                 offset += 2;
3208                 size -= 2;
3209         }
3210
3211         while (size >= 1) {
3212                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmp_reg, srcreg, offset);
3213                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, tmp_reg);
3214                 offset += 1;
3215                 size -= 1;
3216         }
3217
3218         return TRUE;
3219 }
3220
3221 /*
3222  * Emit code to copy a valuetype of type @klass whose address is stored in
3223  * @src->dreg to memory whose address is stored at @dest->dreg.
3224  */
3225 void
3226 mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native)
3227 {
3228         MonoInst *iargs [4];
3229         int n;
3230         guint32 align = 0;
3231         MonoMethod *memcpy_method;
3232         MonoInst *size_ins = NULL;
3233         MonoInst *memcpy_ins = NULL;
3234
3235         g_assert (klass);
3236         if (cfg->gshared)
3237                 klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg));
3238
3239         /*
3240          * This check breaks with spilled vars... need to handle it during verification anyway.
3241          * g_assert (klass && klass == src->klass && klass == dest->klass);
3242          */
3243
3244         if (mini_is_gsharedvt_klass (klass)) {
3245                 g_assert (!native);
3246                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3247                 memcpy_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_MEMCPY);
3248         }
3249
3250         if (native)
3251                 n = mono_class_native_size (klass, &align);
3252         else
3253                 n = mono_class_value_size (klass, &align);
3254
3255         /* if native is true there should be no references in the struct */
3256         if (cfg->gen_write_barriers && (klass->has_references || size_ins) && !native) {
3257                 /* Avoid barriers when storing to the stack */
3258                 if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) ||
3259                           (dest->opcode == OP_LDADDR))) {
3260                         int context_used;
3261
3262                         iargs [0] = dest;
3263                         iargs [1] = src;
3264
3265                         context_used = mini_class_check_context_used (cfg, klass);
3266
3267                         /* It's ok to intrinsify under gsharing since shared code types are layout stable. */
3268                         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && mono_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
3269                                 return;
3270                         } else if (context_used) {
3271                                 iargs [2] = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3272                         }  else {
3273                                 if (cfg->compile_aot) {
3274                                         EMIT_NEW_CLASSCONST (cfg, iargs [2], klass);
3275                                 } else {
3276                                         EMIT_NEW_PCONST (cfg, iargs [2], klass);
3277                                         mono_class_compute_gc_descriptor (klass);
3278                                 }
3279                         }
3280
3281                         if (size_ins)
3282                                 mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs);
3283                         else
3284                                 mono_emit_jit_icall (cfg, mono_value_copy, iargs);
3285                         return;
3286                 }
3287         }
3288
3289         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 8) {
3290                 /* FIXME: Optimize the case when src/dest is OP_LDADDR */
3291                 mini_emit_memcpy (cfg, dest->dreg, 0, src->dreg, 0, n, align);
3292         } else {
3293                 iargs [0] = dest;
3294                 iargs [1] = src;
3295                 if (size_ins)
3296                         iargs [2] = size_ins;
3297                 else
3298                         EMIT_NEW_ICONST (cfg, iargs [2], n);
3299                 
3300                 memcpy_method = get_memcpy_method ();
3301                 if (memcpy_ins)
3302                         mono_emit_calli (cfg, mono_method_signature (memcpy_method), iargs, memcpy_ins, NULL, NULL);
3303                 else
3304                         mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
3305         }
3306 }
3307
3308 static MonoMethod*
3309 get_memset_method (void)
3310 {
3311         static MonoMethod *memset_method = NULL;
3312         if (!memset_method) {
3313                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
3314                 if (!memset_method)
3315                         g_error ("Old corlib found. Install a new one");
3316         }
3317         return memset_method;
3318 }
3319
3320 void
3321 mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass)
3322 {
3323         MonoInst *iargs [3];
3324         int n;
3325         guint32 align;
3326         MonoMethod *memset_method;
3327         MonoInst *size_ins = NULL;
3328         MonoInst *bzero_ins = NULL;
3329         static MonoMethod *bzero_method;
3330
3331         /* FIXME: Optimize this for the case when dest is an LDADDR */
3332         mono_class_init (klass);
3333         if (mini_is_gsharedvt_klass (klass)) {
3334                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3335                 bzero_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_BZERO);
3336                 if (!bzero_method)
3337                         bzero_method = mono_class_get_method_from_name (mono_defaults.string_class, "bzero_aligned_1", 2);
3338                 g_assert (bzero_method);
3339                 iargs [0] = dest;
3340                 iargs [1] = size_ins;
3341                 mono_emit_calli (cfg, mono_method_signature (bzero_method), iargs, bzero_ins, NULL, NULL);
3342                 return;
3343         }
3344
3345         n = mono_class_value_size (klass, &align);
3346
3347         if (n <= sizeof (gpointer) * 8) {
3348                 mini_emit_memset (cfg, dest->dreg, 0, n, 0, align);
3349         }
3350         else {
3351                 memset_method = get_memset_method ();
3352                 iargs [0] = dest;
3353                 EMIT_NEW_ICONST (cfg, iargs [1], 0);
3354                 EMIT_NEW_ICONST (cfg, iargs [2], n);
3355                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
3356         }
3357 }
3358
3359 /*
3360  * emit_get_rgctx:
3361  *
3362  *   Emit IR to return either the this pointer for instance method,
3363  * or the mrgctx for static methods.
3364  */
3365 static MonoInst*
3366 emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used)
3367 {
3368         MonoInst *this = NULL;
3369
3370         g_assert (cfg->gshared);
3371
3372         if (!(method->flags & METHOD_ATTRIBUTE_STATIC) &&
3373                         !(context_used & MONO_GENERIC_CONTEXT_USED_METHOD) &&
3374                         !method->klass->valuetype)
3375                 EMIT_NEW_ARGLOAD (cfg, this, 0);
3376
3377         if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
3378                 MonoInst *mrgctx_loc, *mrgctx_var;
3379
3380                 g_assert (!this);
3381                 g_assert (method->is_inflated && mono_method_get_context (method)->method_inst);
3382
3383                 mrgctx_loc = mono_get_vtable_var (cfg);
3384                 EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
3385
3386                 return mrgctx_var;
3387         } else if (method->flags & METHOD_ATTRIBUTE_STATIC || method->klass->valuetype) {
3388                 MonoInst *vtable_loc, *vtable_var;
3389
3390                 g_assert (!this);
3391
3392                 vtable_loc = mono_get_vtable_var (cfg);
3393                 EMIT_NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
3394
3395                 if (method->is_inflated && mono_method_get_context (method)->method_inst) {
3396                         MonoInst *mrgctx_var = vtable_var;
3397                         int vtable_reg;
3398
3399                         vtable_reg = alloc_preg (cfg);
3400                         EMIT_NEW_LOAD_MEMBASE (cfg, vtable_var, OP_LOAD_MEMBASE, vtable_reg, mrgctx_var->dreg, MONO_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, class_vtable));
3401                         vtable_var->type = STACK_PTR;
3402                 }
3403
3404                 return vtable_var;
3405         } else {
3406                 MonoInst *ins;
3407                 int vtable_reg;
3408         
3409                 vtable_reg = alloc_preg (cfg);
3410                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, vtable_reg, this->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3411                 return ins;
3412         }
3413 }
3414
3415 static MonoJumpInfoRgctxEntry *
3416 mono_patch_info_rgctx_entry_new (MonoMemPool *mp, MonoMethod *method, gboolean in_mrgctx, MonoJumpInfoType patch_type, gconstpointer patch_data, MonoRgctxInfoType info_type)
3417 {
3418         MonoJumpInfoRgctxEntry *res = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoRgctxEntry));
3419         res->method = method;
3420         res->in_mrgctx = in_mrgctx;
3421         res->data = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
3422         res->data->type = patch_type;
3423         res->data->data.target = patch_data;
3424         res->info_type = info_type;
3425
3426         return res;
3427 }
3428
3429 /*
3430  * emit_rgctx_fetch:
3431  *
3432  *   Emit IR to load the value of the rgctx entry ENTRY from the rgctx
3433  * given by RGCTX.
3434  */
3435 static inline MonoInst*
3436 emit_rgctx_fetch (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3437 {
3438         /* Inline version, not currently used */
3439         // FIXME: This can be called from mono_decompose_vtype_opts (), which can't create new bblocks
3440 #if 0
3441         int i, slot, depth, index, rgctx_reg, val_reg, res_reg;
3442         gboolean mrgctx;
3443         MonoBasicBlock *is_null_bb, *end_bb;
3444         MonoInst *res, *ins, *call;
3445         MonoInst *args[16];
3446
3447         slot = mini_get_rgctx_entry_slot (entry);
3448
3449         mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot);
3450         index = MONO_RGCTX_SLOT_INDEX (slot);
3451         if (mrgctx)
3452                 index += MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
3453         for (depth = 0; ; ++depth) {
3454                 int size = mono_class_rgctx_get_array_size (depth, mrgctx);
3455
3456                 if (index < size - 1)
3457                         break;
3458                 index -= size - 1;
3459         }
3460
3461         NEW_BBLOCK (cfg, end_bb);
3462         NEW_BBLOCK (cfg, is_null_bb);
3463
3464         if (mrgctx) {
3465                 rgctx_reg = rgctx->dreg;
3466         } else {
3467                 rgctx_reg = alloc_preg (cfg);
3468
3469                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, rgctx_reg, rgctx->dreg, MONO_STRUCT_OFFSET (MonoVTable, runtime_generic_context));
3470                 // FIXME: Avoid this check by allocating the table when the vtable is created etc.
3471                 NEW_BBLOCK (cfg, is_null_bb);
3472
3473                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3474                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3475         }
3476
3477         for (i = 0; i < depth; ++i) {
3478                 int array_reg = alloc_preg (cfg);
3479
3480                 /* load ptr to next array */
3481                 if (mrgctx && i == 0)
3482                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT);
3483                 else
3484                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, 0);
3485                 rgctx_reg = array_reg;
3486                 /* is the ptr null? */
3487                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3488                 /* if yes, jump to actual trampoline */
3489                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3490         }
3491
3492         /* fetch slot */
3493         val_reg = alloc_preg (cfg);
3494         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, val_reg, rgctx_reg, (index + 1) * sizeof (gpointer));
3495         /* is the slot null? */
3496         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, val_reg, 0);
3497         /* if yes, jump to actual trampoline */
3498         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3499
3500         /* Fastpath */
3501         res_reg = alloc_preg (cfg);
3502         MONO_INST_NEW (cfg, ins, OP_MOVE);
3503         ins->dreg = res_reg;
3504         ins->sreg1 = val_reg;
3505         MONO_ADD_INS (cfg->cbb, ins);
3506         res = ins;
3507         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3508
3509         /* Slowpath */
3510         MONO_START_BB (cfg, is_null_bb);
3511         args [0] = rgctx;
3512         EMIT_NEW_ICONST (cfg, args [1], index);
3513         if (mrgctx)
3514                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3515         else
3516                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3517         MONO_INST_NEW (cfg, ins, OP_MOVE);
3518         ins->dreg = res_reg;
3519         ins->sreg1 = call->dreg;
3520         MONO_ADD_INS (cfg->cbb, ins);
3521         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3522
3523         MONO_START_BB (cfg, end_bb);
3524
3525         return res;
3526 #else
3527         return mono_emit_abs_call (cfg, MONO_PATCH_INFO_RGCTX_FETCH, entry, helper_sig_rgctx_lazy_fetch_trampoline, &rgctx);
3528 #endif
3529 }
3530
3531 static MonoInst*
3532 emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
3533                                           MonoClass *klass, MonoRgctxInfoType rgctx_type)
3534 {
3535         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);
3536         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3537
3538         return emit_rgctx_fetch (cfg, rgctx, entry);
3539 }
3540
3541 static MonoInst*
3542 emit_get_rgctx_sig (MonoCompile *cfg, int context_used,
3543                                         MonoMethodSignature *sig, MonoRgctxInfoType rgctx_type)
3544 {
3545         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);
3546         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3547
3548         return emit_rgctx_fetch (cfg, rgctx, entry);
3549 }
3550
3551 static MonoInst*
3552 emit_get_rgctx_gsharedvt_call (MonoCompile *cfg, int context_used,
3553                                                            MonoMethodSignature *sig, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3554 {
3555         MonoJumpInfoGSharedVtCall *call_info;
3556         MonoJumpInfoRgctxEntry *entry;
3557         MonoInst *rgctx;
3558
3559         call_info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoGSharedVtCall));
3560         call_info->sig = sig;
3561         call_info->method = cmethod;
3562
3563         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);
3564         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3565
3566         return emit_rgctx_fetch (cfg, rgctx, entry);
3567 }
3568
3569 /*
3570  * emit_get_rgctx_virt_method:
3571  *
3572  *   Return data for method VIRT_METHOD for a receiver of type KLASS.
3573  */
3574 static MonoInst*
3575 emit_get_rgctx_virt_method (MonoCompile *cfg, int context_used,
3576                                                         MonoClass *klass, MonoMethod *virt_method, MonoRgctxInfoType rgctx_type)
3577 {
3578         MonoJumpInfoVirtMethod *info;
3579         MonoJumpInfoRgctxEntry *entry;
3580         MonoInst *rgctx;
3581
3582         info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoVirtMethod));
3583         info->klass = klass;
3584         info->method = virt_method;
3585
3586         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);
3587         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3588
3589         return emit_rgctx_fetch (cfg, rgctx, entry);
3590 }
3591
3592 static MonoInst*
3593 emit_get_rgctx_gsharedvt_method (MonoCompile *cfg, int context_used,
3594                                                                  MonoMethod *cmethod, MonoGSharedVtMethodInfo *info)
3595 {
3596         MonoJumpInfoRgctxEntry *entry;
3597         MonoInst *rgctx;
3598
3599         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);
3600         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3601
3602         return emit_rgctx_fetch (cfg, rgctx, entry);
3603 }
3604
3605 /*
3606  * emit_get_rgctx_method:
3607  *
3608  *   Emit IR to load the property RGCTX_TYPE of CMETHOD. If context_used is 0, emit
3609  * normal constants, else emit a load from the rgctx.
3610  */
3611 static MonoInst*
3612 emit_get_rgctx_method (MonoCompile *cfg, int context_used,
3613                                            MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3614 {
3615         if (!context_used) {
3616                 MonoInst *ins;
3617
3618                 switch (rgctx_type) {
3619                 case MONO_RGCTX_INFO_METHOD:
3620                         EMIT_NEW_METHODCONST (cfg, ins, cmethod);
3621                         return ins;
3622                 case MONO_RGCTX_INFO_METHOD_RGCTX:
3623                         EMIT_NEW_METHOD_RGCTX_CONST (cfg, ins, cmethod);
3624                         return ins;
3625                 default:
3626                         g_assert_not_reached ();
3627                 }
3628         } else {
3629                 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);
3630                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3631
3632                 return emit_rgctx_fetch (cfg, rgctx, entry);
3633         }
3634 }
3635
3636 static MonoInst*
3637 emit_get_rgctx_field (MonoCompile *cfg, int context_used,
3638                                           MonoClassField *field, MonoRgctxInfoType rgctx_type)
3639 {
3640         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);
3641         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3642
3643         return emit_rgctx_fetch (cfg, rgctx, entry);
3644 }
3645
3646 static int
3647 get_gsharedvt_info_slot (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3648 {
3649         MonoGSharedVtMethodInfo *info = cfg->gsharedvt_info;
3650         MonoRuntimeGenericContextInfoTemplate *template;
3651         int i, idx;
3652
3653         g_assert (info);
3654
3655         for (i = 0; i < info->num_entries; ++i) {
3656                 MonoRuntimeGenericContextInfoTemplate *otemplate = &info->entries [i];
3657
3658                 if (otemplate->info_type == rgctx_type && otemplate->data == data && rgctx_type != MONO_RGCTX_INFO_LOCAL_OFFSET)
3659                         return i;
3660         }
3661
3662         if (info->num_entries == info->count_entries) {
3663                 MonoRuntimeGenericContextInfoTemplate *new_entries;
3664                 int new_count_entries = info->count_entries ? info->count_entries * 2 : 16;
3665
3666                 new_entries = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * new_count_entries);
3667
3668                 memcpy (new_entries, info->entries, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
3669                 info->entries = new_entries;
3670                 info->count_entries = new_count_entries;
3671         }
3672
3673         idx = info->num_entries;
3674         template = &info->entries [idx];
3675         template->info_type = rgctx_type;
3676         template->data = data;
3677
3678         info->num_entries ++;
3679
3680         return idx;
3681 }
3682
3683 /*
3684  * emit_get_gsharedvt_info:
3685  *
3686  *   This is similar to emit_get_rgctx_.., but loads the data from the gsharedvt info var instead of calling an rgctx fetch trampoline.
3687  */
3688 static MonoInst*
3689 emit_get_gsharedvt_info (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3690 {
3691         MonoInst *ins;
3692         int idx, dreg;
3693
3694         idx = get_gsharedvt_info_slot (cfg, data, rgctx_type);
3695         /* Load info->entries [idx] */
3696         dreg = alloc_preg (cfg);
3697         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, cfg->gsharedvt_info_var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
3698
3699         return ins;
3700 }
3701
3702 static MonoInst*
3703 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type)
3704 {
3705         return emit_get_gsharedvt_info (cfg, &klass->byval_arg, rgctx_type);
3706 }
3707
3708 /*
3709  * On return the caller must check @klass for load errors.
3710  */
3711 static void
3712 emit_class_init (MonoCompile *cfg, MonoClass *klass)
3713 {
3714         MonoInst *vtable_arg;
3715         int context_used;
3716         gboolean use_op_generic_class_init = FALSE;
3717
3718         context_used = mini_class_check_context_used (cfg, klass);
3719
3720         if (context_used) {
3721                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
3722                                                                                    klass, MONO_RGCTX_INFO_VTABLE);
3723         } else {
3724                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3725
3726                 if (!vtable)
3727                         return;
3728                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
3729         }
3730
3731 #ifdef MONO_ARCH_HAVE_OP_GENERIC_CLASS_INIT
3732         if (!COMPILE_LLVM (cfg))
3733                 use_op_generic_class_init = TRUE;
3734 #endif
3735
3736         if (use_op_generic_class_init) {
3737                 MonoInst *ins;
3738
3739                 /*
3740                  * Using an opcode instead of emitting IR here allows the hiding of the call inside the opcode,
3741                  * so this doesn't have to clobber any regs and it doesn't break basic blocks.
3742                  */
3743                 MONO_INST_NEW (cfg, ins, OP_GENERIC_CLASS_INIT);
3744                 ins->sreg1 = vtable_arg->dreg;
3745                 MONO_ADD_INS (cfg->cbb, ins);
3746         } else {
3747                 static int byte_offset = -1;
3748                 static guint8 bitmask;
3749                 int bits_reg, inited_reg;
3750                 MonoBasicBlock *inited_bb;
3751                 MonoInst *args [16];
3752
3753                 if (byte_offset < 0)
3754                         mono_marshal_find_bitfield_offset (MonoVTable, initialized, &byte_offset, &bitmask);
3755
3756                 bits_reg = alloc_ireg (cfg);
3757                 inited_reg = alloc_ireg (cfg);
3758
3759                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, bits_reg, vtable_arg->dreg, byte_offset);
3760                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, inited_reg, bits_reg, bitmask);
3761
3762                 NEW_BBLOCK (cfg, inited_bb);
3763
3764                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, inited_reg, 0);
3765                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, inited_bb);
3766
3767                 args [0] = vtable_arg;
3768                 mono_emit_jit_icall (cfg, mono_generic_class_init, args);
3769
3770                 MONO_START_BB (cfg, inited_bb);
3771         }
3772 }
3773
3774 static void
3775 emit_seq_point (MonoCompile *cfg, MonoMethod *method, guint8* ip, gboolean intr_loc, gboolean nonempty_stack)
3776 {
3777         MonoInst *ins;
3778
3779         if (cfg->gen_seq_points && cfg->method == method) {
3780                 NEW_SEQ_POINT (cfg, ins, ip - cfg->header->code, intr_loc);
3781                 if (nonempty_stack)
3782                         ins->flags |= MONO_INST_NONEMPTY_STACK;
3783                 MONO_ADD_INS (cfg->cbb, ins);
3784         }
3785 }
3786
3787 static void
3788 save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean null_check)
3789 {
3790         if (mini_get_debug_options ()->better_cast_details) {
3791                 int vtable_reg = alloc_preg (cfg);
3792                 int klass_reg = alloc_preg (cfg);
3793                 MonoBasicBlock *is_null_bb = NULL;
3794                 MonoInst *tls_get;
3795                 int to_klass_reg, context_used;
3796
3797                 if (null_check) {
3798                         NEW_BBLOCK (cfg, is_null_bb);
3799
3800                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3801                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3802                 }
3803
3804                 tls_get = mono_get_jit_tls_intrinsic (cfg);
3805                 if (!tls_get) {
3806                         fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
3807                         exit (1);
3808                 }
3809
3810                 MONO_ADD_INS (cfg->cbb, tls_get);
3811                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3812                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3813
3814                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg);
3815
3816                 context_used = mini_class_check_context_used (cfg, klass);
3817                 if (context_used) {
3818                         MonoInst *class_ins;
3819
3820                         class_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3821                         to_klass_reg = class_ins->dreg;
3822                 } else {
3823                         to_klass_reg = alloc_preg (cfg);
3824                         MONO_EMIT_NEW_CLASSCONST (cfg, to_klass_reg, klass);
3825                 }
3826                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg);
3827
3828                 if (null_check)
3829                         MONO_START_BB (cfg, is_null_bb);
3830         }
3831 }
3832
3833 static void
3834 reset_cast_details (MonoCompile *cfg)
3835 {
3836         /* Reset the variables holding the cast details */
3837         if (mini_get_debug_options ()->better_cast_details) {
3838                 MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
3839
3840                 MONO_ADD_INS (cfg->cbb, tls_get);
3841                 /* It is enough to reset the from field */
3842                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0);
3843         }
3844 }
3845
3846 /*
3847  * On return the caller must check @array_class for load errors
3848  */
3849 static void
3850 mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_class)
3851 {
3852         int vtable_reg = alloc_preg (cfg);
3853         int context_used;
3854
3855         context_used = mini_class_check_context_used (cfg, array_class);
3856
3857         save_cast_details (cfg, array_class, obj->dreg, FALSE);
3858
3859         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3860
3861         if (cfg->opt & MONO_OPT_SHARED) {
3862                 int class_reg = alloc_preg (cfg);
3863                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, class_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3864                 if (cfg->compile_aot) {
3865                         int klass_reg = alloc_preg (cfg);
3866                         MONO_EMIT_NEW_CLASSCONST (cfg, klass_reg, array_class);
3867                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, class_reg, klass_reg);
3868                 } else {
3869                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, class_reg, array_class);
3870                 }
3871         } else if (context_used) {
3872                 MonoInst *vtable_ins;
3873
3874                 vtable_ins = emit_get_rgctx_klass (cfg, context_used, array_class, MONO_RGCTX_INFO_VTABLE);
3875                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vtable_ins->dreg);
3876         } else {
3877                 if (cfg->compile_aot) {
3878                         int vt_reg;
3879                         MonoVTable *vtable;
3880
3881                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3882                                 return;
3883                         vt_reg = alloc_preg (cfg);
3884                         MONO_EMIT_NEW_VTABLECONST (cfg, vt_reg, vtable);
3885                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vt_reg);
3886                 } else {
3887                         MonoVTable *vtable;
3888                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3889                                 return;
3890                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vtable);
3891                 }
3892         }
3893         
3894         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException");
3895
3896         reset_cast_details (cfg);
3897 }
3898
3899 /**
3900  * Handles unbox of a Nullable<T>. If context_used is non zero, then shared 
3901  * generic code is generated.
3902  */
3903 static MonoInst*
3904 handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int context_used)
3905 {
3906         MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
3907
3908         if (context_used) {
3909                 MonoInst *rgctx, *addr;
3910
3911                 /* FIXME: What if the class is shared?  We might not
3912                    have to get the address of the method from the
3913                    RGCTX. */
3914                 addr = emit_get_rgctx_method (cfg, context_used, method,
3915                                                                           MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
3916
3917                 rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3918
3919                 return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
3920         } else {
3921                 gboolean pass_vtable, pass_mrgctx;
3922                 MonoInst *rgctx_arg = NULL;
3923
3924                 check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
3925                 g_assert (!pass_mrgctx);
3926
3927                 if (pass_vtable) {
3928                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
3929
3930                         g_assert (vtable);
3931                         EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
3932                 }
3933
3934                 return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
3935         }
3936 }
3937
3938 static MonoInst*
3939 handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_used)
3940 {
3941         MonoInst *add;
3942         int obj_reg;
3943         int vtable_reg = alloc_dreg (cfg ,STACK_PTR);
3944         int klass_reg = alloc_dreg (cfg ,STACK_PTR);
3945         int eclass_reg = alloc_dreg (cfg ,STACK_PTR);
3946         int rank_reg = alloc_dreg (cfg ,STACK_I4);
3947
3948         obj_reg = sp [0]->dreg;
3949         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3950         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
3951
3952         /* FIXME: generics */
3953         g_assert (klass->rank == 0);
3954                         
3955         // Check rank == 0
3956         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, 0);
3957         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3958
3959         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3960         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, element_class));
3961
3962         if (context_used) {
3963                 MonoInst *element_class;
3964
3965                 /* This assertion is from the unboxcast insn */
3966                 g_assert (klass->rank == 0);
3967
3968                 element_class = emit_get_rgctx_klass (cfg, context_used,
3969                                 klass, MONO_RGCTX_INFO_ELEMENT_KLASS);
3970
3971                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, eclass_reg, element_class->dreg);
3972                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3973         } else {
3974                 save_cast_details (cfg, klass->element_class, obj_reg, FALSE);
3975                 mini_emit_class_check (cfg, eclass_reg, klass->element_class);
3976                 reset_cast_details (cfg);
3977         }
3978
3979         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), obj_reg, sizeof (MonoObject));
3980         MONO_ADD_INS (cfg->cbb, add);
3981         add->type = STACK_MP;
3982         add->klass = klass;
3983
3984         return add;
3985 }
3986
3987 static MonoInst*
3988 handle_unbox_gsharedvt (MonoCompile *cfg, MonoClass *klass, MonoInst *obj)
3989 {
3990         MonoInst *addr, *klass_inst, *is_ref, *args[16];
3991         MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
3992         MonoInst *ins;
3993         int dreg, addr_reg;
3994
3995         klass_inst = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_KLASS);
3996
3997         /* obj */
3998         args [0] = obj;
3999
4000         /* klass */
4001         args [1] = klass_inst;
4002
4003         /* CASTCLASS */
4004         obj = mono_emit_jit_icall (cfg, mono_object_castclass_unbox, args);
4005
4006         NEW_BBLOCK (cfg, is_ref_bb);
4007         NEW_BBLOCK (cfg, is_nullable_bb);
4008         NEW_BBLOCK (cfg, end_bb);
4009         is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4010         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 1);
4011         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4012
4013         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 2);
4014         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4015
4016         /* This will contain either the address of the unboxed vtype, or an address of the temporary where the ref is stored */
4017         addr_reg = alloc_dreg (cfg, STACK_MP);
4018
4019         /* Non-ref case */
4020         /* UNBOX */
4021         NEW_BIALU_IMM (cfg, addr, OP_ADD_IMM, addr_reg, obj->dreg, sizeof (MonoObject));
4022         MONO_ADD_INS (cfg->cbb, addr);
4023
4024         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4025
4026         /* Ref case */
4027         MONO_START_BB (cfg, is_ref_bb);
4028
4029         /* Save the ref to a temporary */
4030         dreg = alloc_ireg (cfg);
4031         EMIT_NEW_VARLOADA_VREG (cfg, addr, dreg, &klass->byval_arg);
4032         addr->dreg = addr_reg;
4033         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, obj->dreg);
4034         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4035
4036         /* Nullable case */
4037         MONO_START_BB (cfg, is_nullable_bb);
4038
4039         {
4040                 MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX);
4041                 MonoInst *unbox_call;
4042                 MonoMethodSignature *unbox_sig;
4043
4044                 unbox_sig = mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4045                 unbox_sig->ret = &klass->byval_arg;
4046                 unbox_sig->param_count = 1;
4047                 unbox_sig->params [0] = &mono_defaults.object_class->byval_arg;
4048                 unbox_call = mono_emit_calli (cfg, unbox_sig, &obj, addr, NULL, NULL);
4049
4050                 EMIT_NEW_VARLOADA_VREG (cfg, addr, unbox_call->dreg, &klass->byval_arg);
4051                 addr->dreg = addr_reg;
4052         }
4053
4054         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4055
4056         /* End */
4057         MONO_START_BB (cfg, end_bb);
4058
4059         /* LDOBJ */
4060         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr_reg, 0);
4061
4062         return ins;
4063 }
4064
4065 /*
4066  * Returns NULL and set the cfg exception on error.
4067  */
4068 static MonoInst*
4069 handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_used)
4070 {
4071         MonoInst *iargs [2];
4072         void *alloc_ftn;
4073
4074         if (context_used) {
4075                 MonoInst *data;
4076                 int rgctx_info;
4077                 MonoInst *iargs [2];
4078                 gboolean known_instance_size = !mini_is_gsharedvt_klass (klass);
4079
4080                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (klass, for_box, known_instance_size);
4081
4082                 if (cfg->opt & MONO_OPT_SHARED)
4083                         rgctx_info = MONO_RGCTX_INFO_KLASS;
4084                 else
4085                         rgctx_info = MONO_RGCTX_INFO_VTABLE;
4086                 data = emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
4087
4088                 if (cfg->opt & MONO_OPT_SHARED) {
4089                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4090                         iargs [1] = data;
4091                         alloc_ftn = mono_object_new;
4092                 } else {
4093                         iargs [0] = data;
4094                         alloc_ftn = mono_object_new_specific;
4095                 }
4096
4097                 if (managed_alloc && !(cfg->opt & MONO_OPT_SHARED)) {
4098                         if (known_instance_size) {
4099                                 int size = mono_class_instance_size (klass);
4100                                 if (size < sizeof (MonoObject))
4101                                         g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4102
4103                                 EMIT_NEW_ICONST (cfg, iargs [1], mono_gc_get_aligned_size_for_allocator (size));
4104                         }
4105                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4106                 }
4107
4108                 return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4109         }
4110
4111         if (cfg->opt & MONO_OPT_SHARED) {
4112                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4113                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
4114
4115                 alloc_ftn = mono_object_new;
4116         } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !klass->generic_class) {
4117                 /* This happens often in argument checking code, eg. throw new FooException... */
4118                 /* Avoid relocations and save some space by calling a helper function specialized to mscorlib */
4119                 EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
4120                 return mono_emit_jit_icall (cfg, mono_helper_newobj_mscorlib, iargs);
4121         } else {
4122                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
4123                 MonoMethod *managed_alloc = NULL;
4124                 gboolean pass_lw;
4125
4126                 if (!vtable) {
4127                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4128                         cfg->exception_ptr = klass;
4129                         return NULL;
4130                 }
4131
4132                 managed_alloc = mono_gc_get_managed_allocator (klass, for_box, TRUE);
4133
4134                 if (managed_alloc) {
4135                         int size = mono_class_instance_size (klass);
4136                         if (size < sizeof (MonoObject))
4137                                 g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4138
4139                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4140                         EMIT_NEW_ICONST (cfg, iargs [1], mono_gc_get_aligned_size_for_allocator (size));
4141                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4142                 }
4143                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
4144                 if (pass_lw) {
4145                         guint32 lw = vtable->klass->instance_size;
4146                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
4147                         EMIT_NEW_ICONST (cfg, iargs [0], lw);
4148                         EMIT_NEW_VTABLECONST (cfg, iargs [1], vtable);
4149                 }
4150                 else {
4151                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4152                 }
4153         }
4154
4155         return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4156 }
4157         
4158 /*
4159  * Returns NULL and set the cfg exception on error.
4160  */     
4161 static MonoInst*
4162 handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used)
4163 {
4164         MonoInst *alloc, *ins;
4165
4166         if (mono_class_is_nullable (klass)) {
4167                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
4168
4169                 if (context_used) {
4170                         /* FIXME: What if the class is shared?  We might not
4171                            have to get the method address from the RGCTX. */
4172                         MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4173                                                                                                         MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4174                         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
4175
4176                         return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
4177                 } else {
4178                         gboolean pass_vtable, pass_mrgctx;
4179                         MonoInst *rgctx_arg = NULL;
4180
4181                         check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
4182                         g_assert (!pass_mrgctx);
4183
4184                         if (pass_vtable) {
4185                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4186
4187                                 g_assert (vtable);
4188                                 EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
4189                         }
4190
4191                         return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4192                 }
4193         }
4194
4195         if (mini_is_gsharedvt_klass (klass)) {
4196                 MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4197                 MonoInst *res, *is_ref, *src_var, *addr;
4198                 int dreg;
4199
4200                 dreg = alloc_ireg (cfg);
4201
4202                 NEW_BBLOCK (cfg, is_ref_bb);
4203                 NEW_BBLOCK (cfg, is_nullable_bb);
4204                 NEW_BBLOCK (cfg, end_bb);
4205                 is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4206                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 1);
4207                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4208
4209                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 2);
4210                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4211
4212                 /* Non-ref case */
4213                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4214                 if (!alloc)
4215                         return NULL;
4216                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4217                 ins->opcode = OP_STOREV_MEMBASE;
4218
4219                 EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, alloc->dreg);
4220                 res->type = STACK_OBJ;
4221                 res->klass = klass;
4222                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4223                 
4224                 /* Ref case */
4225                 MONO_START_BB (cfg, is_ref_bb);
4226
4227                 /* val is a vtype, so has to load the value manually */
4228                 src_var = get_vreg_to_inst (cfg, val->dreg);
4229                 if (!src_var)
4230                         src_var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, val->dreg);
4231                 EMIT_NEW_VARLOADA (cfg, addr, src_var, src_var->inst_vtype);
4232                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, addr->dreg, 0);
4233                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4234
4235                 /* Nullable case */
4236                 MONO_START_BB (cfg, is_nullable_bb);
4237
4238                 {
4239                         MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass,
4240                                                                                                         MONO_RGCTX_INFO_NULLABLE_CLASS_BOX);
4241                         MonoInst *box_call;
4242                         MonoMethodSignature *box_sig;
4243
4244                         /*
4245                          * klass is Nullable<T>, need to call Nullable<T>.Box () using a gsharedvt signature, but we cannot
4246                          * construct that method at JIT time, so have to do things by hand.
4247                          */
4248                         box_sig = mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4249                         box_sig->ret = &mono_defaults.object_class->byval_arg;
4250                         box_sig->param_count = 1;
4251                         box_sig->params [0] = &klass->byval_arg;
4252                         box_call = mono_emit_calli (cfg, box_sig, &val, addr, NULL, NULL);
4253                         EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, box_call->dreg);
4254                         res->type = STACK_OBJ;
4255                         res->klass = klass;
4256                 }
4257
4258                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4259
4260                 MONO_START_BB (cfg, end_bb);
4261
4262                 return res;
4263         } else {
4264                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4265                 if (!alloc)
4266                         return NULL;
4267
4268                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4269                 return alloc;
4270         }
4271 }
4272
4273 static gboolean
4274 mini_class_has_reference_variant_generic_argument (MonoCompile *cfg, MonoClass *klass, int context_used)
4275 {
4276         int i;
4277         MonoGenericContainer *container;
4278         MonoGenericInst *ginst;
4279
4280         if (klass->generic_class) {
4281                 container = klass->generic_class->container_class->generic_container;
4282                 ginst = klass->generic_class->context.class_inst;
4283         } else if (klass->generic_container && context_used) {
4284                 container = klass->generic_container;
4285                 ginst = container->context.class_inst;
4286         } else {
4287                 return FALSE;
4288         }
4289
4290         for (i = 0; i < container->type_argc; ++i) {
4291                 MonoType *type;
4292                 if (!(mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT)))
4293                         continue;
4294                 type = ginst->type_argv [i];
4295                 if (mini_type_is_reference (type))
4296                         return TRUE;
4297         }
4298         return FALSE;
4299 }
4300
4301 static GHashTable* direct_icall_type_hash;
4302
4303 static gboolean
4304 icall_is_direct_callable (MonoCompile *cfg, MonoMethod *cmethod)
4305 {
4306         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
4307         if (!direct_icalls_enabled (cfg))
4308                 return FALSE;
4309
4310         /*
4311          * An icall is directly callable if it doesn't directly or indirectly call mono_raise_exception ().
4312          * Whitelist a few icalls for now.
4313          */
4314         if (!direct_icall_type_hash) {
4315                 GHashTable *h = g_hash_table_new (g_str_hash, g_str_equal);
4316
4317                 g_hash_table_insert (h, (char*)"Decimal", GUINT_TO_POINTER (1));
4318                 g_hash_table_insert (h, (char*)"Number", GUINT_TO_POINTER (1));
4319                 g_hash_table_insert (h, (char*)"Buffer", GUINT_TO_POINTER (1));
4320                 mono_memory_barrier ();
4321                 direct_icall_type_hash = h;
4322         }
4323
4324         if (cmethod->klass == mono_defaults.math_class)
4325                 return TRUE;
4326         /* No locking needed */
4327         if (cmethod->klass->image == mono_defaults.corlib && g_hash_table_lookup (direct_icall_type_hash, cmethod->klass->name))
4328                 return TRUE;
4329         return FALSE;
4330 }
4331
4332 #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)
4333
4334 static MonoInst*
4335 emit_castclass_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args)
4336 {
4337         MonoMethod *mono_castclass;
4338         MonoInst *res;
4339
4340         mono_castclass = mono_marshal_get_castclass_with_cache ();
4341
4342         save_cast_details (cfg, klass, args [0]->dreg, TRUE);
4343         res = mono_emit_method_call (cfg, mono_castclass, args, NULL);
4344         reset_cast_details (cfg);
4345
4346         return res;
4347 }
4348
4349 static int
4350 get_castclass_cache_idx (MonoCompile *cfg)
4351 {
4352         /* Each CASTCLASS_CACHE patch needs a unique index which identifies the call site */
4353         cfg->castclass_cache_index ++;
4354         return (cfg->method_index << 16) | cfg->castclass_cache_index;
4355 }
4356
4357 static MonoInst*
4358 emit_castclass_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass *klass)
4359 {
4360         MonoInst *args [3];
4361         int idx;
4362
4363         /* obj */
4364         args [0] = obj;
4365
4366         /* klass */
4367         EMIT_NEW_CLASSCONST (cfg, args [1], klass);
4368
4369         /* inline cache*/
4370         if (cfg->compile_aot) {
4371                 idx = get_castclass_cache_idx (cfg);
4372                 EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
4373         } else {
4374                 EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
4375         }
4376
4377         /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
4378         return emit_castclass_with_cache (cfg, klass, args);
4379 }
4380
4381 /*
4382  * Returns NULL and set the cfg exception on error.
4383  */
4384 static MonoInst*
4385 handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, guint8 *ip, int *inline_costs)
4386 {
4387         MonoBasicBlock *is_null_bb;
4388         int obj_reg = src->dreg;
4389         int vtable_reg = alloc_preg (cfg);
4390         int context_used;
4391         MonoInst *klass_inst = NULL, *res;
4392
4393         context_used = mini_class_check_context_used (cfg, klass);
4394
4395         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
4396                 res = emit_castclass_with_cache_nonshared (cfg, src, klass);
4397                 (*inline_costs) += 2;
4398                 return res;
4399         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
4400                 MonoMethod *mono_castclass;
4401                 MonoInst *iargs [1];
4402                 int costs;
4403
4404                 mono_castclass = mono_marshal_get_castclass (klass); 
4405                 iargs [0] = src;
4406                                 
4407                 save_cast_details (cfg, klass, src->dreg, TRUE);
4408                 costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
4409                                                            iargs, ip, cfg->real_offset, TRUE);
4410                 reset_cast_details (cfg);
4411                 CHECK_CFG_EXCEPTION;
4412                 g_assert (costs > 0);
4413                                 
4414                 cfg->real_offset += 5;
4415
4416                 (*inline_costs) += costs;
4417
4418                 return src;
4419         }
4420
4421         if (context_used) {
4422                 MonoInst *args [3];
4423
4424                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4425                         MonoInst *cache_ins;
4426
4427                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4428
4429                         /* obj */
4430                         args [0] = src;
4431
4432                         /* klass - it's the second element of the cache entry*/
4433                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4434
4435                         /* cache */
4436                         args [2] = cache_ins;
4437
4438                         return emit_castclass_with_cache (cfg, klass, args);
4439                 }
4440
4441                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4442         }
4443
4444         NEW_BBLOCK (cfg, is_null_bb);
4445
4446         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4447         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
4448
4449         save_cast_details (cfg, klass, obj_reg, FALSE);
4450
4451         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4452                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4453                 mini_emit_iface_cast (cfg, vtable_reg, klass, NULL, NULL);
4454         } else {
4455                 int klass_reg = alloc_preg (cfg);
4456
4457                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4458
4459                 if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4460                         /* the remoting code is broken, access the class for now */
4461                         if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4462                                 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4463                                 if (!vt) {
4464                                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4465                                         cfg->exception_ptr = klass;
4466                                         return NULL;
4467                                 }
4468                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4469                         } else {
4470                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4471                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4472                         }
4473                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4474                 } else {
4475                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4476                         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, klass_inst, is_null_bb);
4477                 }
4478         }
4479
4480         MONO_START_BB (cfg, is_null_bb);
4481
4482         reset_cast_details (cfg);
4483
4484         return src;
4485
4486 exception_exit:
4487         return NULL;
4488 }
4489
4490 /*
4491  * Returns NULL and set the cfg exception on error.
4492  */
4493 static MonoInst*
4494 handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
4495 {
4496         MonoInst *ins;
4497         MonoBasicBlock *is_null_bb, *false_bb, *end_bb;
4498         int obj_reg = src->dreg;
4499         int vtable_reg = alloc_preg (cfg);
4500         int res_reg = alloc_ireg_ref (cfg);
4501         MonoInst *klass_inst = NULL;
4502
4503         if (context_used) {
4504                 MonoInst *args [3];
4505
4506                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4507                         MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
4508                         MonoInst *cache_ins;
4509
4510                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4511
4512                         /* obj */
4513                         args [0] = src;
4514
4515                         /* klass - it's the second element of the cache entry*/
4516                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4517
4518                         /* cache */
4519                         args [2] = cache_ins;
4520
4521                         return mono_emit_method_call (cfg, mono_isinst, args, NULL);
4522                 }
4523
4524                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4525         }
4526
4527         NEW_BBLOCK (cfg, is_null_bb);
4528         NEW_BBLOCK (cfg, false_bb);
4529         NEW_BBLOCK (cfg, end_bb);
4530
4531         /* Do the assignment at the beginning, so the other assignment can be if converted */
4532         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, res_reg, obj_reg);
4533         ins->type = STACK_OBJ;
4534         ins->klass = klass;
4535
4536         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4537         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_null_bb);
4538
4539         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4540
4541         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4542                 g_assert (!context_used);
4543                 /* the is_null_bb target simply copies the input register to the output */
4544                 mini_emit_iface_cast (cfg, vtable_reg, klass, false_bb, is_null_bb);
4545         } else {
4546                 int klass_reg = alloc_preg (cfg);
4547
4548                 if (klass->rank) {
4549                         int rank_reg = alloc_preg (cfg);
4550                         int eclass_reg = alloc_preg (cfg);
4551
4552                         g_assert (!context_used);
4553                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
4554                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
4555                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4556                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4557                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
4558                         if (klass->cast_class == mono_defaults.object_class) {
4559                                 int parent_reg = alloc_preg (cfg);
4560                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
4561                                 mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, is_null_bb);
4562                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4563                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4564                         } else if (klass->cast_class == mono_defaults.enum_class->parent) {
4565                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, is_null_bb);
4566                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);                          
4567                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4568                         } else if (klass->cast_class == mono_defaults.enum_class) {
4569                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4570                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4571                         } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
4572                                 mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4573                         } else {
4574                                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY)) {
4575                                         /* Check that the object is a vector too */
4576                                         int bounds_reg = alloc_preg (cfg);
4577                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
4578                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
4579                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4580                                 }
4581
4582                                 /* the is_null_bb target simply copies the input register to the output */
4583                                 mini_emit_isninst_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4584                         }
4585                 } else if (mono_class_is_nullable (klass)) {
4586                         g_assert (!context_used);
4587                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4588                         /* the is_null_bb target simply copies the input register to the output */
4589                         mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb);
4590                 } else {
4591                         if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4592                                 g_assert (!context_used);
4593                                 /* the remoting code is broken, access the class for now */
4594                                 if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4595                                         MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4596                                         if (!vt) {
4597                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4598                                                 cfg->exception_ptr = klass;
4599                                                 return NULL;
4600                                         }
4601                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4602                                 } else {
4603                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4604                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4605                                 }
4606                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4607                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
4608                         } else {
4609                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4610                                 /* the is_null_bb target simply copies the input register to the output */
4611                                 mini_emit_isninst_cast_inst (cfg, klass_reg, klass, klass_inst, false_bb, is_null_bb);
4612                         }
4613                 }
4614         }
4615
4616         MONO_START_BB (cfg, false_bb);
4617
4618         MONO_EMIT_NEW_PCONST (cfg, res_reg, 0);
4619         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4620
4621         MONO_START_BB (cfg, is_null_bb);
4622
4623         MONO_START_BB (cfg, end_bb);
4624
4625         return ins;
4626 }
4627
4628 static MonoInst*
4629 handle_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4630 {
4631         /* This opcode takes as input an object reference and a class, and returns:
4632         0) if the object is an instance of the class,
4633         1) if the object is not instance of the class,
4634         2) if the object is a proxy whose type cannot be determined */
4635
4636         MonoInst *ins;
4637 #ifndef DISABLE_REMOTING
4638         MonoBasicBlock *true_bb, *false_bb, *false2_bb, *end_bb, *no_proxy_bb, *interface_fail_bb;
4639 #else
4640         MonoBasicBlock *true_bb, *false_bb, *end_bb;
4641 #endif
4642         int obj_reg = src->dreg;
4643         int dreg = alloc_ireg (cfg);
4644         int tmp_reg;
4645 #ifndef DISABLE_REMOTING
4646         int klass_reg = alloc_preg (cfg);
4647 #endif
4648
4649         NEW_BBLOCK (cfg, true_bb);
4650         NEW_BBLOCK (cfg, false_bb);
4651         NEW_BBLOCK (cfg, end_bb);
4652 #ifndef DISABLE_REMOTING
4653         NEW_BBLOCK (cfg, false2_bb);
4654         NEW_BBLOCK (cfg, no_proxy_bb);
4655 #endif
4656
4657         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4658         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
4659
4660         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4661 #ifndef DISABLE_REMOTING
4662                 NEW_BBLOCK (cfg, interface_fail_bb);
4663 #endif
4664
4665                 tmp_reg = alloc_preg (cfg);
4666                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4667 #ifndef DISABLE_REMOTING
4668                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, true_bb);
4669                 MONO_START_BB (cfg, interface_fail_bb);
4670                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4671                 
4672                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, false_bb);
4673
4674                 tmp_reg = alloc_preg (cfg);
4675                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4676                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4677                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false2_bb);                
4678 #else
4679                 mini_emit_iface_cast (cfg, tmp_reg, klass, false_bb, true_bb);
4680 #endif
4681         } else {
4682 #ifndef DISABLE_REMOTING
4683                 tmp_reg = alloc_preg (cfg);
4684                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4685                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4686
4687                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4688                 tmp_reg = alloc_preg (cfg);
4689                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4690                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4691
4692                 tmp_reg = alloc_preg (cfg);             
4693                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4694                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4695                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4696                 
4697                 mini_emit_isninst_cast (cfg, klass_reg, klass, false2_bb, true_bb);
4698                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false2_bb);
4699
4700                 MONO_START_BB (cfg, no_proxy_bb);
4701
4702                 mini_emit_isninst_cast (cfg, klass_reg, klass, false_bb, true_bb);
4703 #else
4704                 g_error ("transparent proxy support is disabled while trying to JIT code that uses it");
4705 #endif
4706         }
4707
4708         MONO_START_BB (cfg, false_bb);
4709
4710         MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4711         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4712
4713 #ifndef DISABLE_REMOTING
4714         MONO_START_BB (cfg, false2_bb);
4715
4716         MONO_EMIT_NEW_ICONST (cfg, dreg, 2);
4717         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4718 #endif
4719
4720         MONO_START_BB (cfg, true_bb);
4721
4722         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4723
4724         MONO_START_BB (cfg, end_bb);
4725
4726         /* FIXME: */
4727         MONO_INST_NEW (cfg, ins, OP_ICONST);
4728         ins->dreg = dreg;
4729         ins->type = STACK_I4;
4730
4731         return ins;
4732 }
4733
4734 static MonoInst*
4735 handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4736 {
4737         /* This opcode takes as input an object reference and a class, and returns:
4738         0) if the object is an instance of the class,
4739         1) if the object is a proxy whose type cannot be determined
4740         an InvalidCastException exception is thrown otherwhise*/
4741         
4742         MonoInst *ins;
4743 #ifndef DISABLE_REMOTING
4744         MonoBasicBlock *end_bb, *ok_result_bb, *no_proxy_bb, *interface_fail_bb, *fail_1_bb;
4745 #else
4746         MonoBasicBlock *ok_result_bb;
4747 #endif
4748         int obj_reg = src->dreg;
4749         int dreg = alloc_ireg (cfg);
4750         int tmp_reg = alloc_preg (cfg);
4751
4752 #ifndef DISABLE_REMOTING
4753         int klass_reg = alloc_preg (cfg);
4754         NEW_BBLOCK (cfg, end_bb);
4755 #endif
4756
4757         NEW_BBLOCK (cfg, ok_result_bb);
4758
4759         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4760         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, ok_result_bb);
4761
4762         save_cast_details (cfg, klass, obj_reg, FALSE);
4763
4764         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4765 #ifndef DISABLE_REMOTING
4766                 NEW_BBLOCK (cfg, interface_fail_bb);
4767         
4768                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4769                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, ok_result_bb);
4770                 MONO_START_BB (cfg, interface_fail_bb);
4771                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4772
4773                 mini_emit_class_check (cfg, klass_reg, mono_defaults.transparent_proxy_class);
4774
4775                 tmp_reg = alloc_preg (cfg);             
4776                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4777                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4778                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
4779                 
4780                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4781                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4782 #else
4783                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4784                 mini_emit_iface_cast (cfg, tmp_reg, klass, NULL, NULL);
4785                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, ok_result_bb);
4786 #endif
4787         } else {
4788 #ifndef DISABLE_REMOTING
4789                 NEW_BBLOCK (cfg, no_proxy_bb);
4790
4791                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4792                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4793                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4794
4795                 tmp_reg = alloc_preg (cfg);
4796                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4797                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4798
4799                 tmp_reg = alloc_preg (cfg);
4800                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4801                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4802                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4803
4804                 NEW_BBLOCK (cfg, fail_1_bb);
4805                 
4806                 mini_emit_isninst_cast (cfg, klass_reg, klass, fail_1_bb, ok_result_bb);
4807
4808                 MONO_START_BB (cfg, fail_1_bb);
4809
4810                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4811                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4812
4813                 MONO_START_BB (cfg, no_proxy_bb);
4814
4815                 mini_emit_castclass (cfg, obj_reg, klass_reg, klass, ok_result_bb);
4816 #else
4817                 g_error ("Transparent proxy support is disabled while trying to JIT code that uses it");
4818 #endif
4819         }
4820
4821         MONO_START_BB (cfg, ok_result_bb);
4822
4823         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4824
4825 #ifndef DISABLE_REMOTING
4826         MONO_START_BB (cfg, end_bb);
4827 #endif
4828
4829         /* FIXME: */
4830         MONO_INST_NEW (cfg, ins, OP_ICONST);
4831         ins->dreg = dreg;
4832         ins->type = STACK_I4;
4833
4834         return ins;
4835 }
4836
4837 static G_GNUC_UNUSED MonoInst*
4838 handle_enum_has_flag (MonoCompile *cfg, MonoClass *klass, MonoInst *enum_this, MonoInst *enum_flag)
4839 {
4840         MonoType *enum_type = mono_type_get_underlying_type (&klass->byval_arg);
4841         guint32 load_opc = mono_type_to_load_membase (cfg, enum_type);
4842         gboolean is_i4;
4843
4844         switch (enum_type->type) {
4845         case MONO_TYPE_I8:
4846         case MONO_TYPE_U8:
4847 #if SIZEOF_REGISTER == 8
4848         case MONO_TYPE_I:
4849         case MONO_TYPE_U:
4850 #endif
4851                 is_i4 = FALSE;
4852                 break;
4853         default:
4854                 is_i4 = TRUE;
4855                 break;
4856         }
4857
4858         {
4859                 MonoInst *load, *and, *cmp, *ceq;
4860                 int enum_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4861                 int and_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4862                 int dest_reg = alloc_ireg (cfg);
4863
4864                 EMIT_NEW_LOAD_MEMBASE (cfg, load, load_opc, enum_reg, enum_this->dreg, 0);
4865                 EMIT_NEW_BIALU (cfg, and, is_i4 ? OP_IAND : OP_LAND, and_reg, enum_reg, enum_flag->dreg);
4866                 EMIT_NEW_BIALU (cfg, cmp, is_i4 ? OP_ICOMPARE : OP_LCOMPARE, -1, and_reg, enum_flag->dreg);
4867                 EMIT_NEW_UNALU (cfg, ceq, is_i4 ? OP_ICEQ : OP_LCEQ, dest_reg, -1);
4868
4869                 ceq->type = STACK_I4;
4870
4871                 if (!is_i4) {
4872                         load = mono_decompose_opcode (cfg, load);
4873                         and = mono_decompose_opcode (cfg, and);
4874                         cmp = mono_decompose_opcode (cfg, cmp);
4875                         ceq = mono_decompose_opcode (cfg, ceq);
4876                 }
4877
4878                 return ceq;
4879         }
4880 }
4881
4882 /*
4883  * Returns NULL and set the cfg exception on error.
4884  */
4885 static G_GNUC_UNUSED MonoInst*
4886 handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method, int context_used, gboolean virtual)
4887 {
4888         MonoInst *ptr;
4889         int dreg;
4890         gpointer trampoline;
4891         MonoInst *obj, *method_ins, *tramp_ins;
4892         MonoDomain *domain;
4893         guint8 **code_slot;
4894
4895         if (virtual) {
4896                 MonoMethod *invoke = mono_get_delegate_invoke (klass);
4897                 g_assert (invoke);
4898
4899                 if (!mono_get_delegate_virtual_invoke_impl (mono_method_signature (invoke), context_used ? NULL : method))
4900                         return NULL;
4901         }
4902
4903         obj = handle_alloc (cfg, klass, FALSE, 0);
4904         if (!obj)
4905                 return NULL;
4906
4907         /* Inline the contents of mono_delegate_ctor */
4908
4909         /* Set target field */
4910         /* Optimize away setting of NULL target */
4911         if (!(target->opcode == OP_PCONST && target->inst_p0 == 0)) {
4912                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
4913                 if (cfg->gen_write_barriers) {
4914                         dreg = alloc_preg (cfg);
4915                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target));
4916                         emit_write_barrier (cfg, ptr, target);
4917                 }
4918         }
4919
4920         /* Set method field */
4921         method_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
4922         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg);
4923
4924         /* 
4925          * To avoid looking up the compiled code belonging to the target method
4926          * in mono_delegate_trampoline (), we allocate a per-domain memory slot to
4927          * store it, and we fill it after the method has been compiled.
4928          */
4929         if (!method->dynamic && !(cfg->opt & MONO_OPT_SHARED)) {
4930                 MonoInst *code_slot_ins;
4931
4932                 if (context_used) {
4933                         code_slot_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD_DELEGATE_CODE);
4934                 } else {
4935                         domain = mono_domain_get ();
4936                         mono_domain_lock (domain);
4937                         if (!domain_jit_info (domain)->method_code_hash)
4938                                 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
4939                         code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, method);
4940                         if (!code_slot) {
4941                                 code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
4942                                 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, method, code_slot);
4943                         }
4944                         mono_domain_unlock (domain);
4945
4946                         if (cfg->compile_aot)
4947                                 EMIT_NEW_AOTCONST (cfg, code_slot_ins, MONO_PATCH_INFO_METHOD_CODE_SLOT, method);
4948                         else
4949                                 EMIT_NEW_PCONST (cfg, code_slot_ins, code_slot);
4950                 }
4951                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);                
4952         }
4953
4954         if (cfg->compile_aot) {
4955                 MonoDelegateClassMethodPair *del_tramp;
4956
4957                 del_tramp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoDelegateClassMethodPair));
4958                 del_tramp->klass = klass;
4959                 del_tramp->method = context_used ? NULL : method;
4960                 del_tramp->virtual = virtual;
4961                 EMIT_NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_DELEGATE_TRAMPOLINE, del_tramp);
4962         } else {
4963                 if (virtual)
4964                         trampoline = mono_create_delegate_virtual_trampoline (cfg->domain, klass, context_used ? NULL : method);
4965                 else
4966                         trampoline = mono_create_delegate_trampoline_info (cfg->domain, klass, context_used ? NULL : method);
4967                 EMIT_NEW_PCONST (cfg, tramp_ins, trampoline);
4968         }
4969
4970         /* Set invoke_impl field */
4971         if (virtual) {
4972                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), tramp_ins->dreg);
4973         } else {
4974                 dreg = alloc_preg (cfg);
4975                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, invoke_impl));
4976                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), dreg);
4977
4978                 dreg = alloc_preg (cfg);
4979                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, method_ptr));
4980                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr), dreg);
4981         }
4982
4983         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
4984
4985         return obj;
4986 }
4987
4988 static MonoInst*
4989 handle_array_new (MonoCompile *cfg, int rank, MonoInst **sp, unsigned char *ip)
4990 {
4991         MonoJitICallInfo *info;
4992
4993         /* Need to register the icall so it gets an icall wrapper */
4994         info = mono_get_array_new_va_icall (rank);
4995
4996         cfg->flags |= MONO_CFG_HAS_VARARGS;
4997
4998         /* mono_array_new_va () needs a vararg calling convention */
4999         cfg->disable_llvm = TRUE;
5000
5001         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
5002         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, sp);
5003 }
5004
5005 /*
5006  * handle_constrained_gsharedvt_call:
5007  *
5008  *   Handle constrained calls where the receiver is a gsharedvt type.
5009  * Return the instruction representing the call. Set the cfg exception on failure.
5010  */
5011 static MonoInst*
5012 handle_constrained_gsharedvt_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp, MonoClass *constrained_class,
5013                                                                    gboolean *ref_emit_widen)
5014 {
5015         MonoInst *ins = NULL;
5016         gboolean emit_widen = *ref_emit_widen;
5017
5018         /*
5019          * Constrained calls need to behave differently at runtime dependending on whenever the receiver is instantiated as ref type or as a vtype.
5020          * 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
5021          * pack the arguments into an array, and do the rest of the work in in an icall.
5022          */
5023         if (((cmethod->klass == mono_defaults.object_class) || (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) &&
5024                 (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)) &&
5025                 (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]))))) {
5026                 MonoInst *args [16];
5027
5028                 /*
5029                  * This case handles calls to
5030                  * - object:ToString()/Equals()/GetHashCode(),
5031                  * - System.IComparable<T>:CompareTo()
5032                  * - System.IEquatable<T>:Equals ()
5033                  * plus some simple interface calls enough to support AsyncTaskMethodBuilder.
5034                  */
5035
5036                 args [0] = sp [0];
5037                 if (mono_method_check_context_used (cmethod))
5038                         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cmethod), cmethod, MONO_RGCTX_INFO_METHOD);
5039                 else
5040                         EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
5041                 args [2] = emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_class), constrained_class, MONO_RGCTX_INFO_KLASS);
5042
5043                 /* !fsig->hasthis is for the wrapper for the Object.GetType () icall */
5044                 if (fsig->hasthis && fsig->param_count) {
5045                         /* Pass the arguments using a localloc-ed array using the format expected by runtime_invoke () */
5046                         MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
5047                         ins->dreg = alloc_preg (cfg);
5048                         ins->inst_imm = fsig->param_count * sizeof (mgreg_t);
5049                         MONO_ADD_INS (cfg->cbb, ins);
5050                         args [4] = ins;
5051
5052                         if (mini_is_gsharedvt_type (fsig->params [0])) {
5053                                 int addr_reg;
5054
5055                                 args [3] = emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type (fsig->params [0]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
5056
5057                                 EMIT_NEW_VARLOADA_VREG (cfg, ins, sp [1]->dreg, fsig->params [0]);
5058                                 addr_reg = ins->dreg;
5059                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, addr_reg);
5060                         } else {
5061                                 EMIT_NEW_ICONST (cfg, args [3], 0);
5062                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, sp [1]->dreg);
5063                         }
5064                 } else {
5065                         EMIT_NEW_ICONST (cfg, args [3], 0);
5066                         EMIT_NEW_ICONST (cfg, args [4], 0);
5067                 }
5068                 ins = mono_emit_jit_icall (cfg, mono_gsharedvt_constrained_call, args);
5069                 emit_widen = FALSE;
5070
5071                 if (mini_is_gsharedvt_type (fsig->ret)) {
5072                         ins = handle_unbox_gsharedvt (cfg, mono_class_from_mono_type (fsig->ret), ins);
5073                 } else if (MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret)) {
5074                         MonoInst *add;
5075
5076                         /* Unbox */
5077                         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), ins->dreg, sizeof (MonoObject));
5078                         MONO_ADD_INS (cfg->cbb, add);
5079                         /* Load value */
5080                         NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, add->dreg, 0);
5081                         MONO_ADD_INS (cfg->cbb, ins);
5082                         /* ins represents the call result */
5083                 }
5084         } else {
5085                 GSHAREDVT_FAILURE (CEE_CALLVIRT);
5086         }
5087
5088         *ref_emit_widen = emit_widen;
5089
5090         return ins;
5091
5092  exception_exit:
5093         return NULL;
5094 }
5095
5096 static void
5097 mono_emit_load_got_addr (MonoCompile *cfg)
5098 {
5099         MonoInst *getaddr, *dummy_use;
5100
5101         if (!cfg->got_var || cfg->got_var_allocated)
5102                 return;
5103
5104         MONO_INST_NEW (cfg, getaddr, OP_LOAD_GOTADDR);
5105         getaddr->cil_code = cfg->header->code;
5106         getaddr->dreg = cfg->got_var->dreg;
5107
5108         /* Add it to the start of the first bblock */
5109         if (cfg->bb_entry->code) {
5110                 getaddr->next = cfg->bb_entry->code;
5111                 cfg->bb_entry->code = getaddr;
5112         }
5113         else
5114                 MONO_ADD_INS (cfg->bb_entry, getaddr);
5115
5116         cfg->got_var_allocated = TRUE;
5117
5118         /* 
5119          * Add a dummy use to keep the got_var alive, since real uses might
5120          * only be generated by the back ends.
5121          * Add it to end_bblock, so the variable's lifetime covers the whole
5122          * method.
5123          * It would be better to make the usage of the got var explicit in all
5124          * cases when the backend needs it (i.e. calls, throw etc.), so this
5125          * wouldn't be needed.
5126          */
5127         NEW_DUMMY_USE (cfg, dummy_use, cfg->got_var);
5128         MONO_ADD_INS (cfg->bb_exit, dummy_use);
5129 }
5130
5131 static int inline_limit;
5132 static gboolean inline_limit_inited;
5133
5134 static gboolean
5135 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
5136 {
5137         MonoMethodHeaderSummary header;
5138         MonoVTable *vtable;
5139 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5140         MonoMethodSignature *sig = mono_method_signature (method);
5141         int i;
5142 #endif
5143
5144         if (cfg->disable_inline)
5145                 return FALSE;
5146         if (cfg->gshared)
5147                 return FALSE;
5148
5149         if (cfg->inline_depth > 10)
5150                 return FALSE;
5151
5152 #ifdef MONO_ARCH_HAVE_LMF_OPS
5153         if (((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
5154                  (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) &&
5155             !MONO_TYPE_ISSTRUCT (signature->ret) && !mini_class_is_system_array (method->klass))
5156                 return TRUE;
5157 #endif
5158
5159
5160         if (!mono_method_get_header_summary (method, &header))
5161                 return FALSE;
5162
5163         /*runtime, icall and pinvoke are checked by summary call*/
5164         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
5165             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
5166             (mono_class_is_marshalbyref (method->klass)) ||
5167             header.has_clauses)
5168                 return FALSE;
5169
5170         /* also consider num_locals? */
5171         /* Do the size check early to avoid creating vtables */
5172         if (!inline_limit_inited) {
5173                 if (g_getenv ("MONO_INLINELIMIT"))
5174                         inline_limit = atoi (g_getenv ("MONO_INLINELIMIT"));
5175                 else
5176                         inline_limit = INLINE_LENGTH_LIMIT;
5177                 inline_limit_inited = TRUE;
5178         }
5179         if (header.code_size >= inline_limit && !(method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
5180                 return FALSE;
5181
5182         /*
5183          * if we can initialize the class of the method right away, we do,
5184          * otherwise we don't allow inlining if the class needs initialization,
5185          * since it would mean inserting a call to mono_runtime_class_init()
5186          * inside the inlined code
5187          */
5188         if (!(cfg->opt & MONO_OPT_SHARED)) {
5189                 /* The AggressiveInlining hint is a good excuse to force that cctor to run. */
5190                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING) {
5191                         vtable = mono_class_vtable (cfg->domain, method->klass);
5192                         if (!vtable)
5193                                 return FALSE;
5194                         if (!cfg->compile_aot)
5195                                 mono_runtime_class_init (vtable);
5196                 } else if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5197                         if (cfg->run_cctors && method->klass->has_cctor) {
5198                                 /*FIXME it would easier and lazier to just use mono_class_try_get_vtable */
5199                                 if (!method->klass->runtime_info)
5200                                         /* No vtable created yet */
5201                                         return FALSE;
5202                                 vtable = mono_class_vtable (cfg->domain, method->klass);
5203                                 if (!vtable)
5204                                         return FALSE;
5205                                 /* This makes so that inline cannot trigger */
5206                                 /* .cctors: too many apps depend on them */
5207                                 /* running with a specific order... */
5208                                 if (! vtable->initialized)
5209                                         return FALSE;
5210                                 mono_runtime_class_init (vtable);
5211                         }
5212                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
5213                         if (!method->klass->runtime_info)
5214                                 /* No vtable created yet */
5215                                 return FALSE;
5216                         vtable = mono_class_vtable (cfg->domain, method->klass);
5217                         if (!vtable)
5218                                 return FALSE;
5219                         if (!vtable->initialized)
5220                                 return FALSE;
5221                 }
5222         } else {
5223                 /* 
5224                  * If we're compiling for shared code
5225                  * the cctor will need to be run at aot method load time, for example,
5226                  * or at the end of the compilation of the inlining method.
5227                  */
5228                 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
5229                         return FALSE;
5230         }
5231
5232 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5233         if (mono_arch_is_soft_float ()) {
5234                 /* FIXME: */
5235                 if (sig->ret && sig->ret->type == MONO_TYPE_R4)
5236                         return FALSE;
5237                 for (i = 0; i < sig->param_count; ++i)
5238                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4)
5239                                 return FALSE;
5240         }
5241 #endif
5242
5243         if (g_list_find (cfg->dont_inline, method))
5244                 return FALSE;
5245
5246         return TRUE;
5247 }
5248
5249 static gboolean
5250 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoClass *klass, MonoVTable *vtable)
5251 {
5252         if (!cfg->compile_aot) {
5253                 g_assert (vtable);
5254                 if (vtable->initialized)
5255                         return FALSE;
5256         }
5257
5258         if (klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5259                 if (cfg->method == method)
5260                         return FALSE;
5261         }
5262
5263         if (!mono_class_needs_cctor_run (klass, method))
5264                 return FALSE;
5265
5266         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (klass == method->klass))
5267                 /* The initialization is already done before the method is called */
5268                 return FALSE;
5269
5270         return TRUE;
5271 }
5272
5273 static MonoInst*
5274 mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck)
5275 {
5276         MonoInst *ins;
5277         guint32 size;
5278         int mult_reg, add_reg, array_reg, index_reg, index2_reg;
5279         int context_used;
5280
5281         if (mini_is_gsharedvt_variable_klass (klass)) {
5282                 size = -1;
5283         } else {
5284                 mono_class_init (klass);
5285                 size = mono_class_array_element_size (klass);
5286         }
5287
5288         mult_reg = alloc_preg (cfg);
5289         array_reg = arr->dreg;
5290         index_reg = index->dreg;
5291
5292 #if SIZEOF_REGISTER == 8
5293         /* The array reg is 64 bits but the index reg is only 32 */
5294         if (COMPILE_LLVM (cfg)) {
5295                 /* Not needed */
5296                 index2_reg = index_reg;
5297         } else {
5298                 index2_reg = alloc_preg (cfg);
5299                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
5300         }
5301 #else
5302         if (index->type == STACK_I8) {
5303                 index2_reg = alloc_preg (cfg);
5304                 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I4, index2_reg, index_reg);
5305         } else {
5306                 index2_reg = index_reg;
5307         }
5308 #endif
5309
5310         if (bcheck)
5311                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
5312
5313 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5314         if (size == 1 || size == 2 || size == 4 || size == 8) {
5315                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
5316
5317                 EMIT_NEW_X86_LEA (cfg, ins, array_reg, index2_reg, fast_log2 [size], MONO_STRUCT_OFFSET (MonoArray, vector));
5318                 ins->klass = mono_class_get_element_class (klass);
5319                 ins->type = STACK_MP;
5320
5321                 return ins;
5322         }
5323 #endif          
5324
5325         add_reg = alloc_ireg_mp (cfg);
5326
5327         if (size == -1) {
5328                 MonoInst *rgctx_ins;
5329
5330                 /* gsharedvt */
5331                 g_assert (cfg->gshared);
5332                 context_used = mini_class_check_context_used (cfg, klass);
5333                 g_assert (context_used);
5334                 rgctx_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE);
5335                 MONO_EMIT_NEW_BIALU (cfg, OP_IMUL, mult_reg, index2_reg, rgctx_ins->dreg);
5336         } else {
5337                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
5338         }
5339         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg);
5340         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5341         ins->klass = mono_class_get_element_class (klass);
5342         ins->type = STACK_MP;
5343         MONO_ADD_INS (cfg->cbb, ins);
5344
5345         return ins;
5346 }
5347
5348 #ifndef MONO_ARCH_EMULATE_MUL_DIV
5349 static MonoInst*
5350 mini_emit_ldelema_2_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index_ins1, MonoInst *index_ins2)
5351 {
5352         int bounds_reg = alloc_preg (cfg);
5353         int add_reg = alloc_ireg_mp (cfg);
5354         int mult_reg = alloc_preg (cfg);
5355         int mult2_reg = alloc_preg (cfg);
5356         int low1_reg = alloc_preg (cfg);
5357         int low2_reg = alloc_preg (cfg);
5358         int high1_reg = alloc_preg (cfg);
5359         int high2_reg = alloc_preg (cfg);
5360         int realidx1_reg = alloc_preg (cfg);
5361         int realidx2_reg = alloc_preg (cfg);
5362         int sum_reg = alloc_preg (cfg);
5363         int index1, index2, tmpreg;
5364         MonoInst *ins;
5365         guint32 size;
5366
5367         mono_class_init (klass);
5368         size = mono_class_array_element_size (klass);
5369
5370         index1 = index_ins1->dreg;
5371         index2 = index_ins2->dreg;
5372
5373 #if SIZEOF_REGISTER == 8
5374         /* The array reg is 64 bits but the index reg is only 32 */
5375         if (COMPILE_LLVM (cfg)) {
5376                 /* Not needed */
5377         } else {
5378                 tmpreg = alloc_preg (cfg);
5379                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index1);
5380                 index1 = tmpreg;
5381                 tmpreg = alloc_preg (cfg);
5382                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index2);
5383                 index2 = tmpreg;
5384         }
5385 #else
5386         // FIXME: Do we need to do something here for i8 indexes, like in ldelema_1_ins ?
5387         tmpreg = -1;
5388 #endif
5389
5390         /* range checking */
5391         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, 
5392                                        arr->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5393
5394         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low1_reg, 
5395                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5396         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx1_reg, index1, low1_reg);
5397         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high1_reg, 
5398                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5399         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high1_reg, realidx1_reg);
5400         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5401
5402         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low2_reg, 
5403                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5404         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx2_reg, index2, low2_reg);
5405         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high2_reg, 
5406                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5407         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high2_reg, realidx2_reg);
5408         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5409
5410         MONO_EMIT_NEW_BIALU (cfg, OP_PMUL, mult_reg, high2_reg, realidx1_reg);
5411         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, mult_reg, realidx2_reg);
5412         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PMUL_IMM, mult2_reg, sum_reg, size);
5413         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult2_reg, arr->dreg);
5414         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5415
5416         ins->type = STACK_MP;
5417         ins->klass = klass;
5418         MONO_ADD_INS (cfg->cbb, ins);
5419
5420         return ins;
5421 }
5422 #endif
5423
5424 static MonoInst*
5425 mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
5426 {
5427         int rank;
5428         MonoInst *addr;
5429         MonoMethod *addr_method;
5430         int element_size;
5431         MonoClass *eclass = cmethod->klass->element_class;
5432
5433         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
5434
5435         if (rank == 1)
5436                 return mini_emit_ldelema_1_ins (cfg, eclass, sp [0], sp [1], TRUE);
5437
5438 #ifndef MONO_ARCH_EMULATE_MUL_DIV
5439         /* emit_ldelema_2 depends on OP_LMUL */
5440         if (rank == 2 && (cfg->opt & MONO_OPT_INTRINS) && !mini_is_gsharedvt_variable_klass (eclass)) {
5441                 return mini_emit_ldelema_2_ins (cfg, eclass, sp [0], sp [1], sp [2]);
5442         }
5443 #endif
5444
5445         if (mini_is_gsharedvt_variable_klass (eclass))
5446                 element_size = 0;
5447         else
5448                 element_size = mono_class_array_element_size (eclass);
5449         addr_method = mono_marshal_get_array_address (rank, element_size);
5450         addr = mono_emit_method_call (cfg, addr_method, sp, NULL);
5451
5452         return addr;
5453 }
5454
5455 static MonoBreakPolicy
5456 always_insert_breakpoint (MonoMethod *method)
5457 {
5458         return MONO_BREAK_POLICY_ALWAYS;
5459 }
5460
5461 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
5462
5463 /**
5464  * mono_set_break_policy:
5465  * policy_callback: the new callback function
5466  *
5467  * Allow embedders to decide wherther to actually obey breakpoint instructions
5468  * (both break IL instructions and Debugger.Break () method calls), for example
5469  * to not allow an app to be aborted by a perfectly valid IL opcode when executing
5470  * untrusted or semi-trusted code.
5471  *
5472  * @policy_callback will be called every time a break point instruction needs to
5473  * be inserted with the method argument being the method that calls Debugger.Break()
5474  * or has the IL break instruction. The callback should return #MONO_BREAK_POLICY_NEVER
5475  * if it wants the breakpoint to not be effective in the given method.
5476  * #MONO_BREAK_POLICY_ALWAYS is the default.
5477  */
5478 void
5479 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
5480 {
5481         if (policy_callback)
5482                 break_policy_func = policy_callback;
5483         else
5484                 break_policy_func = always_insert_breakpoint;
5485 }
5486
5487 static gboolean
5488 should_insert_brekpoint (MonoMethod *method) {
5489         switch (break_policy_func (method)) {
5490         case MONO_BREAK_POLICY_ALWAYS:
5491                 return TRUE;
5492         case MONO_BREAK_POLICY_NEVER:
5493                 return FALSE;
5494         case MONO_BREAK_POLICY_ON_DBG:
5495                 g_warning ("mdb no longer supported");
5496                 return FALSE;
5497         default:
5498                 g_warning ("Incorrect value returned from break policy callback");
5499                 return FALSE;
5500         }
5501 }
5502
5503 /* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */
5504 static MonoInst*
5505 emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5506 {
5507         MonoInst *addr, *store, *load;
5508         MonoClass *eklass = mono_class_from_mono_type (fsig->params [2]);
5509
5510         /* the bounds check is already done by the callers */
5511         addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5512         if (is_set) {
5513                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
5514                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
5515                 if (mini_type_is_reference (fsig->params [2]))
5516                         emit_write_barrier (cfg, addr, load);
5517         } else {
5518                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
5519                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
5520         }
5521         return store;
5522 }
5523
5524
5525 static gboolean
5526 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
5527 {
5528         return mini_type_is_reference (&klass->byval_arg);
5529 }
5530
5531 static MonoInst*
5532 emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboolean safety_checks)
5533 {
5534         if (safety_checks && generic_class_is_reference_type (cfg, klass) &&
5535                 !(sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL)) {
5536                 MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
5537                 MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
5538                 MonoInst *iargs [3];
5539
5540                 if (!helper->slot)
5541                         mono_class_setup_vtable (obj_array);
5542                 g_assert (helper->slot);
5543
5544                 if (sp [0]->type != STACK_OBJ)
5545                         return NULL;
5546                 if (sp [2]->type != STACK_OBJ)
5547                         return NULL;
5548
5549                 iargs [2] = sp [2];
5550                 iargs [1] = sp [1];
5551                 iargs [0] = sp [0];
5552
5553                 return mono_emit_method_call (cfg, helper, iargs, sp [0]);
5554         } else {
5555                 MonoInst *ins;
5556
5557                 if (mini_is_gsharedvt_variable_klass (klass)) {
5558                         MonoInst *addr;
5559
5560                         // FIXME-VT: OP_ICONST optimization
5561                         addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
5562                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5563                         ins->opcode = OP_STOREV_MEMBASE;
5564                 } else if (sp [1]->opcode == OP_ICONST) {
5565                         int array_reg = sp [0]->dreg;
5566                         int index_reg = sp [1]->dreg;
5567                         int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
5568
5569                         if (safety_checks)
5570                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
5571                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
5572                 } else {
5573                         MonoInst *addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], safety_checks);
5574                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5575                         if (generic_class_is_reference_type (cfg, klass))
5576                                 emit_write_barrier (cfg, addr, sp [2]);
5577                 }
5578                 return ins;
5579         }
5580 }
5581
5582 static MonoInst*
5583 emit_array_unsafe_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5584 {
5585         MonoClass *eklass;
5586         
5587         if (is_set)
5588                 eklass = mono_class_from_mono_type (fsig->params [2]);
5589         else
5590                 eklass = mono_class_from_mono_type (fsig->ret);
5591
5592         if (is_set) {
5593                 return emit_array_store (cfg, eklass, args, FALSE);
5594         } else {
5595                 MonoInst *ins, *addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5596                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &eklass->byval_arg, addr->dreg, 0);
5597                 return ins;
5598         }
5599 }
5600
5601 static gboolean
5602 is_unsafe_mov_compatible (MonoCompile *cfg, MonoClass *param_klass, MonoClass *return_klass)
5603 {
5604         uint32_t align;
5605
5606         param_klass = mono_class_from_mono_type (mini_get_underlying_type (&param_klass->byval_arg));
5607
5608         //Only allow for valuetypes
5609         if (!param_klass->valuetype || !return_klass->valuetype)
5610                 return FALSE;
5611
5612         //That are blitable
5613         if (param_klass->has_references || return_klass->has_references)
5614                 return FALSE;
5615
5616         /* Avoid mixing structs and primitive types/enums, they need to be handled differently in the JIT */
5617         if ((MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && !MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)) ||
5618                 (!MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)))
5619                 return FALSE;
5620
5621         if (param_klass->byval_arg.type == MONO_TYPE_R4 || param_klass->byval_arg.type == MONO_TYPE_R8 ||
5622                 return_klass->byval_arg.type == MONO_TYPE_R4 || return_klass->byval_arg.type == MONO_TYPE_R8)
5623                 return FALSE;
5624
5625         //And have the same size
5626         if (mono_class_value_size (param_klass, &align) != mono_class_value_size (return_klass, &align))
5627                 return FALSE;
5628         return TRUE;
5629 }
5630
5631 static MonoInst*
5632 emit_array_unsafe_mov (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args)
5633 {
5634         MonoClass *param_klass = mono_class_from_mono_type (fsig->params [0]);
5635         MonoClass *return_klass = mono_class_from_mono_type (fsig->ret);
5636
5637         //Valuetypes that are semantically equivalent
5638         if (is_unsafe_mov_compatible (cfg, param_klass, return_klass))
5639                 return args [0];
5640
5641         //Arrays of valuetypes that are semantically equivalent
5642         if (param_klass->rank == 1 && return_klass->rank == 1 && is_unsafe_mov_compatible (cfg, param_klass->element_class, return_klass->element_class))
5643                 return args [0];
5644
5645         return NULL;
5646 }
5647
5648 static MonoInst*
5649 mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5650 {
5651 #ifdef MONO_ARCH_SIMD_INTRINSICS
5652         MonoInst *ins = NULL;
5653
5654         if (cfg->opt & MONO_OPT_SIMD) {
5655                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5656                 if (ins)
5657                         return ins;
5658         }
5659 #endif
5660
5661         return mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
5662 }
5663
5664 static MonoInst*
5665 emit_memory_barrier (MonoCompile *cfg, int kind)
5666 {
5667         MonoInst *ins = NULL;
5668         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
5669         MONO_ADD_INS (cfg->cbb, ins);
5670         ins->backend.memory_barrier_kind = kind;
5671
5672         return ins;
5673 }
5674
5675 static MonoInst*
5676 llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5677 {
5678         MonoInst *ins = NULL;
5679         int opcode = 0;
5680
5681         /* The LLVM backend supports these intrinsics */
5682         if (cmethod->klass == mono_defaults.math_class) {
5683                 if (strcmp (cmethod->name, "Sin") == 0) {
5684                         opcode = OP_SIN;
5685                 } else if (strcmp (cmethod->name, "Cos") == 0) {
5686                         opcode = OP_COS;
5687                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
5688                         opcode = OP_SQRT;
5689                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
5690                         opcode = OP_ABS;
5691                 }
5692
5693                 if (opcode && fsig->param_count == 1) {
5694                         MONO_INST_NEW (cfg, ins, opcode);
5695                         ins->type = STACK_R8;
5696                         ins->dreg = mono_alloc_freg (cfg);
5697                         ins->sreg1 = args [0]->dreg;
5698                         MONO_ADD_INS (cfg->cbb, ins);
5699                 }
5700
5701                 opcode = 0;
5702                 if (cfg->opt & MONO_OPT_CMOV) {
5703                         if (strcmp (cmethod->name, "Min") == 0) {
5704                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5705                                         opcode = OP_IMIN;
5706                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5707                                         opcode = OP_IMIN_UN;
5708                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5709                                         opcode = OP_LMIN;
5710                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5711                                         opcode = OP_LMIN_UN;
5712                         } else if (strcmp (cmethod->name, "Max") == 0) {
5713                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5714                                         opcode = OP_IMAX;
5715                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5716                                         opcode = OP_IMAX_UN;
5717                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5718                                         opcode = OP_LMAX;
5719                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5720                                         opcode = OP_LMAX_UN;
5721                         }
5722                 }
5723
5724                 if (opcode && fsig->param_count == 2) {
5725                         MONO_INST_NEW (cfg, ins, opcode);
5726                         ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
5727                         ins->dreg = mono_alloc_ireg (cfg);
5728                         ins->sreg1 = args [0]->dreg;
5729                         ins->sreg2 = args [1]->dreg;
5730                         MONO_ADD_INS (cfg->cbb, ins);
5731                 }
5732         }
5733
5734         return ins;
5735 }
5736
5737 static MonoInst*
5738 mini_emit_inst_for_sharable_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5739 {
5740         if (cmethod->klass == mono_defaults.array_class) {
5741                 if (strcmp (cmethod->name, "UnsafeStore") == 0)
5742                         return emit_array_unsafe_access (cfg, fsig, args, TRUE);
5743                 else if (strcmp (cmethod->name, "UnsafeLoad") == 0)
5744                         return emit_array_unsafe_access (cfg, fsig, args, FALSE);
5745                 else if (strcmp (cmethod->name, "UnsafeMov") == 0)
5746                         return emit_array_unsafe_mov (cfg, fsig, args);
5747         }
5748
5749         return NULL;
5750 }
5751
5752 static MonoInst*
5753 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5754 {
5755         MonoInst *ins = NULL;
5756
5757         static MonoClass *runtime_helpers_class = NULL;
5758         if (! runtime_helpers_class)
5759                 runtime_helpers_class = mono_class_from_name (mono_defaults.corlib,
5760                         "System.Runtime.CompilerServices", "RuntimeHelpers");
5761
5762         if (cmethod->klass == mono_defaults.string_class) {
5763                 if (strcmp (cmethod->name, "get_Chars") == 0 && fsig->param_count + fsig->hasthis == 2) {
5764                         int dreg = alloc_ireg (cfg);
5765                         int index_reg = alloc_preg (cfg);
5766                         int add_reg = alloc_preg (cfg);
5767
5768 #if SIZEOF_REGISTER == 8
5769                         /* The array reg is 64 bits but the index reg is only 32 */
5770                         MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index_reg, args [1]->dreg);
5771 #else
5772                         index_reg = args [1]->dreg;
5773 #endif  
5774                         MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
5775
5776 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5777                         EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, MONO_STRUCT_OFFSET (MonoString, chars));
5778                         add_reg = ins->dreg;
5779                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5780                                                                    add_reg, 0);
5781 #else
5782                         int mult_reg = alloc_preg (cfg);
5783                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1);
5784                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5785                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5786                                                                    add_reg, MONO_STRUCT_OFFSET (MonoString, chars));
5787 #endif
5788                         type_from_op (cfg, ins, NULL, NULL);
5789                         return ins;
5790                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
5791                         int dreg = alloc_ireg (cfg);
5792                         /* Decompose later to allow more optimizations */
5793                         EMIT_NEW_UNALU (cfg, ins, OP_STRLEN, dreg, args [0]->dreg);
5794                         ins->type = STACK_I4;
5795                         ins->flags |= MONO_INST_FAULT;
5796                         cfg->cbb->has_array_access = TRUE;
5797                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
5798
5799                         return ins;
5800                 } else 
5801                         return NULL;
5802         } else if (cmethod->klass == mono_defaults.object_class) {
5803
5804                 if (strcmp (cmethod->name, "GetType") == 0 && fsig->param_count + fsig->hasthis == 1) {
5805                         int dreg = alloc_ireg_ref (cfg);
5806                         int vt_reg = alloc_preg (cfg);
5807                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
5808                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, MONO_STRUCT_OFFSET (MonoVTable, type));
5809                         type_from_op (cfg, ins, NULL, NULL);
5810
5811                         return ins;
5812 #if !defined(MONO_ARCH_EMULATE_MUL_DIV)
5813                 } else if (strcmp (cmethod->name, "InternalGetHashCode") == 0 && fsig->param_count == 1 && !mono_gc_is_moving ()) {
5814                         int dreg = alloc_ireg (cfg);
5815                         int t1 = alloc_ireg (cfg);
5816         
5817                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, t1, args [0]->dreg, 3);
5818                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_MUL_IMM, dreg, t1, 2654435761u);
5819                         ins->type = STACK_I4;
5820
5821                         return ins;
5822 #endif
5823                 } else if (strcmp (cmethod->name, ".ctor") == 0 && fsig->param_count == 0) {
5824                         MONO_INST_NEW (cfg, ins, OP_NOP);
5825                         MONO_ADD_INS (cfg->cbb, ins);
5826                         return ins;
5827                 } else
5828                         return NULL;
5829         } else if (cmethod->klass == mono_defaults.array_class) {
5830                 if (strcmp (cmethod->name, "GetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
5831                         return emit_array_generic_access (cfg, fsig, args, FALSE);
5832                 else if (strcmp (cmethod->name, "SetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
5833                         return emit_array_generic_access (cfg, fsig, args, TRUE);
5834
5835 #ifndef MONO_BIG_ARRAYS
5836                 /*
5837                  * This is an inline version of GetLength/GetLowerBound(0) used frequently in
5838                  * Array methods.
5839                  */
5840                 else if (((strcmp (cmethod->name, "GetLength") == 0 && fsig->param_count + fsig->hasthis == 2) ||
5841                          (strcmp (cmethod->name, "GetLowerBound") == 0 && fsig->param_count + fsig->hasthis == 2)) &&
5842                          args [1]->opcode == OP_ICONST && args [1]->inst_c0 == 0) {
5843                         int dreg = alloc_ireg (cfg);
5844                         int bounds_reg = alloc_ireg_mp (cfg);
5845                         MonoBasicBlock *end_bb, *szarray_bb;
5846                         gboolean get_length = strcmp (cmethod->name, "GetLength") == 0;
5847
5848                         NEW_BBLOCK (cfg, end_bb);
5849                         NEW_BBLOCK (cfg, szarray_bb);
5850
5851                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOAD_MEMBASE, bounds_reg,
5852                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5853                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
5854                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, szarray_bb);
5855                         /* Non-szarray case */
5856                         if (get_length)
5857                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5858                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5859                         else
5860                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5861                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5862                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
5863                         MONO_START_BB (cfg, szarray_bb);
5864                         /* Szarray case */
5865                         if (get_length)
5866                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5867                                                                            args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
5868                         else
5869                                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
5870                         MONO_START_BB (cfg, end_bb);
5871
5872                         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, dreg, dreg);
5873                         ins->type = STACK_I4;
5874                         
5875                         return ins;
5876                 }
5877 #endif
5878
5879                 if (cmethod->name [0] != 'g')
5880                         return NULL;
5881
5882                 if (strcmp (cmethod->name, "get_Rank") == 0 && fsig->param_count + fsig->hasthis == 1) {
5883                         int dreg = alloc_ireg (cfg);
5884                         int vtable_reg = alloc_preg (cfg);
5885                         MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, 
5886                                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
5887                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
5888                                                                    vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
5889                         type_from_op (cfg, ins, NULL, NULL);
5890
5891                         return ins;
5892                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
5893                         int dreg = alloc_ireg (cfg);
5894
5895                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
5896                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
5897                         type_from_op (cfg, ins, NULL, NULL);
5898
5899                         return ins;
5900                 } else
5901                         return NULL;
5902         } else if (cmethod->klass == runtime_helpers_class) {
5903
5904                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0 && fsig->param_count == 0) {
5905                         EMIT_NEW_ICONST (cfg, ins, MONO_STRUCT_OFFSET (MonoString, chars));
5906                         return ins;
5907                 } else
5908                         return NULL;
5909         } else if (cmethod->klass == mono_defaults.thread_class) {
5910                 if (strcmp (cmethod->name, "SpinWait_nop") == 0 && fsig->param_count == 0) {
5911                         MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
5912                         MONO_ADD_INS (cfg->cbb, ins);
5913                         return ins;
5914                 } else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0) {
5915                         return emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5916                 } else if (!strcmp (cmethod->name, "VolatileRead") && fsig->param_count == 1) {
5917                         guint32 opcode = 0;
5918                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
5919
5920                         if (fsig->params [0]->type == MONO_TYPE_I1)
5921                                 opcode = OP_LOADI1_MEMBASE;
5922                         else if (fsig->params [0]->type == MONO_TYPE_U1)
5923                                 opcode = OP_LOADU1_MEMBASE;
5924                         else if (fsig->params [0]->type == MONO_TYPE_I2)
5925                                 opcode = OP_LOADI2_MEMBASE;
5926                         else if (fsig->params [0]->type == MONO_TYPE_U2)
5927                                 opcode = OP_LOADU2_MEMBASE;
5928                         else if (fsig->params [0]->type == MONO_TYPE_I4)
5929                                 opcode = OP_LOADI4_MEMBASE;
5930                         else if (fsig->params [0]->type == MONO_TYPE_U4)
5931                                 opcode = OP_LOADU4_MEMBASE;
5932                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
5933                                 opcode = OP_LOADI8_MEMBASE;
5934                         else if (fsig->params [0]->type == MONO_TYPE_R4)
5935                                 opcode = OP_LOADR4_MEMBASE;
5936                         else if (fsig->params [0]->type == MONO_TYPE_R8)
5937                                 opcode = OP_LOADR8_MEMBASE;
5938                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
5939                                 opcode = OP_LOAD_MEMBASE;
5940
5941                         if (opcode) {
5942                                 MONO_INST_NEW (cfg, ins, opcode);
5943                                 ins->inst_basereg = args [0]->dreg;
5944                                 ins->inst_offset = 0;
5945                                 MONO_ADD_INS (cfg->cbb, ins);
5946
5947                                 switch (fsig->params [0]->type) {
5948                                 case MONO_TYPE_I1:
5949                                 case MONO_TYPE_U1:
5950                                 case MONO_TYPE_I2:
5951                                 case MONO_TYPE_U2:
5952                                 case MONO_TYPE_I4:
5953                                 case MONO_TYPE_U4:
5954                                         ins->dreg = mono_alloc_ireg (cfg);
5955                                         ins->type = STACK_I4;
5956                                         break;
5957                                 case MONO_TYPE_I8:
5958                                 case MONO_TYPE_U8:
5959                                         ins->dreg = mono_alloc_lreg (cfg);
5960                                         ins->type = STACK_I8;
5961                                         break;
5962                                 case MONO_TYPE_I:
5963                                 case MONO_TYPE_U:
5964                                         ins->dreg = mono_alloc_ireg (cfg);
5965 #if SIZEOF_REGISTER == 8
5966                                         ins->type = STACK_I8;
5967 #else
5968                                         ins->type = STACK_I4;
5969 #endif
5970                                         break;
5971                                 case MONO_TYPE_R4:
5972                                 case MONO_TYPE_R8:
5973                                         ins->dreg = mono_alloc_freg (cfg);
5974                                         ins->type = STACK_R8;
5975                                         break;
5976                                 default:
5977                                         g_assert (mini_type_is_reference (fsig->params [0]));
5978                                         ins->dreg = mono_alloc_ireg_ref (cfg);
5979                                         ins->type = STACK_OBJ;
5980                                         break;
5981                                 }
5982
5983                                 if (opcode == OP_LOADI8_MEMBASE)
5984                                         ins = mono_decompose_opcode (cfg, ins);
5985
5986                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
5987
5988                                 return ins;
5989                         }
5990                 } else if (!strcmp (cmethod->name, "VolatileWrite") && fsig->param_count == 2) {
5991                         guint32 opcode = 0;
5992                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
5993
5994                         if (fsig->params [0]->type == MONO_TYPE_I1 || fsig->params [0]->type == MONO_TYPE_U1)
5995                                 opcode = OP_STOREI1_MEMBASE_REG;
5996                         else if (fsig->params [0]->type == MONO_TYPE_I2 || fsig->params [0]->type == MONO_TYPE_U2)
5997                                 opcode = OP_STOREI2_MEMBASE_REG;
5998                         else if (fsig->params [0]->type == MONO_TYPE_I4 || fsig->params [0]->type == MONO_TYPE_U4)
5999                                 opcode = OP_STOREI4_MEMBASE_REG;
6000                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
6001                                 opcode = OP_STOREI8_MEMBASE_REG;
6002                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6003                                 opcode = OP_STORER4_MEMBASE_REG;
6004                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6005                                 opcode = OP_STORER8_MEMBASE_REG;
6006                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
6007                                 opcode = OP_STORE_MEMBASE_REG;
6008
6009                         if (opcode) {
6010                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
6011
6012                                 MONO_INST_NEW (cfg, ins, opcode);
6013                                 ins->sreg1 = args [1]->dreg;
6014                                 ins->inst_destbasereg = args [0]->dreg;
6015                                 ins->inst_offset = 0;
6016                                 MONO_ADD_INS (cfg->cbb, ins);
6017
6018                                 if (opcode == OP_STOREI8_MEMBASE_REG)
6019                                         ins = mono_decompose_opcode (cfg, ins);
6020
6021                                 return ins;
6022                         }
6023                 }
6024         } else if (cmethod->klass == mono_defaults.monitor_class) {
6025 #if defined(MONO_ARCH_MONITOR_OBJECT_REG)
6026                 if (strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 1) {
6027                         MonoCallInst *call;
6028
6029                         if (COMPILE_LLVM (cfg)) {
6030                                 /* 
6031                                  * Pass the argument normally, the LLVM backend will handle the
6032                                  * calling convention problems.
6033                                  */
6034                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER, NULL, helper_sig_monitor_enter_exit_trampoline_llvm, args);
6035                         } else {
6036                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER,
6037                                             NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
6038                                 mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg,
6039                                                                                            MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
6040                         }
6041
6042                         return (MonoInst*)call;
6043 #if defined(MONO_ARCH_MONITOR_LOCK_TAKEN_REG)
6044                 } else if (strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 2) {
6045                         MonoCallInst *call;
6046
6047                         if (COMPILE_LLVM (cfg)) {
6048                                 /*
6049                                  * Pass the argument normally, the LLVM backend will handle the
6050                                  * calling convention problems.
6051                                  */
6052                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER_V4, NULL, helper_sig_monitor_enter_v4_trampoline_llvm, args);
6053                         } else {
6054                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER_V4,
6055                                             NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
6056                                 mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg, MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
6057                                 mono_call_inst_add_outarg_reg (cfg, call, args [1]->dreg, MONO_ARCH_MONITOR_LOCK_TAKEN_REG, FALSE);
6058                         }
6059
6060                         return (MonoInst*)call;
6061 #endif
6062                 } else if (strcmp (cmethod->name, "Exit") == 0 && fsig->param_count == 1) {
6063                         MonoCallInst *call;
6064
6065                         if (COMPILE_LLVM (cfg)) {
6066                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_EXIT, NULL, helper_sig_monitor_enter_exit_trampoline_llvm, args);
6067                         } else {
6068                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_EXIT,
6069                                             NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
6070                                 mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg,
6071                                                                                            MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
6072                         }
6073
6074                         return (MonoInst*)call;
6075                 }
6076 #endif
6077         } else if (cmethod->klass->image == mono_defaults.corlib &&
6078                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6079                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
6080                 ins = NULL;
6081
6082 #if SIZEOF_REGISTER == 8
6083                 if (strcmp (cmethod->name, "Read") == 0 && fsig->param_count == 1 && (fsig->params [0]->type == MONO_TYPE_I8)) {
6084                         if (mono_arch_opcode_supported (OP_ATOMIC_LOAD_I8)) {
6085                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_LOAD_I8);
6086                                 ins->dreg = mono_alloc_preg (cfg);
6087                                 ins->sreg1 = args [0]->dreg;
6088                                 ins->type = STACK_I8;
6089                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_SEQ;
6090                                 MONO_ADD_INS (cfg->cbb, ins);
6091                         } else {
6092                                 MonoInst *load_ins;
6093
6094                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6095
6096                                 /* 64 bit reads are already atomic */
6097                                 MONO_INST_NEW (cfg, load_ins, OP_LOADI8_MEMBASE);
6098                                 load_ins->dreg = mono_alloc_preg (cfg);
6099                                 load_ins->inst_basereg = args [0]->dreg;
6100                                 load_ins->inst_offset = 0;
6101                                 load_ins->type = STACK_I8;
6102                                 MONO_ADD_INS (cfg->cbb, load_ins);
6103
6104                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6105
6106                                 ins = load_ins;
6107                         }
6108                 }
6109 #endif
6110
6111                 if (strcmp (cmethod->name, "Increment") == 0 && fsig->param_count == 1) {
6112                         MonoInst *ins_iconst;
6113                         guint32 opcode = 0;
6114
6115                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6116                                 opcode = OP_ATOMIC_ADD_I4;
6117                                 cfg->has_atomic_add_i4 = TRUE;
6118                         }
6119 #if SIZEOF_REGISTER == 8
6120                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6121                                 opcode = OP_ATOMIC_ADD_I8;
6122 #endif
6123                         if (opcode) {
6124                                 if (!mono_arch_opcode_supported (opcode))
6125                                         return NULL;
6126                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6127                                 ins_iconst->inst_c0 = 1;
6128                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6129                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6130
6131                                 MONO_INST_NEW (cfg, ins, opcode);
6132                                 ins->dreg = mono_alloc_ireg (cfg);
6133                                 ins->inst_basereg = args [0]->dreg;
6134                                 ins->inst_offset = 0;
6135                                 ins->sreg2 = ins_iconst->dreg;
6136                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6137                                 MONO_ADD_INS (cfg->cbb, ins);
6138                         }
6139                 } else if (strcmp (cmethod->name, "Decrement") == 0 && fsig->param_count == 1) {
6140                         MonoInst *ins_iconst;
6141                         guint32 opcode = 0;
6142
6143                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6144                                 opcode = OP_ATOMIC_ADD_I4;
6145                                 cfg->has_atomic_add_i4 = TRUE;
6146                         }
6147 #if SIZEOF_REGISTER == 8
6148                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6149                                 opcode = OP_ATOMIC_ADD_I8;
6150 #endif
6151                         if (opcode) {
6152                                 if (!mono_arch_opcode_supported (opcode))
6153                                         return NULL;
6154                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6155                                 ins_iconst->inst_c0 = -1;
6156                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6157                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6158
6159                                 MONO_INST_NEW (cfg, ins, opcode);
6160                                 ins->dreg = mono_alloc_ireg (cfg);
6161                                 ins->inst_basereg = args [0]->dreg;
6162                                 ins->inst_offset = 0;
6163                                 ins->sreg2 = ins_iconst->dreg;
6164                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6165                                 MONO_ADD_INS (cfg->cbb, ins);
6166                         }
6167                 } else if (strcmp (cmethod->name, "Add") == 0 && fsig->param_count == 2) {
6168                         guint32 opcode = 0;
6169
6170                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6171                                 opcode = OP_ATOMIC_ADD_I4;
6172                                 cfg->has_atomic_add_i4 = TRUE;
6173                         }
6174 #if SIZEOF_REGISTER == 8
6175                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6176                                 opcode = OP_ATOMIC_ADD_I8;
6177 #endif
6178                         if (opcode) {
6179                                 if (!mono_arch_opcode_supported (opcode))
6180                                         return NULL;
6181                                 MONO_INST_NEW (cfg, ins, opcode);
6182                                 ins->dreg = mono_alloc_ireg (cfg);
6183                                 ins->inst_basereg = args [0]->dreg;
6184                                 ins->inst_offset = 0;
6185                                 ins->sreg2 = args [1]->dreg;
6186                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6187                                 MONO_ADD_INS (cfg->cbb, ins);
6188                         }
6189                 }
6190                 else if (strcmp (cmethod->name, "Exchange") == 0 && fsig->param_count == 2) {
6191                         MonoInst *f2i = NULL, *i2f;
6192                         guint32 opcode, f2i_opcode, i2f_opcode;
6193                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6194                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
6195
6196                         if (fsig->params [0]->type == MONO_TYPE_I4 ||
6197                             fsig->params [0]->type == MONO_TYPE_R4) {
6198                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6199                                 f2i_opcode = OP_MOVE_F_TO_I4;
6200                                 i2f_opcode = OP_MOVE_I4_TO_F;
6201                                 cfg->has_atomic_exchange_i4 = TRUE;
6202                         }
6203 #if SIZEOF_REGISTER == 8
6204                         else if (is_ref ||
6205                                  fsig->params [0]->type == MONO_TYPE_I8 ||
6206                                  fsig->params [0]->type == MONO_TYPE_R8 ||
6207                                  fsig->params [0]->type == MONO_TYPE_I) {
6208                                 opcode = OP_ATOMIC_EXCHANGE_I8;
6209                                 f2i_opcode = OP_MOVE_F_TO_I8;
6210                                 i2f_opcode = OP_MOVE_I8_TO_F;
6211                         }
6212 #else
6213                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I) {
6214                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6215                                 cfg->has_atomic_exchange_i4 = TRUE;
6216                         }
6217 #endif
6218                         else
6219                                 return NULL;
6220
6221                         if (!mono_arch_opcode_supported (opcode))
6222                                 return NULL;
6223
6224                         if (is_float) {
6225                                 /* TODO: Decompose these opcodes instead of bailing here. */
6226                                 if (COMPILE_SOFT_FLOAT (cfg))
6227                                         return NULL;
6228
6229                                 MONO_INST_NEW (cfg, f2i, f2i_opcode);
6230                                 f2i->dreg = mono_alloc_ireg (cfg);
6231                                 f2i->sreg1 = args [1]->dreg;
6232                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6233                                         f2i->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6234                                 MONO_ADD_INS (cfg->cbb, f2i);
6235                         }
6236
6237                         MONO_INST_NEW (cfg, ins, opcode);
6238                         ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : mono_alloc_ireg (cfg);
6239                         ins->inst_basereg = args [0]->dreg;
6240                         ins->inst_offset = 0;
6241                         ins->sreg2 = is_float ? f2i->dreg : args [1]->dreg;
6242                         MONO_ADD_INS (cfg->cbb, ins);
6243
6244                         switch (fsig->params [0]->type) {
6245                         case MONO_TYPE_I4:
6246                                 ins->type = STACK_I4;
6247                                 break;
6248                         case MONO_TYPE_I8:
6249                                 ins->type = STACK_I8;
6250                                 break;
6251                         case MONO_TYPE_I:
6252 #if SIZEOF_REGISTER == 8
6253                                 ins->type = STACK_I8;
6254 #else
6255                                 ins->type = STACK_I4;
6256 #endif
6257                                 break;
6258                         case MONO_TYPE_R4:
6259                         case MONO_TYPE_R8:
6260                                 ins->type = STACK_R8;
6261                                 break;
6262                         default:
6263                                 g_assert (mini_type_is_reference (fsig->params [0]));
6264                                 ins->type = STACK_OBJ;
6265                                 break;
6266                         }
6267
6268                         if (is_float) {
6269                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6270                                 i2f->dreg = mono_alloc_freg (cfg);
6271                                 i2f->sreg1 = ins->dreg;
6272                                 i2f->type = STACK_R8;
6273                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6274                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6275                                 MONO_ADD_INS (cfg->cbb, i2f);
6276
6277                                 ins = i2f;
6278                         }
6279
6280                         if (cfg->gen_write_barriers && is_ref)
6281                                 emit_write_barrier (cfg, args [0], args [1]);
6282                 }
6283                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 3) {
6284                         MonoInst *f2i_new = NULL, *f2i_cmp = NULL, *i2f;
6285                         guint32 opcode, f2i_opcode, i2f_opcode;
6286                         gboolean is_ref = mini_type_is_reference (fsig->params [1]);
6287                         gboolean is_float = fsig->params [1]->type == MONO_TYPE_R4 || fsig->params [1]->type == MONO_TYPE_R8;
6288
6289                         if (fsig->params [1]->type == MONO_TYPE_I4 ||
6290                             fsig->params [1]->type == MONO_TYPE_R4) {
6291                                 opcode = OP_ATOMIC_CAS_I4;
6292                                 f2i_opcode = OP_MOVE_F_TO_I4;
6293                                 i2f_opcode = OP_MOVE_I4_TO_F;
6294                                 cfg->has_atomic_cas_i4 = TRUE;
6295                         }
6296 #if SIZEOF_REGISTER == 8
6297                         else if (is_ref ||
6298                                  fsig->params [1]->type == MONO_TYPE_I8 ||
6299                                  fsig->params [1]->type == MONO_TYPE_R8 ||
6300                                  fsig->params [1]->type == MONO_TYPE_I) {
6301                                 opcode = OP_ATOMIC_CAS_I8;
6302                                 f2i_opcode = OP_MOVE_F_TO_I8;
6303                                 i2f_opcode = OP_MOVE_I8_TO_F;
6304                         }
6305 #else
6306                         else if (is_ref || fsig->params [1]->type == MONO_TYPE_I) {
6307                                 opcode = OP_ATOMIC_CAS_I4;
6308                                 cfg->has_atomic_cas_i4 = TRUE;
6309                         }
6310 #endif
6311                         else
6312                                 return NULL;
6313
6314                         if (!mono_arch_opcode_supported (opcode))
6315                                 return NULL;
6316
6317                         if (is_float) {
6318                                 /* TODO: Decompose these opcodes instead of bailing here. */
6319                                 if (COMPILE_SOFT_FLOAT (cfg))
6320                                         return NULL;
6321
6322                                 MONO_INST_NEW (cfg, f2i_new, f2i_opcode);
6323                                 f2i_new->dreg = mono_alloc_ireg (cfg);
6324                                 f2i_new->sreg1 = args [1]->dreg;
6325                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6326                                         f2i_new->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6327                                 MONO_ADD_INS (cfg->cbb, f2i_new);
6328
6329                                 MONO_INST_NEW (cfg, f2i_cmp, f2i_opcode);
6330                                 f2i_cmp->dreg = mono_alloc_ireg (cfg);
6331                                 f2i_cmp->sreg1 = args [2]->dreg;
6332                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6333                                         f2i_cmp->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6334                                 MONO_ADD_INS (cfg->cbb, f2i_cmp);
6335                         }
6336
6337                         MONO_INST_NEW (cfg, ins, opcode);
6338                         ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
6339                         ins->sreg1 = args [0]->dreg;
6340                         ins->sreg2 = is_float ? f2i_new->dreg : args [1]->dreg;
6341                         ins->sreg3 = is_float ? f2i_cmp->dreg : args [2]->dreg;
6342                         MONO_ADD_INS (cfg->cbb, ins);
6343
6344                         switch (fsig->params [1]->type) {
6345                         case MONO_TYPE_I4:
6346                                 ins->type = STACK_I4;
6347                                 break;
6348                         case MONO_TYPE_I8:
6349                                 ins->type = STACK_I8;
6350                                 break;
6351                         case MONO_TYPE_I:
6352 #if SIZEOF_REGISTER == 8
6353                                 ins->type = STACK_I8;
6354 #else
6355                                 ins->type = STACK_I4;
6356 #endif
6357                                 break;
6358                         case MONO_TYPE_R4:
6359                                 ins->type = cfg->r4_stack_type;
6360                                 break;
6361                         case MONO_TYPE_R8:
6362                                 ins->type = STACK_R8;
6363                                 break;
6364                         default:
6365                                 g_assert (mini_type_is_reference (fsig->params [1]));
6366                                 ins->type = STACK_OBJ;
6367                                 break;
6368                         }
6369
6370                         if (is_float) {
6371                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6372                                 i2f->dreg = mono_alloc_freg (cfg);
6373                                 i2f->sreg1 = ins->dreg;
6374                                 i2f->type = STACK_R8;
6375                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6376                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6377                                 MONO_ADD_INS (cfg->cbb, i2f);
6378
6379                                 ins = i2f;
6380                         }
6381
6382                         if (cfg->gen_write_barriers && is_ref)
6383                                 emit_write_barrier (cfg, args [0], args [1]);
6384                 }
6385                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 4 &&
6386                          fsig->params [1]->type == MONO_TYPE_I4) {
6387                         MonoInst *cmp, *ceq;
6388
6389                         if (!mono_arch_opcode_supported (OP_ATOMIC_CAS_I4))
6390                                 return NULL;
6391
6392                         /* int32 r = CAS (location, value, comparand); */
6393                         MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
6394                         ins->dreg = alloc_ireg (cfg);
6395                         ins->sreg1 = args [0]->dreg;
6396                         ins->sreg2 = args [1]->dreg;
6397                         ins->sreg3 = args [2]->dreg;
6398                         ins->type = STACK_I4;
6399                         MONO_ADD_INS (cfg->cbb, ins);
6400
6401                         /* bool result = r == comparand; */
6402                         MONO_INST_NEW (cfg, cmp, OP_ICOMPARE);
6403                         cmp->sreg1 = ins->dreg;
6404                         cmp->sreg2 = args [2]->dreg;
6405                         cmp->type = STACK_I4;
6406                         MONO_ADD_INS (cfg->cbb, cmp);
6407
6408                         MONO_INST_NEW (cfg, ceq, OP_ICEQ);
6409                         ceq->dreg = alloc_ireg (cfg);
6410                         ceq->type = STACK_I4;
6411                         MONO_ADD_INS (cfg->cbb, ceq);
6412
6413                         /* *success = result; */
6414                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, args [3]->dreg, 0, ceq->dreg);
6415
6416                         cfg->has_atomic_cas_i4 = TRUE;
6417                 }
6418                 else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0)
6419                         ins = emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6420
6421                 if (ins)
6422                         return ins;
6423         } else if (cmethod->klass->image == mono_defaults.corlib &&
6424                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6425                            (strcmp (cmethod->klass->name, "Volatile") == 0)) {
6426                 ins = NULL;
6427
6428                 if (!strcmp (cmethod->name, "Read") && fsig->param_count == 1) {
6429                         guint32 opcode = 0;
6430                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6431                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
6432
6433                         if (fsig->params [0]->type == MONO_TYPE_I1)
6434                                 opcode = OP_ATOMIC_LOAD_I1;
6435                         else if (fsig->params [0]->type == MONO_TYPE_U1 || fsig->params [0]->type == MONO_TYPE_BOOLEAN)
6436                                 opcode = OP_ATOMIC_LOAD_U1;
6437                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6438                                 opcode = OP_ATOMIC_LOAD_I2;
6439                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6440                                 opcode = OP_ATOMIC_LOAD_U2;
6441                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6442                                 opcode = OP_ATOMIC_LOAD_I4;
6443                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6444                                 opcode = OP_ATOMIC_LOAD_U4;
6445                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6446                                 opcode = OP_ATOMIC_LOAD_R4;
6447                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6448                                 opcode = OP_ATOMIC_LOAD_R8;
6449 #if SIZEOF_REGISTER == 8
6450                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_I)
6451                                 opcode = OP_ATOMIC_LOAD_I8;
6452                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U8 || fsig->params [0]->type == MONO_TYPE_U)
6453                                 opcode = OP_ATOMIC_LOAD_U8;
6454 #else
6455                         else if (fsig->params [0]->type == MONO_TYPE_I)
6456                                 opcode = OP_ATOMIC_LOAD_I4;
6457                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U)
6458                                 opcode = OP_ATOMIC_LOAD_U4;
6459 #endif
6460
6461                         if (opcode) {
6462                                 if (!mono_arch_opcode_supported (opcode))
6463                                         return NULL;
6464
6465                                 MONO_INST_NEW (cfg, ins, opcode);
6466                                 ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : (is_float ? mono_alloc_freg (cfg) : mono_alloc_ireg (cfg));
6467                                 ins->sreg1 = args [0]->dreg;
6468                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_ACQ;
6469                                 MONO_ADD_INS (cfg->cbb, ins);
6470
6471                                 switch (fsig->params [0]->type) {
6472                                 case MONO_TYPE_BOOLEAN:
6473                                 case MONO_TYPE_I1:
6474                                 case MONO_TYPE_U1:
6475                                 case MONO_TYPE_I2:
6476                                 case MONO_TYPE_U2:
6477                                 case MONO_TYPE_I4:
6478                                 case MONO_TYPE_U4:
6479                                         ins->type = STACK_I4;
6480                                         break;
6481                                 case MONO_TYPE_I8:
6482                                 case MONO_TYPE_U8:
6483                                         ins->type = STACK_I8;
6484                                         break;
6485                                 case MONO_TYPE_I:
6486                                 case MONO_TYPE_U:
6487 #if SIZEOF_REGISTER == 8
6488                                         ins->type = STACK_I8;
6489 #else
6490                                         ins->type = STACK_I4;
6491 #endif
6492                                         break;
6493                                 case MONO_TYPE_R4:
6494                                         ins->type = cfg->r4_stack_type;
6495                                         break;
6496                                 case MONO_TYPE_R8:
6497                                         ins->type = STACK_R8;
6498                                         break;
6499                                 default:
6500                                         g_assert (mini_type_is_reference (fsig->params [0]));
6501                                         ins->type = STACK_OBJ;
6502                                         break;
6503                                 }
6504                         }
6505                 }
6506
6507                 if (!strcmp (cmethod->name, "Write") && fsig->param_count == 2) {
6508                         guint32 opcode = 0;
6509                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6510
6511                         if (fsig->params [0]->type == MONO_TYPE_I1)
6512                                 opcode = OP_ATOMIC_STORE_I1;
6513                         else if (fsig->params [0]->type == MONO_TYPE_U1 || fsig->params [0]->type == MONO_TYPE_BOOLEAN)
6514                                 opcode = OP_ATOMIC_STORE_U1;
6515                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6516                                 opcode = OP_ATOMIC_STORE_I2;
6517                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6518                                 opcode = OP_ATOMIC_STORE_U2;
6519                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6520                                 opcode = OP_ATOMIC_STORE_I4;
6521                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6522                                 opcode = OP_ATOMIC_STORE_U4;
6523                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6524                                 opcode = OP_ATOMIC_STORE_R4;
6525                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6526                                 opcode = OP_ATOMIC_STORE_R8;
6527 #if SIZEOF_REGISTER == 8
6528                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_I)
6529                                 opcode = OP_ATOMIC_STORE_I8;
6530                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U8 || fsig->params [0]->type == MONO_TYPE_U)
6531                                 opcode = OP_ATOMIC_STORE_U8;
6532 #else
6533                         else if (fsig->params [0]->type == MONO_TYPE_I)
6534                                 opcode = OP_ATOMIC_STORE_I4;
6535                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U)
6536                                 opcode = OP_ATOMIC_STORE_U4;
6537 #endif
6538
6539                         if (opcode) {
6540                                 if (!mono_arch_opcode_supported (opcode))
6541                                         return NULL;
6542
6543                                 MONO_INST_NEW (cfg, ins, opcode);
6544                                 ins->dreg = args [0]->dreg;
6545                                 ins->sreg1 = args [1]->dreg;
6546                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_REL;
6547                                 MONO_ADD_INS (cfg->cbb, ins);
6548
6549                                 if (cfg->gen_write_barriers && is_ref)
6550                                         emit_write_barrier (cfg, args [0], args [1]);
6551                         }
6552                 }
6553
6554                 if (ins)
6555                         return ins;
6556         } else if (cmethod->klass->image == mono_defaults.corlib &&
6557                            (strcmp (cmethod->klass->name_space, "System.Diagnostics") == 0) &&
6558                            (strcmp (cmethod->klass->name, "Debugger") == 0)) {
6559                 if (!strcmp (cmethod->name, "Break") && fsig->param_count == 0) {
6560                         if (should_insert_brekpoint (cfg->method)) {
6561                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
6562                         } else {
6563                                 MONO_INST_NEW (cfg, ins, OP_NOP);
6564                                 MONO_ADD_INS (cfg->cbb, ins);
6565                         }
6566                         return ins;
6567                 }
6568         } else if (cmethod->klass->image == mono_defaults.corlib &&
6569                    (strcmp (cmethod->klass->name_space, "System") == 0) &&
6570                    (strcmp (cmethod->klass->name, "Environment") == 0)) {
6571                 if (!strcmp (cmethod->name, "get_IsRunningOnWindows") && fsig->param_count == 0) {
6572 #ifdef TARGET_WIN32
6573                         EMIT_NEW_ICONST (cfg, ins, 1);
6574 #else
6575                         EMIT_NEW_ICONST (cfg, ins, 0);
6576 #endif
6577                 }
6578         } else if (cmethod->klass == mono_defaults.math_class) {
6579                 /* 
6580                  * There is general branchless code for Min/Max, but it does not work for 
6581                  * all inputs:
6582                  * http://everything2.com/?node_id=1051618
6583                  */
6584         } else if (((!strcmp (cmethod->klass->image->assembly->aname.name, "MonoMac") ||
6585                     !strcmp (cmethod->klass->image->assembly->aname.name, "monotouch")) &&
6586                                 !strcmp (cmethod->klass->name_space, "XamCore.ObjCRuntime") &&
6587                                 !strcmp (cmethod->klass->name, "Selector")) ||
6588                            (!strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.iOS") &&
6589                                 !strcmp (cmethod->klass->name_space, "ObjCRuntime") &&
6590                                 !strcmp (cmethod->klass->name, "Selector"))
6591                            ) {
6592 #ifdef MONO_ARCH_HAVE_OBJC_GET_SELECTOR
6593                 if (!strcmp (cmethod->name, "GetHandle") && fsig->param_count == 1 &&
6594                     (args [0]->opcode == OP_GOT_ENTRY || args [0]->opcode == OP_AOTCONST) &&
6595                     cfg->compile_aot) {
6596                         MonoInst *pi;
6597                         MonoJumpInfoToken *ji;
6598                         MonoString *s;
6599
6600                         cfg->disable_llvm = TRUE;
6601
6602                         if (args [0]->opcode == OP_GOT_ENTRY) {
6603                                 pi = args [0]->inst_p1;
6604                                 g_assert (pi->opcode == OP_PATCH_INFO);
6605                                 g_assert (GPOINTER_TO_INT (pi->inst_p1) == MONO_PATCH_INFO_LDSTR);
6606                                 ji = pi->inst_p0;
6607                         } else {
6608                                 g_assert (GPOINTER_TO_INT (args [0]->inst_p1) == MONO_PATCH_INFO_LDSTR);
6609                                 ji = args [0]->inst_p0;
6610                         }
6611
6612                         NULLIFY_INS (args [0]);
6613
6614                         // FIXME: Ugly
6615                         s = mono_ldstr (cfg->domain, ji->image, mono_metadata_token_index (ji->token));
6616                         MONO_INST_NEW (cfg, ins, OP_OBJC_GET_SELECTOR);
6617                         ins->dreg = mono_alloc_ireg (cfg);
6618                         // FIXME: Leaks
6619                         ins->inst_p0 = mono_string_to_utf8 (s);
6620                         MONO_ADD_INS (cfg->cbb, ins);
6621                         return ins;
6622                 }
6623 #endif
6624         }
6625
6626 #ifdef MONO_ARCH_SIMD_INTRINSICS
6627         if (cfg->opt & MONO_OPT_SIMD) {
6628                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
6629                 if (ins)
6630                         return ins;
6631         }
6632 #endif
6633
6634         ins = mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
6635         if (ins)
6636                 return ins;
6637
6638         if (COMPILE_LLVM (cfg)) {
6639                 ins = llvm_emit_inst_for_method (cfg, cmethod, fsig, args);
6640                 if (ins)
6641                         return ins;
6642         }
6643
6644         return mono_arch_emit_inst_for_method (cfg, cmethod, fsig, args);
6645 }
6646
6647 /*
6648  * This entry point could be used later for arbitrary method
6649  * redirection.
6650  */
6651 inline static MonoInst*
6652 mini_redirect_call (MonoCompile *cfg, MonoMethod *method,  
6653                                         MonoMethodSignature *signature, MonoInst **args, MonoInst *this)
6654 {
6655         if (method->klass == mono_defaults.string_class) {
6656                 /* managed string allocation support */
6657                 if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && !(cfg->opt & MONO_OPT_SHARED)) {
6658                         MonoInst *iargs [2];
6659                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
6660                         MonoMethod *managed_alloc = NULL;
6661
6662                         g_assert (vtable); /*Should not fail since it System.String*/
6663 #ifndef MONO_CROSS_COMPILE
6664                         managed_alloc = mono_gc_get_managed_allocator (method->klass, FALSE, FALSE);
6665 #endif
6666                         if (!managed_alloc)
6667                                 return NULL;
6668                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
6669                         iargs [1] = args [0];
6670                         return mono_emit_method_call (cfg, managed_alloc, iargs, this);
6671                 }
6672         }
6673         return NULL;
6674 }
6675
6676 static void
6677 mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp)
6678 {
6679         MonoInst *store, *temp;
6680         int i;
6681
6682         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
6683                 MonoType *argtype = (sig->hasthis && (i == 0)) ? type_from_stack_type (*sp) : sig->params [i - sig->hasthis];
6684
6685                 /*
6686                  * FIXME: We should use *args++ = sp [0], but that would mean the arg
6687                  * would be different than the MonoInst's used to represent arguments, and
6688                  * the ldelema implementation can't deal with that.
6689                  * Solution: When ldelema is used on an inline argument, create a var for 
6690                  * it, emit ldelema on that var, and emit the saving code below in
6691                  * inline_method () if needed.
6692                  */
6693                 temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
6694                 cfg->args [i] = temp;
6695                 /* This uses cfg->args [i] which is set by the preceeding line */
6696                 EMIT_NEW_ARGSTORE (cfg, store, i, *sp);
6697                 store->cil_code = sp [0]->cil_code;
6698                 sp++;
6699         }
6700 }
6701
6702 #define MONO_INLINE_CALLED_LIMITED_METHODS 1
6703 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
6704
6705 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6706 static gboolean
6707 check_inline_called_method_name_limit (MonoMethod *called_method)
6708 {
6709         int strncmp_result;
6710         static const char *limit = NULL;
6711         
6712         if (limit == NULL) {
6713                 const char *limit_string = g_getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
6714
6715                 if (limit_string != NULL)
6716                         limit = limit_string;
6717                 else
6718                         limit = "";
6719         }
6720
6721         if (limit [0] != '\0') {
6722                 char *called_method_name = mono_method_full_name (called_method, TRUE);
6723
6724                 strncmp_result = strncmp (called_method_name, limit, strlen (limit));
6725                 g_free (called_method_name);
6726         
6727                 //return (strncmp_result <= 0);
6728                 return (strncmp_result == 0);
6729         } else {
6730                 return TRUE;
6731         }
6732 }
6733 #endif
6734
6735 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6736 static gboolean
6737 check_inline_caller_method_name_limit (MonoMethod *caller_method)
6738 {
6739         int strncmp_result;
6740         static const char *limit = NULL;
6741         
6742         if (limit == NULL) {
6743                 const char *limit_string = g_getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
6744                 if (limit_string != NULL) {
6745                         limit = limit_string;
6746                 } else {
6747                         limit = "";
6748                 }
6749         }
6750
6751         if (limit [0] != '\0') {
6752                 char *caller_method_name = mono_method_full_name (caller_method, TRUE);
6753
6754                 strncmp_result = strncmp (caller_method_name, limit, strlen (limit));
6755                 g_free (caller_method_name);
6756         
6757                 //return (strncmp_result <= 0);
6758                 return (strncmp_result == 0);
6759         } else {
6760                 return TRUE;
6761         }
6762 }
6763 #endif
6764
6765 static void
6766 emit_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6767 {
6768         static double r8_0 = 0.0;
6769         static float r4_0 = 0.0;
6770         MonoInst *ins;
6771         int t;
6772
6773         rtype = mini_get_underlying_type (rtype);
6774         t = rtype->type;
6775
6776         if (rtype->byref) {
6777                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6778         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6779                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
6780         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6781                 MONO_EMIT_NEW_I8CONST (cfg, dreg, 0);
6782         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6783                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
6784                 ins->type = STACK_R4;
6785                 ins->inst_p0 = (void*)&r4_0;
6786                 ins->dreg = dreg;
6787                 MONO_ADD_INS (cfg->cbb, ins);
6788         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6789                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
6790                 ins->type = STACK_R8;
6791                 ins->inst_p0 = (void*)&r8_0;
6792                 ins->dreg = dreg;
6793                 MONO_ADD_INS (cfg->cbb, ins);
6794         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6795                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6796                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6797         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
6798                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6799         } else {
6800                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6801         }
6802 }
6803
6804 static void
6805 emit_dummy_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6806 {
6807         int t;
6808
6809         rtype = mini_get_underlying_type (rtype);
6810         t = rtype->type;
6811
6812         if (rtype->byref) {
6813                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_PCONST);
6814         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6815                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_ICONST);
6816         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6817                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_I8CONST);
6818         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6819                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R4CONST);
6820         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6821                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R8CONST);
6822         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6823                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6824                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6825         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
6826                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6827         } else {
6828                 emit_init_rvar (cfg, dreg, rtype);
6829         }
6830 }
6831
6832 /* If INIT is FALSE, emit dummy initialization statements to keep the IR valid */
6833 static void
6834 emit_init_local (MonoCompile *cfg, int local, MonoType *type, gboolean init)
6835 {
6836         MonoInst *var = cfg->locals [local];
6837         if (COMPILE_SOFT_FLOAT (cfg)) {
6838                 MonoInst *store;
6839                 int reg = alloc_dreg (cfg, var->type);
6840                 emit_init_rvar (cfg, reg, type);
6841                 EMIT_NEW_LOCSTORE (cfg, store, local, cfg->cbb->last_ins);
6842         } else {
6843                 if (init)
6844                         emit_init_rvar (cfg, var->dreg, type);
6845                 else
6846                         emit_dummy_init_rvar (cfg, var->dreg, type);
6847         }
6848 }
6849
6850 /*
6851  * inline_method:
6852  *
6853  *   Return the cost of inlining CMETHOD.
6854  */
6855 static int
6856 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
6857                            guchar *ip, guint real_offset, gboolean inline_always)
6858 {
6859         MonoInst *ins, *rvar = NULL;
6860         MonoMethodHeader *cheader;
6861         MonoBasicBlock *ebblock, *sbblock;
6862         int i, costs;
6863         MonoMethod *prev_inlined_method;
6864         MonoInst **prev_locals, **prev_args;
6865         MonoType **prev_arg_types;
6866         guint prev_real_offset;
6867         GHashTable *prev_cbb_hash;
6868         MonoBasicBlock **prev_cil_offset_to_bb;
6869         MonoBasicBlock *prev_cbb;
6870         unsigned char* prev_cil_start;
6871         guint32 prev_cil_offset_to_bb_len;
6872         MonoMethod *prev_current_method;
6873         MonoGenericContext *prev_generic_context;
6874         gboolean ret_var_set, prev_ret_var_set, prev_disable_inline, virtual = FALSE;
6875
6876         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
6877
6878 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6879         if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod))
6880                 return 0;
6881 #endif
6882 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6883         if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method))
6884                 return 0;
6885 #endif
6886
6887         if (!fsig)
6888                 fsig = mono_method_signature (cmethod);
6889
6890         if (cfg->verbose_level > 2)
6891                 printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
6892
6893         if (!cmethod->inline_info) {
6894                 cfg->stat_inlineable_methods++;
6895                 cmethod->inline_info = 1;
6896         }
6897
6898         /* allocate local variables */
6899         cheader = mono_method_get_header (cmethod);
6900
6901         if (cheader == NULL || mono_loader_get_last_error ()) {
6902                 MonoLoaderError *error = mono_loader_get_last_error ();
6903
6904                 if (cheader)
6905                         mono_metadata_free_mh (cheader);
6906                 if (inline_always && error)
6907                         mono_cfg_set_exception (cfg, error->exception_type);
6908
6909                 mono_loader_clear_error ();
6910                 return 0;
6911         }
6912
6913         /*Must verify before creating locals as it can cause the JIT to assert.*/
6914         if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
6915                 mono_metadata_free_mh (cheader);
6916                 return 0;
6917         }
6918
6919         /* allocate space to store the return value */
6920         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
6921                 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
6922         }
6923
6924         prev_locals = cfg->locals;
6925         cfg->locals = mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));     
6926         for (i = 0; i < cheader->num_locals; ++i)
6927                 cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
6928
6929         /* allocate start and end blocks */
6930         /* This is needed so if the inline is aborted, we can clean up */
6931         NEW_BBLOCK (cfg, sbblock);
6932         sbblock->real_offset = real_offset;
6933
6934         NEW_BBLOCK (cfg, ebblock);
6935         ebblock->block_num = cfg->num_bblocks++;
6936         ebblock->real_offset = real_offset;
6937
6938         prev_args = cfg->args;
6939         prev_arg_types = cfg->arg_types;
6940         prev_inlined_method = cfg->inlined_method;
6941         cfg->inlined_method = cmethod;
6942         cfg->ret_var_set = FALSE;
6943         cfg->inline_depth ++;
6944         prev_real_offset = cfg->real_offset;
6945         prev_cbb_hash = cfg->cbb_hash;
6946         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
6947         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
6948         prev_cil_start = cfg->cil_start;
6949         prev_cbb = cfg->cbb;
6950         prev_current_method = cfg->current_method;
6951         prev_generic_context = cfg->generic_context;
6952         prev_ret_var_set = cfg->ret_var_set;
6953         prev_disable_inline = cfg->disable_inline;
6954
6955         if (ip && *ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
6956                 virtual = TRUE;
6957
6958         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, sp, real_offset, virtual);
6959
6960         ret_var_set = cfg->ret_var_set;
6961
6962         cfg->inlined_method = prev_inlined_method;
6963         cfg->real_offset = prev_real_offset;
6964         cfg->cbb_hash = prev_cbb_hash;
6965         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
6966         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
6967         cfg->cil_start = prev_cil_start;
6968         cfg->locals = prev_locals;
6969         cfg->args = prev_args;
6970         cfg->arg_types = prev_arg_types;
6971         cfg->current_method = prev_current_method;
6972         cfg->generic_context = prev_generic_context;
6973         cfg->ret_var_set = prev_ret_var_set;
6974         cfg->disable_inline = prev_disable_inline;
6975         cfg->inline_depth --;
6976
6977         if ((costs >= 0 && costs < 60) || inline_always) {
6978                 if (cfg->verbose_level > 2)
6979                         printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
6980                 
6981                 cfg->stat_inlined_methods++;
6982
6983                 /* always add some code to avoid block split failures */
6984                 MONO_INST_NEW (cfg, ins, OP_NOP);
6985                 MONO_ADD_INS (prev_cbb, ins);
6986
6987                 prev_cbb->next_bb = sbblock;
6988                 link_bblock (cfg, prev_cbb, sbblock);
6989
6990                 /* 
6991                  * Get rid of the begin and end bblocks if possible to aid local
6992                  * optimizations.
6993                  */
6994                 mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
6995
6996                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
6997                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
6998
6999                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
7000                         MonoBasicBlock *prev = ebblock->in_bb [0];
7001                         mono_merge_basic_blocks (cfg, prev, ebblock);
7002                         cfg->cbb = prev;
7003                         if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
7004                                 mono_merge_basic_blocks (cfg, prev_cbb, prev);
7005                                 cfg->cbb = prev_cbb;
7006                         }
7007                 } else {
7008                         /* 
7009                          * Its possible that the rvar is set in some prev bblock, but not in others.
7010                          * (#1835).
7011                          */
7012                         if (rvar) {
7013                                 MonoBasicBlock *bb;
7014
7015                                 for (i = 0; i < ebblock->in_count; ++i) {
7016                                         bb = ebblock->in_bb [i];
7017
7018                                         if (bb->last_ins && bb->last_ins->opcode == OP_NOT_REACHED) {
7019                                                 cfg->cbb = bb;
7020
7021                                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
7022                                         }
7023                                 }
7024                         }
7025
7026                         cfg->cbb = ebblock;
7027                 }
7028
7029                 if (rvar) {
7030                         /*
7031                          * If the inlined method contains only a throw, then the ret var is not 
7032                          * set, so set it to a dummy value.
7033                          */
7034                         if (!ret_var_set)
7035                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
7036
7037                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
7038                         *sp++ = ins;
7039                 }
7040                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
7041                 return costs + 1;
7042         } else {
7043                 if (cfg->verbose_level > 2)
7044                         printf ("INLINE ABORTED %s (cost %d)\n", mono_method_full_name (cmethod, TRUE), costs);
7045                 cfg->exception_type = MONO_EXCEPTION_NONE;
7046                 mono_loader_clear_error ();
7047
7048                 /* This gets rid of the newly added bblocks */
7049                 cfg->cbb = prev_cbb;
7050         }
7051         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
7052         return 0;
7053 }
7054
7055 /*
7056  * Some of these comments may well be out-of-date.
7057  * Design decisions: we do a single pass over the IL code (and we do bblock 
7058  * splitting/merging in the few cases when it's required: a back jump to an IL
7059  * address that was not already seen as bblock starting point).
7060  * Code is validated as we go (full verification is still better left to metadata/verify.c).
7061  * Complex operations are decomposed in simpler ones right away. We need to let the 
7062  * arch-specific code peek and poke inside this process somehow (except when the 
7063  * optimizations can take advantage of the full semantic info of coarse opcodes).
7064  * All the opcodes of the form opcode.s are 'normalized' to opcode.
7065  * MonoInst->opcode initially is the IL opcode or some simplification of that 
7066  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
7067  * opcode with value bigger than OP_LAST.
7068  * At this point the IR can be handed over to an interpreter, a dumb code generator
7069  * or to the optimizing code generator that will translate it to SSA form.
7070  *
7071  * Profiling directed optimizations.
7072  * We may compile by default with few or no optimizations and instrument the code
7073  * or the user may indicate what methods to optimize the most either in a config file
7074  * or through repeated runs where the compiler applies offline the optimizations to 
7075  * each method and then decides if it was worth it.
7076  */
7077
7078 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
7079 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
7080 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
7081 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
7082 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
7083 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
7084 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
7085 #define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) TYPE_LOAD_ERROR ((klass))
7086
7087 /* offset from br.s -> br like opcodes */
7088 #define BIG_BRANCH_OFFSET 13
7089
7090 static gboolean
7091 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
7092 {
7093         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
7094
7095         return b == NULL || b == bb;
7096 }
7097
7098 static int
7099 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
7100 {
7101         unsigned char *ip = start;
7102         unsigned char *target;
7103         int i;
7104         guint cli_addr;
7105         MonoBasicBlock *bblock;
7106         const MonoOpcode *opcode;
7107
7108         while (ip < end) {
7109                 cli_addr = ip - start;
7110                 i = mono_opcode_value ((const guint8 **)&ip, end);
7111                 if (i < 0)
7112                         UNVERIFIED;
7113                 opcode = &mono_opcodes [i];
7114                 switch (opcode->argument) {
7115                 case MonoInlineNone:
7116                         ip++; 
7117                         break;
7118                 case MonoInlineString:
7119                 case MonoInlineType:
7120                 case MonoInlineField:
7121                 case MonoInlineMethod:
7122                 case MonoInlineTok:
7123                 case MonoInlineSig:
7124                 case MonoShortInlineR:
7125                 case MonoInlineI:
7126                         ip += 5;
7127                         break;
7128                 case MonoInlineVar:
7129                         ip += 3;
7130                         break;
7131                 case MonoShortInlineVar:
7132                 case MonoShortInlineI:
7133                         ip += 2;
7134                         break;
7135                 case MonoShortInlineBrTarget:
7136                         target = start + cli_addr + 2 + (signed char)ip [1];
7137                         GET_BBLOCK (cfg, bblock, target);
7138                         ip += 2;
7139                         if (ip < end)
7140                                 GET_BBLOCK (cfg, bblock, ip);
7141                         break;
7142                 case MonoInlineBrTarget:
7143                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
7144                         GET_BBLOCK (cfg, bblock, target);
7145                         ip += 5;
7146                         if (ip < end)
7147                                 GET_BBLOCK (cfg, bblock, ip);
7148                         break;
7149                 case MonoInlineSwitch: {
7150                         guint32 n = read32 (ip + 1);
7151                         guint32 j;
7152                         ip += 5;
7153                         cli_addr += 5 + 4 * n;
7154                         target = start + cli_addr;
7155                         GET_BBLOCK (cfg, bblock, target);
7156                         
7157                         for (j = 0; j < n; ++j) {
7158                                 target = start + cli_addr + (gint32)read32 (ip);
7159                                 GET_BBLOCK (cfg, bblock, target);
7160                                 ip += 4;
7161                         }
7162                         break;
7163                 }
7164                 case MonoInlineR:
7165                 case MonoInlineI8:
7166                         ip += 9;
7167                         break;
7168                 default:
7169                         g_assert_not_reached ();
7170                 }
7171
7172                 if (i == CEE_THROW) {
7173                         unsigned char *bb_start = ip - 1;
7174                         
7175                         /* Find the start of the bblock containing the throw */
7176                         bblock = NULL;
7177                         while ((bb_start >= start) && !bblock) {
7178                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
7179                                 bb_start --;
7180                         }
7181                         if (bblock)
7182                                 bblock->out_of_line = 1;
7183                 }
7184         }
7185         return 0;
7186 unverified:
7187 exception_exit:
7188         *pos = ip;
7189         return 1;
7190 }
7191
7192 static inline MonoMethod *
7193 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
7194 {
7195         MonoMethod *method;
7196
7197         if (m->wrapper_type != MONO_WRAPPER_NONE) {
7198                 method = mono_method_get_wrapper_data (m, token);
7199                 if (context) {
7200                         MonoError error;
7201                         method = mono_class_inflate_generic_method_checked (method, context, &error);
7202                         g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
7203                 }
7204         } else {
7205                 method = mono_get_method_full (m->klass->image, token, klass, context);
7206         }
7207
7208         return method;
7209 }
7210
7211 static inline MonoMethod *
7212 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
7213 {
7214         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context);
7215
7216         if (method && cfg && !cfg->gshared && mono_class_is_open_constructed_type (&method->klass->byval_arg))
7217                 return NULL;
7218
7219         return method;
7220 }
7221
7222 static inline MonoClass*
7223 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
7224 {
7225         MonoError error;
7226         MonoClass *klass;
7227
7228         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7229                 klass = mono_method_get_wrapper_data (method, token);
7230                 if (context)
7231                         klass = mono_class_inflate_generic_class (klass, context);
7232         } else {
7233                 klass = mono_class_get_and_inflate_typespec_checked (method->klass->image, token, context, &error);
7234                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
7235         }
7236         if (klass)
7237                 mono_class_init (klass);
7238         return klass;
7239 }
7240
7241 static inline MonoMethodSignature*
7242 mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context)
7243 {
7244         MonoMethodSignature *fsig;
7245
7246         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7247                 MonoError error;
7248
7249                 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
7250                 if (context) {
7251                         fsig = mono_inflate_generic_signature (fsig, context, &error);
7252                         // FIXME:
7253                         g_assert (mono_error_ok (&error));
7254                 }
7255         } else {
7256                 fsig = mono_metadata_parse_signature (method->klass->image, token);
7257         }
7258         return fsig;
7259 }
7260
7261 static MonoMethod*
7262 throw_exception (void)
7263 {
7264         static MonoMethod *method = NULL;
7265
7266         if (!method) {
7267                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
7268                 method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
7269         }
7270         g_assert (method);
7271         return method;
7272 }
7273
7274 static void
7275 emit_throw_exception (MonoCompile *cfg, MonoException *ex)
7276 {
7277         MonoMethod *thrower = throw_exception ();
7278         MonoInst *args [1];
7279
7280         EMIT_NEW_PCONST (cfg, args [0], ex);
7281         mono_emit_method_call (cfg, thrower, args, NULL);
7282 }
7283
7284 /*
7285  * Return the original method is a wrapper is specified. We can only access 
7286  * the custom attributes from the original method.
7287  */
7288 static MonoMethod*
7289 get_original_method (MonoMethod *method)
7290 {
7291         if (method->wrapper_type == MONO_WRAPPER_NONE)
7292                 return method;
7293
7294         /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
7295         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
7296                 return NULL;
7297
7298         /* in other cases we need to find the original method */
7299         return mono_marshal_method_from_wrapper (method);
7300 }
7301
7302 static void
7303 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field)
7304 {
7305         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7306         MonoException *ex = mono_security_core_clr_is_field_access_allowed (get_original_method (caller), field);
7307         if (ex)
7308                 emit_throw_exception (cfg, ex);
7309 }
7310
7311 static void
7312 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
7313 {
7314         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7315         MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
7316         if (ex)
7317                 emit_throw_exception (cfg, ex);
7318 }
7319
7320 /*
7321  * Check that the IL instructions at ip are the array initialization
7322  * sequence and return the pointer to the data and the size.
7323  */
7324 static const char*
7325 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
7326 {
7327         /*
7328          * newarr[System.Int32]
7329          * dup
7330          * ldtoken field valuetype ...
7331          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
7332          */
7333         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
7334                 MonoError error;
7335                 guint32 token = read32 (ip + 7);
7336                 guint32 field_token = read32 (ip + 2);
7337                 guint32 field_index = field_token & 0xffffff;
7338                 guint32 rva;
7339                 const char *data_ptr;
7340                 int size = 0;
7341                 MonoMethod *cmethod;
7342                 MonoClass *dummy_class;
7343                 MonoClassField *field = mono_field_from_token_checked (method->klass->image, field_token, &dummy_class, NULL, &error);
7344                 int dummy_align;
7345
7346                 if (!field) {
7347                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7348                         return NULL;
7349                 }
7350
7351                 *out_field_token = field_token;
7352
7353                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
7354                 if (!cmethod)
7355                         return NULL;
7356                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
7357                         return NULL;
7358                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
7359                 case MONO_TYPE_BOOLEAN:
7360                 case MONO_TYPE_I1:
7361                 case MONO_TYPE_U1:
7362                         size = 1; break;
7363                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
7364 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
7365                 case MONO_TYPE_CHAR:
7366                 case MONO_TYPE_I2:
7367                 case MONO_TYPE_U2:
7368                         size = 2; break;
7369                 case MONO_TYPE_I4:
7370                 case MONO_TYPE_U4:
7371                 case MONO_TYPE_R4:
7372                         size = 4; break;
7373                 case MONO_TYPE_R8:
7374                 case MONO_TYPE_I8:
7375                 case MONO_TYPE_U8:
7376                         size = 8; break;
7377 #endif
7378                 default:
7379                         return NULL;
7380                 }
7381                 size *= len;
7382                 if (size > mono_type_size (field->type, &dummy_align))
7383                     return NULL;
7384                 *out_size = size;
7385                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
7386                 if (!image_is_dynamic (method->klass->image)) {
7387                         field_index = read32 (ip + 2) & 0xffffff;
7388                         mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
7389                         data_ptr = mono_image_rva_map (method->klass->image, rva);
7390                         /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
7391                         /* for aot code we do the lookup on load */
7392                         if (aot && data_ptr)
7393                                 return GUINT_TO_POINTER (rva);
7394                 } else {
7395                         /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
7396                         g_assert (!aot);
7397                         data_ptr = mono_field_get_data (field);
7398                 }
7399                 return data_ptr;
7400         }
7401         return NULL;
7402 }
7403
7404 static void
7405 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
7406 {
7407         char *method_fname = mono_method_full_name (method, TRUE);
7408         char *method_code;
7409         MonoMethodHeader *header = mono_method_get_header (method);
7410
7411         if (header->code_size == 0)
7412                 method_code = g_strdup ("method body is empty.");
7413         else
7414                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
7415         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
7416         cfg->exception_message = g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code);
7417         g_free (method_fname);
7418         g_free (method_code);
7419         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
7420 }
7421
7422 static void
7423 set_exception_object (MonoCompile *cfg, MonoException *exception)
7424 {
7425         mono_cfg_set_exception (cfg, MONO_EXCEPTION_OBJECT_SUPPLIED);
7426         MONO_GC_REGISTER_ROOT_SINGLE (cfg->exception_ptr);
7427         cfg->exception_ptr = exception;
7428 }
7429
7430 static void
7431 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
7432 {
7433         MonoInst *ins;
7434         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
7435         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
7436                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
7437                 /* Optimize reg-reg moves away */
7438                 /* 
7439                  * Can't optimize other opcodes, since sp[0] might point to
7440                  * the last ins of a decomposed opcode.
7441                  */
7442                 sp [0]->dreg = (cfg)->locals [n]->dreg;
7443         } else {
7444                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
7445         }
7446 }
7447
7448 /*
7449  * ldloca inhibits many optimizations so try to get rid of it in common
7450  * cases.
7451  */
7452 static inline unsigned char *
7453 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
7454 {
7455         int local, token;
7456         MonoClass *klass;
7457         MonoType *type;
7458
7459         if (size == 1) {
7460                 local = ip [1];
7461                 ip += 2;
7462         } else {
7463                 local = read16 (ip + 2);
7464                 ip += 4;
7465         }
7466         
7467         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
7468                 /* From the INITOBJ case */
7469                 token = read32 (ip + 2);
7470                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
7471                 CHECK_TYPELOAD (klass);
7472                 type = mini_get_underlying_type (&klass->byval_arg);
7473                 emit_init_local (cfg, local, type, TRUE);
7474                 return ip + 6;
7475         }
7476  exception_exit:
7477         return NULL;
7478 }
7479
7480 static gboolean
7481 is_exception_class (MonoClass *class)
7482 {
7483         while (class) {
7484                 if (class == mono_defaults.exception_class)
7485                         return TRUE;
7486                 class = class->parent;
7487         }
7488         return FALSE;
7489 }
7490
7491 /*
7492  * is_jit_optimizer_disabled:
7493  *
7494  *   Determine whenever M's assembly has a DebuggableAttribute with the
7495  * IsJITOptimizerDisabled flag set.
7496  */
7497 static gboolean
7498 is_jit_optimizer_disabled (MonoMethod *m)
7499 {
7500         MonoAssembly *ass = m->klass->image->assembly;
7501         MonoCustomAttrInfo* attrs;
7502         static MonoClass *klass;
7503         int i;
7504         gboolean val = FALSE;
7505
7506         g_assert (ass);
7507         if (ass->jit_optimizer_disabled_inited)
7508                 return ass->jit_optimizer_disabled;
7509
7510         if (!klass)
7511                 klass = mono_class_from_name (mono_defaults.corlib, "System.Diagnostics", "DebuggableAttribute");
7512         if (!klass) {
7513                 /* Linked away */
7514                 ass->jit_optimizer_disabled = FALSE;
7515                 mono_memory_barrier ();
7516                 ass->jit_optimizer_disabled_inited = TRUE;
7517                 return FALSE;
7518         }
7519
7520         attrs = mono_custom_attrs_from_assembly (ass);
7521         if (attrs) {
7522                 for (i = 0; i < attrs->num_attrs; ++i) {
7523                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
7524                         const gchar *p;
7525                         MonoMethodSignature *sig;
7526
7527                         if (!attr->ctor || attr->ctor->klass != klass)
7528                                 continue;
7529                         /* Decode the attribute. See reflection.c */
7530                         p = (const char*)attr->data;
7531                         g_assert (read16 (p) == 0x0001);
7532                         p += 2;
7533
7534                         // FIXME: Support named parameters
7535                         sig = mono_method_signature (attr->ctor);
7536                         if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
7537                                 continue;
7538                         /* Two boolean arguments */
7539                         p ++;
7540                         val = *p;
7541                 }
7542                 mono_custom_attrs_free (attrs);
7543         }
7544
7545         ass->jit_optimizer_disabled = val;
7546         mono_memory_barrier ();
7547         ass->jit_optimizer_disabled_inited = TRUE;
7548
7549         return val;
7550 }
7551
7552 static gboolean
7553 is_supported_tail_call (MonoCompile *cfg, MonoMethod *method, MonoMethod *cmethod, MonoMethodSignature *fsig, int call_opcode)
7554 {
7555         gboolean supported_tail_call;
7556         int i;
7557
7558 #ifdef MONO_ARCH_HAVE_OP_TAIL_CALL
7559         supported_tail_call = mono_arch_tail_call_supported (cfg, mono_method_signature (method), mono_method_signature (cmethod));
7560 #else
7561         supported_tail_call = mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod)) && !MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->ret);
7562 #endif
7563
7564         for (i = 0; i < fsig->param_count; ++i) {
7565                 if (fsig->params [i]->byref || fsig->params [i]->type == MONO_TYPE_PTR || fsig->params [i]->type == MONO_TYPE_FNPTR)
7566                         /* These can point to the current method's stack */
7567                         supported_tail_call = FALSE;
7568         }
7569         if (fsig->hasthis && cmethod->klass->valuetype)
7570                 /* this might point to the current method's stack */
7571                 supported_tail_call = FALSE;
7572         if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
7573                 supported_tail_call = FALSE;
7574         if (cfg->method->save_lmf)
7575                 supported_tail_call = FALSE;
7576         if (cmethod->wrapper_type && cmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
7577                 supported_tail_call = FALSE;
7578         if (call_opcode != CEE_CALL)
7579                 supported_tail_call = FALSE;
7580
7581         /* Debugging support */
7582 #if 0
7583         if (supported_tail_call) {
7584                 if (!mono_debug_count ())
7585                         supported_tail_call = FALSE;
7586         }
7587 #endif
7588
7589         return supported_tail_call;
7590 }
7591
7592 /* emits the code needed to access a managed tls var (like ThreadStatic)
7593  * with the value of the tls offset in offset_reg. thread_ins represents the MonoInternalThread
7594  * pointer for the current thread.
7595  * Returns the MonoInst* representing the address of the tls var.
7596  */
7597 static MonoInst*
7598 emit_managed_static_data_access (MonoCompile *cfg, MonoInst *thread_ins, int offset_reg)
7599 {
7600         MonoInst *addr;
7601         int static_data_reg, array_reg, dreg;
7602         int offset2_reg, idx_reg;
7603         // inlined access to the tls data (see threads.c)
7604         static_data_reg = alloc_ireg (cfg);
7605         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
7606         idx_reg = alloc_ireg (cfg);
7607         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, idx_reg, offset_reg, 0x3f);
7608         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
7609         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
7610         array_reg = alloc_ireg (cfg);
7611         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
7612         offset2_reg = alloc_ireg (cfg);
7613         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, offset2_reg, offset_reg, 6);
7614         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset2_reg, 0x1ffffff);
7615         dreg = alloc_ireg (cfg);
7616         EMIT_NEW_BIALU (cfg, addr, OP_PADD, dreg, array_reg, offset2_reg);
7617         return addr;
7618 }
7619
7620 /*
7621  * handle_ctor_call:
7622  *
7623  *   Handle calls made to ctors from NEWOBJ opcodes.
7624  */
7625 static void
7626 handle_ctor_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used,
7627                                   MonoInst **sp, guint8 *ip, int *inline_costs)
7628 {
7629         MonoInst *vtable_arg = NULL, *callvirt_this_arg = NULL, *ins;
7630
7631         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
7632                                         mono_method_is_generic_sharable (cmethod, TRUE)) {
7633                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
7634                         mono_class_vtable (cfg->domain, cmethod->klass);
7635                         CHECK_TYPELOAD (cmethod->klass);
7636
7637                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
7638                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
7639                 } else {
7640                         if (context_used) {
7641                                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
7642                                                                                                    cmethod->klass, MONO_RGCTX_INFO_VTABLE);
7643                         } else {
7644                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
7645
7646                                 CHECK_TYPELOAD (cmethod->klass);
7647                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
7648                         }
7649                 }
7650         }
7651
7652         /* Avoid virtual calls to ctors if possible */
7653         if (mono_class_is_marshalbyref (cmethod->klass))
7654                 callvirt_this_arg = sp [0];
7655
7656         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
7657                 g_assert (MONO_TYPE_IS_VOID (fsig->ret));
7658                 CHECK_CFG_EXCEPTION;
7659         } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
7660                            mono_method_check_inlining (cfg, cmethod) &&
7661                            !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE)) {
7662                 int costs;
7663
7664                 if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, FALSE))) {
7665                         cfg->real_offset += 5;
7666
7667                         *inline_costs += costs - 5;
7668                 } else {
7669                         INLINE_FAILURE ("inline failure");
7670                         // FIXME-VT: Clean this up
7671                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
7672                                 GSHAREDVT_FAILURE(*ip);
7673                         mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, callvirt_this_arg, NULL, NULL);
7674                 }
7675         } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
7676                 MonoInst *addr;
7677
7678                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
7679                 mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
7680         } else if (context_used &&
7681                            ((!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
7682                                  !mono_class_generic_sharing_enabled (cmethod->klass)) || cfg->gsharedvt)) {
7683                 MonoInst *cmethod_addr;
7684
7685                 /* Generic calls made out of gsharedvt methods cannot be patched, so use an indirect call */
7686
7687                 cmethod_addr = emit_get_rgctx_method (cfg, context_used,
7688                                                                                           cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
7689
7690                 mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
7691         } else {
7692                 INLINE_FAILURE ("ctor call");
7693                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
7694                                                                                   callvirt_this_arg, NULL, vtable_arg);
7695         }
7696  exception_exit:
7697         return;
7698 }
7699
7700 /*
7701  * mono_method_to_ir:
7702  *
7703  *   Translate the .net IL into linear IR.
7704  */
7705 int
7706 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
7707                    MonoInst *return_var, MonoInst **inline_args, 
7708                    guint inline_offset, gboolean is_virtual_call)
7709 {
7710         MonoError error;
7711         MonoInst *ins, **sp, **stack_start;
7712         MonoBasicBlock *tblock = NULL, *init_localsbb = NULL;
7713         MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
7714         MonoMethod *cmethod, *method_definition;
7715         MonoInst **arg_array;
7716         MonoMethodHeader *header;
7717         MonoImage *image;
7718         guint32 token, ins_flag;
7719         MonoClass *klass;
7720         MonoClass *constrained_class = NULL;
7721         unsigned char *ip, *end, *target, *err_pos;
7722         MonoMethodSignature *sig;
7723         MonoGenericContext *generic_context = NULL;
7724         MonoGenericContainer *generic_container = NULL;
7725         MonoType **param_types;
7726         int i, n, start_new_bblock, dreg;
7727         int num_calls = 0, inline_costs = 0;
7728         int breakpoint_id = 0;
7729         guint num_args;
7730         GSList *class_inits = NULL;
7731         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
7732         int context_used;
7733         gboolean init_locals, seq_points, skip_dead_blocks;
7734         gboolean sym_seq_points = FALSE;
7735         MonoDebugMethodInfo *minfo;
7736         MonoBitSet *seq_point_locs = NULL;
7737         MonoBitSet *seq_point_set_locs = NULL;
7738
7739         cfg->disable_inline = is_jit_optimizer_disabled (method);
7740
7741         /* serialization and xdomain stuff may need access to private fields and methods */
7742         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
7743         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
7744         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
7745         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
7746         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
7747         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
7748
7749         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
7750         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
7751         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
7752         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
7753         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF;
7754
7755         image = method->klass->image;
7756         header = mono_method_get_header (method);
7757         if (!header) {
7758                 MonoLoaderError *error;
7759
7760                 if ((error = mono_loader_get_last_error ())) {
7761                         mono_cfg_set_exception (cfg, error->exception_type);
7762                 } else {
7763                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
7764                         cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
7765                 }
7766                 goto exception_exit;
7767         }
7768         generic_container = mono_method_get_generic_container (method);
7769         sig = mono_method_signature (method);
7770         num_args = sig->hasthis + sig->param_count;
7771         ip = (unsigned char*)header->code;
7772         cfg->cil_start = ip;
7773         end = ip + header->code_size;
7774         cfg->stat_cil_code_size += header->code_size;
7775
7776         seq_points = cfg->gen_seq_points && cfg->method == method;
7777
7778         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
7779                 /* We could hit a seq point before attaching to the JIT (#8338) */
7780                 seq_points = FALSE;
7781         }
7782
7783         if (cfg->gen_sdb_seq_points && cfg->method == method) {
7784                 minfo = mono_debug_lookup_method (method);
7785                 if (minfo) {
7786                         MonoSymSeqPoint *sps;
7787                         int i, n_il_offsets;
7788
7789                         mono_debug_get_seq_points (minfo, NULL, NULL, NULL, &sps, &n_il_offsets);
7790                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7791                         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);
7792                         sym_seq_points = TRUE;
7793                         for (i = 0; i < n_il_offsets; ++i) {
7794                                 if (sps [i].il_offset < header->code_size)
7795                                         mono_bitset_set_fast (seq_point_locs, sps [i].il_offset);
7796                         }
7797                         g_free (sps);
7798                 } else if (!method->wrapper_type && !method->dynamic && mono_debug_image_has_debug_info (method->klass->image)) {
7799                         /* Methods without line number info like auto-generated property accessors */
7800                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7801                         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);
7802                         sym_seq_points = TRUE;
7803                 }
7804         }
7805
7806         /* 
7807          * Methods without init_locals set could cause asserts in various passes
7808          * (#497220). To work around this, we emit dummy initialization opcodes
7809          * (OP_DUMMY_ICONST etc.) which generate no code. These are only supported
7810          * on some platforms.
7811          */
7812         if ((cfg->opt & MONO_OPT_UNSAFE) && ARCH_HAVE_DUMMY_INIT)
7813                 init_locals = header->init_locals;
7814         else
7815                 init_locals = TRUE;
7816
7817         method_definition = method;
7818         while (method_definition->is_inflated) {
7819                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
7820                 method_definition = imethod->declaring;
7821         }
7822
7823         /* SkipVerification is not allowed if core-clr is enabled */
7824         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
7825                 dont_verify = TRUE;
7826                 dont_verify_stloc = TRUE;
7827         }
7828
7829         if (sig->is_inflated)
7830                 generic_context = mono_method_get_context (method);
7831         else if (generic_container)
7832                 generic_context = &generic_container->context;
7833         cfg->generic_context = generic_context;
7834
7835         if (!cfg->gshared)
7836                 g_assert (!sig->has_type_parameters);
7837
7838         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
7839                 g_assert (method->is_inflated);
7840                 g_assert (mono_method_get_context (method)->method_inst);
7841         }
7842         if (method->is_inflated && mono_method_get_context (method)->method_inst)
7843                 g_assert (sig->generic_param_count);
7844
7845         if (cfg->method == method) {
7846                 cfg->real_offset = 0;
7847         } else {
7848                 cfg->real_offset = inline_offset;
7849         }
7850
7851         cfg->cil_offset_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
7852         cfg->cil_offset_to_bb_len = header->code_size;
7853
7854         cfg->current_method = method;
7855
7856         if (cfg->verbose_level > 2)
7857                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
7858
7859         param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
7860         if (sig->hasthis)
7861                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
7862         for (n = 0; n < sig->param_count; ++n)
7863                 param_types [n + sig->hasthis] = sig->params [n];
7864         cfg->arg_types = param_types;
7865
7866         cfg->dont_inline = g_list_prepend (cfg->dont_inline, method);
7867         if (cfg->method == method) {
7868
7869                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
7870                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
7871
7872                 /* ENTRY BLOCK */
7873                 NEW_BBLOCK (cfg, start_bblock);
7874                 cfg->bb_entry = start_bblock;
7875                 start_bblock->cil_code = NULL;
7876                 start_bblock->cil_length = 0;
7877
7878                 /* EXIT BLOCK */
7879                 NEW_BBLOCK (cfg, end_bblock);
7880                 cfg->bb_exit = end_bblock;
7881                 end_bblock->cil_code = NULL;
7882                 end_bblock->cil_length = 0;
7883                 end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
7884                 g_assert (cfg->num_bblocks == 2);
7885
7886                 arg_array = cfg->args;
7887
7888                 if (header->num_clauses) {
7889                         cfg->spvars = g_hash_table_new (NULL, NULL);
7890                         cfg->exvars = g_hash_table_new (NULL, NULL);
7891                 }
7892                 /* handle exception clauses */
7893                 for (i = 0; i < header->num_clauses; ++i) {
7894                         MonoBasicBlock *try_bb;
7895                         MonoExceptionClause *clause = &header->clauses [i];
7896                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
7897                         try_bb->real_offset = clause->try_offset;
7898                         try_bb->try_start = TRUE;
7899                         try_bb->region = ((i + 1) << 8) | clause->flags;
7900                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
7901                         tblock->real_offset = clause->handler_offset;
7902                         tblock->flags |= BB_EXCEPTION_HANDLER;
7903
7904                         /*
7905                          * Linking the try block with the EH block hinders inlining as we won't be able to 
7906                          * merge the bblocks from inlining and produce an artificial hole for no good reason.
7907                          */
7908                         if (COMPILE_LLVM (cfg))
7909                                 link_bblock (cfg, try_bb, tblock);
7910
7911                         if (*(ip + clause->handler_offset) == CEE_POP)
7912                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
7913
7914                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
7915                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
7916                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
7917                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
7918                                 MONO_ADD_INS (tblock, ins);
7919
7920                                 if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY) {
7921                                         /* finally clauses already have a seq point */
7922                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
7923                                         MONO_ADD_INS (tblock, ins);
7924                                 }
7925
7926                                 /* todo: is a fault block unsafe to optimize? */
7927                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
7928                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
7929                         }
7930
7931                         /*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);
7932                           while (p < end) {
7933                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
7934                           }*/
7935                         /* catch and filter blocks get the exception object on the stack */
7936                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
7937                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7938
7939                                 /* mostly like handle_stack_args (), but just sets the input args */
7940                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
7941                                 tblock->in_scount = 1;
7942                                 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
7943                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
7944
7945                                 cfg->cbb = tblock;
7946
7947 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
7948                                 /* The EH code passes in the exception in a register to both JITted and LLVM compiled code */
7949                                 if (!cfg->compile_llvm) {
7950                                         MONO_INST_NEW (cfg, ins, OP_GET_EX_OBJ);
7951                                         ins->dreg = tblock->in_stack [0]->dreg;
7952                                         MONO_ADD_INS (tblock, ins);
7953                                 }
7954 #else
7955                                 MonoInst *dummy_use;
7956
7957                                 /* 
7958                                  * Add a dummy use for the exvar so its liveness info will be
7959                                  * correct.
7960                                  */
7961                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
7962 #endif
7963                                 
7964                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7965                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
7966                                         tblock->flags |= BB_EXCEPTION_HANDLER;
7967                                         tblock->real_offset = clause->data.filter_offset;
7968                                         tblock->in_scount = 1;
7969                                         tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
7970                                         /* The filter block shares the exvar with the handler block */
7971                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
7972                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
7973                                         MONO_ADD_INS (tblock, ins);
7974                                 }
7975                         }
7976
7977                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
7978                                         clause->data.catch_class &&
7979                                         cfg->gshared &&
7980                                         mono_class_check_context_used (clause->data.catch_class)) {
7981                                 /*
7982                                  * In shared generic code with catch
7983                                  * clauses containing type variables
7984                                  * the exception handling code has to
7985                                  * be able to get to the rgctx.
7986                                  * Therefore we have to make sure that
7987                                  * the vtable/mrgctx argument (for
7988                                  * static or generic methods) or the
7989                                  * "this" argument (for non-static
7990                                  * methods) are live.
7991                                  */
7992                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
7993                                                 mini_method_get_context (method)->method_inst ||
7994                                                 method->klass->valuetype) {
7995                                         mono_get_vtable_var (cfg);
7996                                 } else {
7997                                         MonoInst *dummy_use;
7998
7999                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
8000                                 }
8001                         }
8002                 }
8003         } else {
8004                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
8005                 cfg->cbb = start_bblock;
8006                 cfg->args = arg_array;
8007                 mono_save_args (cfg, sig, inline_args);
8008         }
8009
8010         /* FIRST CODE BLOCK */
8011         NEW_BBLOCK (cfg, tblock);
8012         tblock->cil_code = ip;
8013         cfg->cbb = tblock;
8014         cfg->ip = ip;
8015
8016         ADD_BBLOCK (cfg, tblock);
8017
8018         if (cfg->method == method) {
8019                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
8020                 if (breakpoint_id) {
8021                         MONO_INST_NEW (cfg, ins, OP_BREAK);
8022                         MONO_ADD_INS (cfg->cbb, ins);
8023                 }
8024         }
8025
8026         /* we use a separate basic block for the initialization code */
8027         NEW_BBLOCK (cfg, init_localsbb);
8028         cfg->bb_init = init_localsbb;
8029         init_localsbb->real_offset = cfg->real_offset;
8030         start_bblock->next_bb = init_localsbb;
8031         init_localsbb->next_bb = cfg->cbb;
8032         link_bblock (cfg, start_bblock, init_localsbb);
8033         link_bblock (cfg, init_localsbb, cfg->cbb);
8034                 
8035         cfg->cbb = init_localsbb;
8036
8037         if (cfg->gsharedvt && cfg->method == method) {
8038                 MonoGSharedVtMethodInfo *info;
8039                 MonoInst *var, *locals_var;
8040                 int dreg;
8041
8042                 info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoGSharedVtMethodInfo));
8043                 info->method = cfg->method;
8044                 info->count_entries = 16;
8045                 info->entries = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
8046                 cfg->gsharedvt_info = info;
8047
8048                 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8049                 /* prevent it from being register allocated */
8050                 //var->flags |= MONO_INST_VOLATILE;
8051                 cfg->gsharedvt_info_var = var;
8052
8053                 ins = emit_get_rgctx_gsharedvt_method (cfg, mini_method_check_context_used (cfg, method), method, info);
8054                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, var->dreg, ins->dreg);
8055
8056                 /* Allocate locals */
8057                 locals_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8058                 /* prevent it from being register allocated */
8059                 //locals_var->flags |= MONO_INST_VOLATILE;
8060                 cfg->gsharedvt_locals_var = locals_var;
8061
8062                 dreg = alloc_ireg (cfg);
8063                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, dreg, var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, locals_size));
8064
8065                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
8066                 ins->dreg = locals_var->dreg;
8067                 ins->sreg1 = dreg;
8068                 MONO_ADD_INS (cfg->cbb, ins);
8069                 cfg->gsharedvt_locals_var_ins = ins;
8070                 
8071                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
8072                 /*
8073                 if (init_locals)
8074                         ins->flags |= MONO_INST_INIT;
8075                 */
8076         }
8077
8078         if (mono_security_core_clr_enabled ()) {
8079                 /* check if this is native code, e.g. an icall or a p/invoke */
8080                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
8081                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
8082                         if (wrapped) {
8083                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
8084                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
8085
8086                                 /* if this ia a native call then it can only be JITted from platform code */
8087                                 if ((icall || pinvk) && method->klass && method->klass->image) {
8088                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
8089                                                 MonoException *ex = icall ? mono_get_exception_security () : 
8090                                                         mono_get_exception_method_access ();
8091                                                 emit_throw_exception (cfg, ex);
8092                                         }
8093                                 }
8094                         }
8095                 }
8096         }
8097
8098         CHECK_CFG_EXCEPTION;
8099
8100         if (header->code_size == 0)
8101                 UNVERIFIED;
8102
8103         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
8104                 ip = err_pos;
8105                 UNVERIFIED;
8106         }
8107
8108         if (cfg->method == method)
8109                 mono_debug_init_method (cfg, cfg->cbb, breakpoint_id);
8110
8111         for (n = 0; n < header->num_locals; ++n) {
8112                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
8113                         UNVERIFIED;
8114         }
8115         class_inits = NULL;
8116
8117         /* We force the vtable variable here for all shared methods
8118            for the possibility that they might show up in a stack
8119            trace where their exact instantiation is needed. */
8120         if (cfg->gshared && method == cfg->method) {
8121                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8122                                 mini_method_get_context (method)->method_inst ||
8123                                 method->klass->valuetype) {
8124                         mono_get_vtable_var (cfg);
8125                 } else {
8126                         /* FIXME: Is there a better way to do this?
8127                            We need the variable live for the duration
8128                            of the whole method. */
8129                         cfg->args [0]->flags |= MONO_INST_VOLATILE;
8130                 }
8131         }
8132
8133         /* add a check for this != NULL to inlined methods */
8134         if (is_virtual_call) {
8135                 MonoInst *arg_ins;
8136
8137                 NEW_ARGLOAD (cfg, arg_ins, 0);
8138                 MONO_ADD_INS (cfg->cbb, arg_ins);
8139                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
8140         }
8141
8142         skip_dead_blocks = !dont_verify;
8143         if (skip_dead_blocks) {
8144                 original_bb = bb = mono_basic_block_split (method, &cfg->error);
8145                 CHECK_CFG_ERROR;
8146                 g_assert (bb);
8147         }
8148
8149         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
8150         stack_start = sp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
8151
8152         ins_flag = 0;
8153         start_new_bblock = 0;
8154         while (ip < end) {
8155                 if (cfg->method == method)
8156                         cfg->real_offset = ip - header->code;
8157                 else
8158                         cfg->real_offset = inline_offset;
8159                 cfg->ip = ip;
8160
8161                 context_used = 0;
8162
8163                 if (start_new_bblock) {
8164                         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
8165                         if (start_new_bblock == 2) {
8166                                 g_assert (ip == tblock->cil_code);
8167                         } else {
8168                                 GET_BBLOCK (cfg, tblock, ip);
8169                         }
8170                         cfg->cbb->next_bb = tblock;
8171                         cfg->cbb = tblock;
8172                         start_new_bblock = 0;
8173                         for (i = 0; i < cfg->cbb->in_scount; ++i) {
8174                                 if (cfg->verbose_level > 3)
8175                                         printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8176                                 EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8177                                 *sp++ = ins;
8178                         }
8179                         if (class_inits)
8180                                 g_slist_free (class_inits);
8181                         class_inits = NULL;
8182                 } else {
8183                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != cfg->cbb)) {
8184                                 link_bblock (cfg, cfg->cbb, tblock);
8185                                 if (sp != stack_start) {
8186                                         handle_stack_args (cfg, stack_start, sp - stack_start);
8187                                         sp = stack_start;
8188                                         CHECK_UNVERIFIABLE (cfg);
8189                                 }
8190                                 cfg->cbb->next_bb = tblock;
8191                                 cfg->cbb = tblock;
8192                                 for (i = 0; i < cfg->cbb->in_scount; ++i) {
8193                                         if (cfg->verbose_level > 3)
8194                                                 printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8195                                         EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8196                                         *sp++ = ins;
8197                                 }
8198                                 g_slist_free (class_inits);
8199                                 class_inits = NULL;
8200                         }
8201                 }
8202
8203                 if (skip_dead_blocks) {
8204                         int ip_offset = ip - header->code;
8205
8206                         if (ip_offset == bb->end)
8207                                 bb = bb->next;
8208
8209                         if (bb->dead) {
8210                                 int op_size = mono_opcode_size (ip, end);
8211                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
8212
8213                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
8214
8215                                 if (ip_offset + op_size == bb->end) {
8216                                         MONO_INST_NEW (cfg, ins, OP_NOP);
8217                                         MONO_ADD_INS (cfg->cbb, ins);
8218                                         start_new_bblock = 1;
8219                                 }
8220
8221                                 ip += op_size;
8222                                 continue;
8223                         }
8224                 }
8225                 /*
8226                  * Sequence points are points where the debugger can place a breakpoint.
8227                  * Currently, we generate these automatically at points where the IL
8228                  * stack is empty.
8229                  */
8230                 if (seq_points && ((!sym_seq_points && (sp == stack_start)) || (sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code)))) {
8231                         /*
8232                          * Make methods interruptable at the beginning, and at the targets of
8233                          * backward branches.
8234                          * Also, do this at the start of every bblock in methods with clauses too,
8235                          * to be able to handle instructions with inprecise control flow like
8236                          * throw/endfinally.
8237                          * Backward branches are handled at the end of method-to-ir ().
8238                          */
8239                         gboolean intr_loc = ip == header->code || (!cfg->cbb->last_ins && cfg->header->num_clauses);
8240                         gboolean sym_seq_point = sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code);
8241
8242                         /* Avoid sequence points on empty IL like .volatile */
8243                         // FIXME: Enable this
8244                         //if (!(cfg->cbb->last_ins && cfg->cbb->last_ins->opcode == OP_SEQ_POINT)) {
8245                         NEW_SEQ_POINT (cfg, ins, ip - header->code, intr_loc);
8246                         if ((sp != stack_start) && !sym_seq_point)
8247                                 ins->flags |= MONO_INST_NONEMPTY_STACK;
8248                         MONO_ADD_INS (cfg->cbb, ins);
8249
8250                         if (sym_seq_points)
8251                                 mono_bitset_set_fast (seq_point_set_locs, ip - header->code);
8252                 }
8253
8254                 cfg->cbb->real_offset = cfg->real_offset;
8255
8256                 if ((cfg->method == method) && cfg->coverage_info) {
8257                         guint32 cil_offset = ip - header->code;
8258                         cfg->coverage_info->data [cil_offset].cil_code = ip;
8259
8260                         /* TODO: Use an increment here */
8261 #if defined(TARGET_X86)
8262                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
8263                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
8264                         ins->inst_imm = 1;
8265                         MONO_ADD_INS (cfg->cbb, ins);
8266 #else
8267                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
8268                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
8269 #endif
8270                 }
8271
8272                 if (cfg->verbose_level > 3)
8273                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
8274
8275                 switch (*ip) {
8276                 case CEE_NOP:
8277                         if (seq_points && !sym_seq_points && sp != stack_start) {
8278                                 /*
8279                                  * The C# compiler uses these nops to notify the JIT that it should
8280                                  * insert seq points.
8281                                  */
8282                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, FALSE);
8283                                 MONO_ADD_INS (cfg->cbb, ins);
8284                         }
8285                         if (cfg->keep_cil_nops)
8286                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
8287                         else
8288                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8289                         ip++;
8290                         MONO_ADD_INS (cfg->cbb, ins);
8291                         break;
8292                 case CEE_BREAK:
8293                         if (should_insert_brekpoint (cfg->method)) {
8294                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
8295                         } else {
8296                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8297                         }
8298                         ip++;
8299                         MONO_ADD_INS (cfg->cbb, ins);
8300                         break;
8301                 case CEE_LDARG_0:
8302                 case CEE_LDARG_1:
8303                 case CEE_LDARG_2:
8304                 case CEE_LDARG_3:
8305                         CHECK_STACK_OVF (1);
8306                         n = (*ip)-CEE_LDARG_0;
8307                         CHECK_ARG (n);
8308                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8309                         ip++;
8310                         *sp++ = ins;
8311                         break;
8312                 case CEE_LDLOC_0:
8313                 case CEE_LDLOC_1:
8314                 case CEE_LDLOC_2:
8315                 case CEE_LDLOC_3:
8316                         CHECK_STACK_OVF (1);
8317                         n = (*ip)-CEE_LDLOC_0;
8318                         CHECK_LOCAL (n);
8319                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8320                         ip++;
8321                         *sp++ = ins;
8322                         break;
8323                 case CEE_STLOC_0:
8324                 case CEE_STLOC_1:
8325                 case CEE_STLOC_2:
8326                 case CEE_STLOC_3: {
8327                         CHECK_STACK (1);
8328                         n = (*ip)-CEE_STLOC_0;
8329                         CHECK_LOCAL (n);
8330                         --sp;
8331                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
8332                                 UNVERIFIED;
8333                         emit_stloc_ir (cfg, sp, header, n);
8334                         ++ip;
8335                         inline_costs += 1;
8336                         break;
8337                         }
8338                 case CEE_LDARG_S:
8339                         CHECK_OPSIZE (2);
8340                         CHECK_STACK_OVF (1);
8341                         n = ip [1];
8342                         CHECK_ARG (n);
8343                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8344                         *sp++ = ins;
8345                         ip += 2;
8346                         break;
8347                 case CEE_LDARGA_S:
8348                         CHECK_OPSIZE (2);
8349                         CHECK_STACK_OVF (1);
8350                         n = ip [1];
8351                         CHECK_ARG (n);
8352                         NEW_ARGLOADA (cfg, ins, n);
8353                         MONO_ADD_INS (cfg->cbb, ins);
8354                         *sp++ = ins;
8355                         ip += 2;
8356                         break;
8357                 case CEE_STARG_S:
8358                         CHECK_OPSIZE (2);
8359                         CHECK_STACK (1);
8360                         --sp;
8361                         n = ip [1];
8362                         CHECK_ARG (n);
8363                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
8364                                 UNVERIFIED;
8365                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
8366                         ip += 2;
8367                         break;
8368                 case CEE_LDLOC_S:
8369                         CHECK_OPSIZE (2);
8370                         CHECK_STACK_OVF (1);
8371                         n = ip [1];
8372                         CHECK_LOCAL (n);
8373                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8374                         *sp++ = ins;
8375                         ip += 2;
8376                         break;
8377                 case CEE_LDLOCA_S: {
8378                         unsigned char *tmp_ip;
8379                         CHECK_OPSIZE (2);
8380                         CHECK_STACK_OVF (1);
8381                         CHECK_LOCAL (ip [1]);
8382
8383                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
8384                                 ip = tmp_ip;
8385                                 inline_costs += 1;
8386                                 break;
8387                         }
8388
8389                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
8390                         *sp++ = ins;
8391                         ip += 2;
8392                         break;
8393                 }
8394                 case CEE_STLOC_S:
8395                         CHECK_OPSIZE (2);
8396                         CHECK_STACK (1);
8397                         --sp;
8398                         CHECK_LOCAL (ip [1]);
8399                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
8400                                 UNVERIFIED;
8401                         emit_stloc_ir (cfg, sp, header, ip [1]);
8402                         ip += 2;
8403                         inline_costs += 1;
8404                         break;
8405                 case CEE_LDNULL:
8406                         CHECK_STACK_OVF (1);
8407                         EMIT_NEW_PCONST (cfg, ins, NULL);
8408                         ins->type = STACK_OBJ;
8409                         ++ip;
8410                         *sp++ = ins;
8411                         break;
8412                 case CEE_LDC_I4_M1:
8413                         CHECK_STACK_OVF (1);
8414                         EMIT_NEW_ICONST (cfg, ins, -1);
8415                         ++ip;
8416                         *sp++ = ins;
8417                         break;
8418                 case CEE_LDC_I4_0:
8419                 case CEE_LDC_I4_1:
8420                 case CEE_LDC_I4_2:
8421                 case CEE_LDC_I4_3:
8422                 case CEE_LDC_I4_4:
8423                 case CEE_LDC_I4_5:
8424                 case CEE_LDC_I4_6:
8425                 case CEE_LDC_I4_7:
8426                 case CEE_LDC_I4_8:
8427                         CHECK_STACK_OVF (1);
8428                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
8429                         ++ip;
8430                         *sp++ = ins;
8431                         break;
8432                 case CEE_LDC_I4_S:
8433                         CHECK_OPSIZE (2);
8434                         CHECK_STACK_OVF (1);
8435                         ++ip;
8436                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
8437                         ++ip;
8438                         *sp++ = ins;
8439                         break;
8440                 case CEE_LDC_I4:
8441                         CHECK_OPSIZE (5);
8442                         CHECK_STACK_OVF (1);
8443                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
8444                         ip += 5;
8445                         *sp++ = ins;
8446                         break;
8447                 case CEE_LDC_I8:
8448                         CHECK_OPSIZE (9);
8449                         CHECK_STACK_OVF (1);
8450                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
8451                         ins->type = STACK_I8;
8452                         ins->dreg = alloc_dreg (cfg, STACK_I8);
8453                         ++ip;
8454                         ins->inst_l = (gint64)read64 (ip);
8455                         MONO_ADD_INS (cfg->cbb, ins);
8456                         ip += 8;
8457                         *sp++ = ins;
8458                         break;
8459                 case CEE_LDC_R4: {
8460                         float *f;
8461                         gboolean use_aotconst = FALSE;
8462
8463 #ifdef TARGET_POWERPC
8464                         /* FIXME: Clean this up */
8465                         if (cfg->compile_aot)
8466                                 use_aotconst = TRUE;
8467 #endif
8468
8469                         /* FIXME: we should really allocate this only late in the compilation process */
8470                         f = mono_domain_alloc (cfg->domain, sizeof (float));
8471                         CHECK_OPSIZE (5);
8472                         CHECK_STACK_OVF (1);
8473
8474                         if (use_aotconst) {
8475                                 MonoInst *cons;
8476                                 int dreg;
8477
8478                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
8479
8480                                 dreg = alloc_freg (cfg);
8481                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
8482                                 ins->type = cfg->r4_stack_type;
8483                         } else {
8484                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
8485                                 ins->type = cfg->r4_stack_type;
8486                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8487                                 ins->inst_p0 = f;
8488                                 MONO_ADD_INS (cfg->cbb, ins);
8489                         }
8490                         ++ip;
8491                         readr4 (ip, f);
8492                         ip += 4;
8493                         *sp++ = ins;                    
8494                         break;
8495                 }
8496                 case CEE_LDC_R8: {
8497                         double *d;
8498                         gboolean use_aotconst = FALSE;
8499
8500 #ifdef TARGET_POWERPC
8501                         /* FIXME: Clean this up */
8502                         if (cfg->compile_aot)
8503                                 use_aotconst = TRUE;
8504 #endif
8505
8506                         /* FIXME: we should really allocate this only late in the compilation process */
8507                         d = mono_domain_alloc (cfg->domain, sizeof (double));
8508                         CHECK_OPSIZE (9);
8509                         CHECK_STACK_OVF (1);
8510
8511                         if (use_aotconst) {
8512                                 MonoInst *cons;
8513                                 int dreg;
8514
8515                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
8516
8517                                 dreg = alloc_freg (cfg);
8518                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
8519                                 ins->type = STACK_R8;
8520                         } else {
8521                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
8522                                 ins->type = STACK_R8;
8523                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8524                                 ins->inst_p0 = d;
8525                                 MONO_ADD_INS (cfg->cbb, ins);
8526                         }
8527                         ++ip;
8528                         readr8 (ip, d);
8529                         ip += 8;
8530                         *sp++ = ins;
8531                         break;
8532                 }
8533                 case CEE_DUP: {
8534                         MonoInst *temp, *store;
8535                         CHECK_STACK (1);
8536                         CHECK_STACK_OVF (1);
8537                         sp--;
8538                         ins = *sp;
8539
8540                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
8541                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
8542
8543                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8544                         *sp++ = ins;
8545
8546                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8547                         *sp++ = ins;
8548
8549                         ++ip;
8550                         inline_costs += 2;
8551                         break;
8552                 }
8553                 case CEE_POP:
8554                         CHECK_STACK (1);
8555                         ip++;
8556                         --sp;
8557
8558 #ifdef TARGET_X86
8559                         if (sp [0]->type == STACK_R8)
8560                                 /* we need to pop the value from the x86 FP stack */
8561                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
8562 #endif
8563                         break;
8564                 case CEE_JMP: {
8565                         MonoCallInst *call;
8566
8567                         INLINE_FAILURE ("jmp");
8568                         GSHAREDVT_FAILURE (*ip);
8569
8570                         CHECK_OPSIZE (5);
8571                         if (stack_start != sp)
8572                                 UNVERIFIED;
8573                         token = read32 (ip + 1);
8574                         /* FIXME: check the signature matches */
8575                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8576
8577                         if (!cmethod || mono_loader_get_last_error ())
8578                                 LOAD_ERROR;
8579  
8580                         if (cfg->gshared && mono_method_check_context_used (cmethod))
8581                                 GENERIC_SHARING_FAILURE (CEE_JMP);
8582
8583                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
8584
8585                         if (ARCH_HAVE_OP_TAIL_CALL) {
8586                                 MonoMethodSignature *fsig = mono_method_signature (cmethod);
8587                                 int i, n;
8588
8589                                 /* Handle tail calls similarly to calls */
8590                                 n = fsig->param_count + fsig->hasthis;
8591
8592                                 DISABLE_AOT (cfg);
8593
8594                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
8595                                 call->method = cmethod;
8596                                 call->tail_call = TRUE;
8597                                 call->signature = mono_method_signature (cmethod);
8598                                 call->args = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
8599                                 call->inst.inst_p0 = cmethod;
8600                                 for (i = 0; i < n; ++i)
8601                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
8602
8603                                 mono_arch_emit_call (cfg, call);
8604                                 cfg->param_area = MAX(cfg->param_area, call->stack_usage);
8605                                 MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
8606                         } else {
8607                                 for (i = 0; i < num_args; ++i)
8608                                         /* Prevent arguments from being optimized away */
8609                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
8610
8611                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
8612                                 ins = (MonoInst*)call;
8613                                 ins->inst_p0 = cmethod;
8614                                 MONO_ADD_INS (cfg->cbb, ins);
8615                         }
8616
8617                         ip += 5;
8618                         start_new_bblock = 1;
8619                         break;
8620                 }
8621                 case CEE_CALLI: {
8622                         MonoInst *addr;
8623                         MonoMethodSignature *fsig;
8624
8625                         CHECK_OPSIZE (5);
8626                         token = read32 (ip + 1);
8627
8628                         ins = NULL;
8629
8630                         //GSHAREDVT_FAILURE (*ip);
8631                         cmethod = NULL;
8632                         CHECK_STACK (1);
8633                         --sp;
8634                         addr = *sp;
8635                         fsig = mini_get_signature (method, token, generic_context);
8636
8637                         if (method->dynamic && fsig->pinvoke) {
8638                                 MonoInst *args [3];
8639
8640                                 /*
8641                                  * This is a call through a function pointer using a pinvoke
8642                                  * signature. Have to create a wrapper and call that instead.
8643                                  * FIXME: This is very slow, need to create a wrapper at JIT time
8644                                  * instead based on the signature.
8645                                  */
8646                                 EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
8647                                 EMIT_NEW_PCONST (cfg, args [1], fsig);
8648                                 args [2] = addr;
8649                                 addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
8650                         }
8651
8652                         n = fsig->param_count + fsig->hasthis;
8653
8654                         CHECK_STACK (n);
8655
8656                         //g_assert (!virtual || fsig->hasthis);
8657
8658                         sp -= n;
8659
8660                         inline_costs += 10 * num_calls++;
8661
8662                         /*
8663                          * Making generic calls out of gsharedvt methods.
8664                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
8665                          * patching gshared method addresses into a gsharedvt method.
8666                          */
8667                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
8668                                 /*
8669                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
8670                                  */
8671                                 MonoInst *callee = addr;
8672
8673                                 if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
8674                                         /* Not tested */
8675                                         GSHAREDVT_FAILURE (*ip);
8676
8677                                 addr = emit_get_rgctx_sig (cfg, context_used,
8678                                                                                           fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
8679                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
8680                                 goto calli_end;
8681                         }
8682
8683                         /* Prevent inlining of methods with indirect calls */
8684                         INLINE_FAILURE ("indirect call");
8685
8686                         if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
8687                                 int info_type;
8688                                 gpointer info_data;
8689
8690                                 /*
8691                                  * Instead of emitting an indirect call, emit a direct call
8692                                  * with the contents of the aotconst as the patch info.
8693                                  */
8694                                 if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
8695                                         info_type = addr->inst_c1;
8696                                         info_data = addr->inst_p0;
8697                                 } else {
8698                                         info_type = addr->inst_right->inst_c1;
8699                                         info_data = addr->inst_right->inst_left;
8700                                 }
8701
8702                                 if (info_type == MONO_PATCH_INFO_ICALL_ADDR || info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
8703                                         ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
8704                                         NULLIFY_INS (addr);
8705                                         goto calli_end;
8706                                 }
8707                         }
8708                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8709
8710                         calli_end:
8711
8712                         /* End of call, INS should contain the result of the call, if any */
8713
8714                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8715                                 g_assert (ins);
8716                                 *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
8717                         }
8718
8719                         CHECK_CFG_EXCEPTION;
8720
8721                         ip += 5;
8722                         ins_flag = 0;
8723                         constrained_class = NULL;
8724                         break;
8725                 }
8726                 case CEE_CALL:
8727                 case CEE_CALLVIRT: {
8728                         MonoInst *addr = NULL;
8729                         MonoMethodSignature *fsig = NULL;
8730                         int array_rank = 0;
8731                         int virtual = *ip == CEE_CALLVIRT;
8732                         gboolean pass_imt_from_rgctx = FALSE;
8733                         MonoInst *imt_arg = NULL;
8734                         MonoInst *keep_this_alive = NULL;
8735                         gboolean pass_vtable = FALSE;
8736                         gboolean pass_mrgctx = FALSE;
8737                         MonoInst *vtable_arg = NULL;
8738                         gboolean check_this = FALSE;
8739                         gboolean supported_tail_call = FALSE;
8740                         gboolean tail_call = FALSE;
8741                         gboolean need_seq_point = FALSE;
8742                         guint32 call_opcode = *ip;
8743                         gboolean emit_widen = TRUE;
8744                         gboolean push_res = TRUE;
8745                         gboolean skip_ret = FALSE;
8746                         gboolean delegate_invoke = FALSE;
8747                         gboolean direct_icall = FALSE;
8748                         gboolean constrained_partial_call = FALSE;
8749                         MonoMethod *cil_method;
8750
8751                         CHECK_OPSIZE (5);
8752                         token = read32 (ip + 1);
8753
8754                         ins = NULL;
8755
8756                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8757                         cil_method = cmethod;
8758                                 
8759                         if (constrained_class) {
8760                                 if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
8761                                         if (!mini_is_gsharedvt_klass (constrained_class)) {
8762                                                 g_assert (!cmethod->klass->valuetype);
8763                                                 if (!mini_type_is_reference (&constrained_class->byval_arg))
8764                                                         constrained_partial_call = TRUE;
8765                                         }
8766                                 }
8767
8768                                 if (method->wrapper_type != MONO_WRAPPER_NONE) {
8769                                         if (cfg->verbose_level > 2)
8770                                                 printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_class));
8771                                         if (!((constrained_class->byval_arg.type == MONO_TYPE_VAR ||
8772                                                    constrained_class->byval_arg.type == MONO_TYPE_MVAR) &&
8773                                                   cfg->gshared)) {
8774                                                 cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_class, generic_context, &cfg->error);
8775                                                 CHECK_CFG_ERROR;
8776                                         }
8777                                 } else {
8778                                         if (cfg->verbose_level > 2)
8779                                                 printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_class));
8780
8781                                         if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
8782                                                 /* 
8783                                                  * This is needed since get_method_constrained can't find 
8784                                                  * the method in klass representing a type var.
8785                                                  * The type var is guaranteed to be a reference type in this
8786                                                  * case.
8787                                                  */
8788                                                 if (!mini_is_gsharedvt_klass (constrained_class))
8789                                                         g_assert (!cmethod->klass->valuetype);
8790                                         } else {
8791                                                 cmethod = mono_get_method_constrained_checked (image, token, constrained_class, generic_context, &cil_method, &cfg->error);
8792                                                 CHECK_CFG_ERROR;
8793                                         }
8794                                 }
8795                         }
8796                                         
8797                         if (!cmethod || mono_loader_get_last_error ())
8798                                 LOAD_ERROR;
8799                         if (!dont_verify && !cfg->skip_visibility) {
8800                                 MonoMethod *target_method = cil_method;
8801                                 if (method->is_inflated) {
8802                                         target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context));
8803                                 }
8804                                 if (!mono_method_can_access_method (method_definition, target_method) &&
8805                                         !mono_method_can_access_method (method, cil_method))
8806                                         METHOD_ACCESS_FAILURE (method, cil_method);
8807                         }
8808
8809                         if (mono_security_core_clr_enabled ())
8810                                 ensure_method_is_allowed_to_call_method (cfg, method, cil_method);
8811
8812                         if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
8813                                 /* MS.NET seems to silently convert this to a callvirt */
8814                                 virtual = 1;
8815
8816                         {
8817                                 /*
8818                                  * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
8819                                  * converts to a callvirt.
8820                                  *
8821                                  * tests/bug-515884.il is an example of this behavior
8822                                  */
8823                                 const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
8824                                 const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
8825                                 if (!virtual && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
8826                                         virtual = 1;
8827                         }
8828
8829                         if (!cmethod->klass->inited)
8830                                 if (!mono_class_init (cmethod->klass))
8831                                         TYPE_LOAD_ERROR (cmethod->klass);
8832
8833                         fsig = mono_method_signature (cmethod);
8834                         if (!fsig)
8835                                 LOAD_ERROR;
8836                         if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
8837                                 mini_class_is_system_array (cmethod->klass)) {
8838                                 array_rank = cmethod->klass->rank;
8839                         } else if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && icall_is_direct_callable (cfg, cmethod)) {
8840                                 direct_icall = TRUE;
8841                         } else if (fsig->pinvoke) {
8842                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
8843                                 fsig = mono_method_signature (wrapper);
8844                         } else if (constrained_class) {
8845                         } else {
8846                                 fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
8847                                 CHECK_CFG_ERROR;
8848                         }
8849
8850                         mono_save_token_info (cfg, image, token, cil_method);
8851
8852                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip + 5 - header->code)))
8853                                 need_seq_point = TRUE;
8854
8855                         /* Don't support calls made using type arguments for now */
8856                         /*
8857                           if (cfg->gsharedvt) {
8858                           if (mini_is_gsharedvt_signature (fsig))
8859                           GSHAREDVT_FAILURE (*ip);
8860                           }
8861                         */
8862
8863                         if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
8864                                 g_assert_not_reached ();
8865
8866                         n = fsig->param_count + fsig->hasthis;
8867
8868                         if (!cfg->gshared && cmethod->klass->generic_container)
8869                                 UNVERIFIED;
8870
8871                         if (!cfg->gshared)
8872                                 g_assert (!mono_method_check_context_used (cmethod));
8873
8874                         CHECK_STACK (n);
8875
8876                         //g_assert (!virtual || fsig->hasthis);
8877
8878                         sp -= n;
8879
8880                         if (constrained_class) {
8881                                 if (mini_is_gsharedvt_klass (constrained_class)) {
8882                                         if ((cmethod->klass != mono_defaults.object_class) && constrained_class->valuetype && cmethod->klass->valuetype) {
8883                                                 /* The 'Own method' case below */
8884                                         } else if (cmethod->klass->image != mono_defaults.corlib && !(cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !cmethod->klass->valuetype) {
8885                                                 /* 'The type parameter is instantiated as a reference type' case below. */
8886                                         } else {
8887                                                 ins = handle_constrained_gsharedvt_call (cfg, cmethod, fsig, sp, constrained_class, &emit_widen);
8888                                                 CHECK_CFG_EXCEPTION;
8889                                                 g_assert (ins);
8890                                                 goto call_end;
8891                                         }
8892                                 }
8893
8894                                 /*
8895                                  * We have the `constrained.' prefix opcode.
8896                                  */
8897                                 if (constrained_partial_call) {
8898                                         gboolean need_box = TRUE;
8899
8900                                         /*
8901                                          * The receiver is a valuetype, but the exact type is not known at compile time. This means the
8902                                          * called method is not known at compile time either. The called method could end up being
8903                                          * one of the methods on the parent classes (object/valuetype/enum), in which case we need
8904                                          * to box the receiver.
8905                                          * A simple solution would be to box always and make a normal virtual call, but that would
8906                                          * be bad performance wise.
8907                                          */
8908                                         if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE && cmethod->klass->generic_class) {
8909                                                 /*
8910                                                  * The parent classes implement no generic interfaces, so the called method will be a vtype method, so no boxing neccessary.
8911                                                  */
8912                                                 need_box = FALSE;
8913                                         }
8914
8915                                         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)) {
8916                                                 /* The called method is not virtual, i.e. Object:GetType (), the receiver is a vtype, has to box */
8917                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8918                                                 ins->klass = constrained_class;
8919                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8920                                                 CHECK_CFG_EXCEPTION;
8921                                         } else if (need_box) {
8922                                                 MonoInst *box_type;
8923                                                 MonoBasicBlock *is_ref_bb, *end_bb;
8924                                                 MonoInst *nonbox_call;
8925
8926                                                 /*
8927                                                  * Determine at runtime whenever the called method is defined on object/valuetype/enum, and emit a boxing call
8928                                                  * if needed.
8929                                                  * FIXME: It is possible to inline the called method in a lot of cases, i.e. for T_INT,
8930                                                  * the no-box case goes to a method in Int32, while the box case goes to a method in Enum.
8931                                                  */
8932                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
8933
8934                                                 NEW_BBLOCK (cfg, is_ref_bb);
8935                                                 NEW_BBLOCK (cfg, end_bb);
8936
8937                                                 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);
8938                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, box_type->dreg, 1);
8939                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
8940
8941                                                 /* Non-ref case */
8942                                                 nonbox_call = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8943
8944                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
8945
8946                                                 /* Ref case */
8947                                                 MONO_START_BB (cfg, is_ref_bb);
8948                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8949                                                 ins->klass = constrained_class;
8950                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8951                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8952
8953                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
8954
8955                                                 MONO_START_BB (cfg, end_bb);
8956                                                 cfg->cbb = end_bb;
8957
8958                                                 nonbox_call->dreg = ins->dreg;
8959                                                 goto call_end;
8960                                         } else {
8961                                                 g_assert (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
8962                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
8963                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8964                                                 goto call_end;
8965                                         }
8966                                 } else if (constrained_class->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
8967                                         /*
8968                                          * The type parameter is instantiated as a valuetype,
8969                                          * but that type doesn't override the method we're
8970                                          * calling, so we need to box `this'.
8971                                          */
8972                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8973                                         ins->klass = constrained_class;
8974                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8975                                         CHECK_CFG_EXCEPTION;
8976                                 } else if (!constrained_class->valuetype) {
8977                                         int dreg = alloc_ireg_ref (cfg);
8978
8979                                         /*
8980                                          * The type parameter is instantiated as a reference
8981                                          * type.  We have a managed pointer on the stack, so
8982                                          * we need to dereference it here.
8983                                          */
8984                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
8985                                         ins->type = STACK_OBJ;
8986                                         sp [0] = ins;
8987                                 } else {
8988                                         if (cmethod->klass->valuetype) {
8989                                                 /* Own method */
8990                                         } else {
8991                                                 /* Interface method */
8992                                                 int ioffset, slot;
8993
8994                                                 mono_class_setup_vtable (constrained_class);
8995                                                 CHECK_TYPELOAD (constrained_class);
8996                                                 ioffset = mono_class_interface_offset (constrained_class, cmethod->klass);
8997                                                 if (ioffset == -1)
8998                                                         TYPE_LOAD_ERROR (constrained_class);
8999                                                 slot = mono_method_get_vtable_slot (cmethod);
9000                                                 if (slot == -1)
9001                                                         TYPE_LOAD_ERROR (cmethod->klass);
9002                                                 cmethod = constrained_class->vtable [ioffset + slot];
9003
9004                                                 if (cmethod->klass == mono_defaults.enum_class) {
9005                                                         /* Enum implements some interfaces, so treat this as the first case */
9006                                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9007                                                         ins->klass = constrained_class;
9008                                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9009                                                         CHECK_CFG_EXCEPTION;
9010                                                 }
9011                                         }
9012                                         virtual = 0;
9013                                 }
9014                                 constrained_class = NULL;
9015                         }
9016
9017                         if (check_call_signature (cfg, fsig, sp))
9018                                 UNVERIFIED;
9019
9020                         if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
9021                                 delegate_invoke = TRUE;
9022
9023                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
9024                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9025                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9026                                         emit_widen = FALSE;
9027                                 }
9028
9029                                 goto call_end;
9030                         }
9031
9032                         /* 
9033                          * If the callee is a shared method, then its static cctor
9034                          * might not get called after the call was patched.
9035                          */
9036                         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)) {
9037                                 emit_class_init (cfg, cmethod->klass);
9038                                 CHECK_TYPELOAD (cmethod->klass);
9039                         }
9040
9041                         check_method_sharing (cfg, cmethod, &pass_vtable, &pass_mrgctx);
9042
9043                         if (cfg->gshared) {
9044                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
9045
9046                                 context_used = mini_method_check_context_used (cfg, cmethod);
9047
9048                                 if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9049                                         /* Generic method interface
9050                                            calls are resolved via a
9051                                            helper function and don't
9052                                            need an imt. */
9053                                         if (!cmethod_context || !cmethod_context->method_inst)
9054                                                 pass_imt_from_rgctx = TRUE;
9055                                 }
9056
9057                                 /*
9058                                  * If a shared method calls another
9059                                  * shared method then the caller must
9060                                  * have a generic sharing context
9061                                  * because the magic trampoline
9062                                  * requires it.  FIXME: We shouldn't
9063                                  * have to force the vtable/mrgctx
9064                                  * variable here.  Instead there
9065                                  * should be a flag in the cfg to
9066                                  * request a generic sharing context.
9067                                  */
9068                                 if (context_used &&
9069                                                 ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
9070                                         mono_get_vtable_var (cfg);
9071                         }
9072
9073                         if (pass_vtable) {
9074                                 if (context_used) {
9075                                         vtable_arg = emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
9076                                 } else {
9077                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
9078
9079                                         CHECK_TYPELOAD (cmethod->klass);
9080                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
9081                                 }
9082                         }
9083
9084                         if (pass_mrgctx) {
9085                                 g_assert (!vtable_arg);
9086
9087                                 if (!cfg->compile_aot) {
9088                                         /* 
9089                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
9090                                          * for type load errors before.
9091                                          */
9092                                         mono_class_setup_vtable (cmethod->klass);
9093                                         CHECK_TYPELOAD (cmethod->klass);
9094                                 }
9095
9096                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
9097
9098                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
9099                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
9100                                          MONO_METHOD_IS_FINAL (cmethod)) &&
9101                                         !mono_class_is_marshalbyref (cmethod->klass)) {
9102                                         if (virtual)
9103                                                 check_this = TRUE;
9104                                         virtual = 0;
9105                                 }
9106                         }
9107
9108                         if (pass_imt_from_rgctx) {
9109                                 g_assert (!pass_vtable);
9110
9111                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9112                                         cmethod, MONO_RGCTX_INFO_METHOD);
9113                         }
9114
9115                         if (check_this)
9116                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9117
9118                         /* Calling virtual generic methods */
9119                         if (virtual && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) && 
9120                             !(MONO_METHOD_IS_FINAL (cmethod) && 
9121                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
9122                             fsig->generic_param_count && 
9123                                 !(cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))) {
9124                                 MonoInst *this_temp, *this_arg_temp, *store;
9125                                 MonoInst *iargs [4];
9126                                 gboolean use_imt = FALSE;
9127
9128                                 g_assert (fsig->is_inflated);
9129
9130                                 /* Prevent inlining of methods that contain indirect calls */
9131                                 INLINE_FAILURE ("virtual generic call");
9132
9133                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
9134                                         GSHAREDVT_FAILURE (*ip);
9135
9136 #if MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK && defined(MONO_ARCH_GSHARED_SUPPORTED)
9137                                 if (cmethod->wrapper_type == MONO_WRAPPER_NONE)
9138                                         use_imt = TRUE;
9139 #endif
9140
9141                                 if (use_imt) {
9142                                         g_assert (!imt_arg);
9143                                         if (!context_used)
9144                                                 g_assert (cmethod->is_inflated);
9145                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
9146                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
9147                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, sp [0], imt_arg, NULL);
9148                                 } else {
9149                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
9150                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
9151                                         MONO_ADD_INS (cfg->cbb, store);
9152
9153                                         /* FIXME: This should be a managed pointer */
9154                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
9155
9156                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
9157                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
9158                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
9159                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
9160                                         addr = mono_emit_jit_icall (cfg,
9161                                                                                                 mono_helper_compile_generic_method, iargs);
9162
9163                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
9164
9165                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9166                                 }
9167
9168                                 goto call_end;
9169                         }
9170
9171                         /*
9172                          * Implement a workaround for the inherent races involved in locking:
9173                          * Monitor.Enter ()
9174                          * try {
9175                          * } finally {
9176                          *    Monitor.Exit ()
9177                          * }
9178                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
9179                          * try block, the Exit () won't be executed, see:
9180                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
9181                          * To work around this, we extend such try blocks to include the last x bytes
9182                          * of the Monitor.Enter () call.
9183                          */
9184                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
9185                                 MonoBasicBlock *tbb;
9186
9187                                 GET_BBLOCK (cfg, tbb, ip + 5);
9188                                 /* 
9189                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
9190                                  * from Monitor.Enter like ArgumentNullException.
9191                                  */
9192                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
9193                                         /* Mark this bblock as needing to be extended */
9194                                         tbb->extend_try_block = TRUE;
9195                                 }
9196                         }
9197
9198                         /* Conversion to a JIT intrinsic */
9199                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
9200                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9201                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9202                                         emit_widen = FALSE;
9203                                 }
9204                                 goto call_end;
9205                         }
9206
9207                         /* Inlining */
9208                         if ((cfg->opt & MONO_OPT_INLINE) &&
9209                                 (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
9210                             mono_method_check_inlining (cfg, cmethod)) {
9211                                 int costs;
9212                                 gboolean always = FALSE;
9213
9214                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
9215                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
9216                                         /* Prevent inlining of methods that call wrappers */
9217                                         INLINE_FAILURE ("wrapper call");
9218                                         cmethod = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
9219                                         always = TRUE;
9220                                 }
9221
9222                                 costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, always);
9223                                 if (costs) {
9224                                         cfg->real_offset += 5;
9225
9226                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9227                                                 /* *sp is already set by inline_method */
9228                                                 sp++;
9229                                                 push_res = FALSE;
9230                                         }
9231
9232                                         inline_costs += costs;
9233
9234                                         goto call_end;
9235                                 }
9236                         }
9237
9238                         /* Tail recursion elimination */
9239                         if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
9240                                 gboolean has_vtargs = FALSE;
9241                                 int i;
9242
9243                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9244                                 INLINE_FAILURE ("tail call");
9245
9246                                 /* keep it simple */
9247                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
9248                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
9249                                                 has_vtargs = TRUE;
9250                                 }
9251
9252                                 if (!has_vtargs) {
9253                                         for (i = 0; i < n; ++i)
9254                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9255                                         MONO_INST_NEW (cfg, ins, OP_BR);
9256                                         MONO_ADD_INS (cfg->cbb, ins);
9257                                         tblock = start_bblock->out_bb [0];
9258                                         link_bblock (cfg, cfg->cbb, tblock);
9259                                         ins->inst_target_bb = tblock;
9260                                         start_new_bblock = 1;
9261
9262                                         /* skip the CEE_RET, too */
9263                                         if (ip_in_bb (cfg, cfg->cbb, ip + 5))
9264                                                 skip_ret = TRUE;
9265                                         push_res = FALSE;
9266                                         goto call_end;
9267                                 }
9268                         }
9269
9270                         inline_costs += 10 * num_calls++;
9271
9272                         /*
9273                          * Making generic calls out of gsharedvt methods.
9274                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9275                          * patching gshared method addresses into a gsharedvt method.
9276                          */
9277                         if (cfg->gsharedvt && (mini_is_gsharedvt_signature (fsig) || cmethod->is_inflated || cmethod->klass->generic_class) &&
9278                                 !(cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY)) {
9279                                 MonoRgctxInfoType info_type;
9280
9281                                 if (virtual) {
9282                                         //if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
9283                                                 //GSHAREDVT_FAILURE (*ip);
9284                                         // disable for possible remoting calls
9285                                         if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
9286                                                 GSHAREDVT_FAILURE (*ip);
9287                                         if (fsig->generic_param_count) {
9288                                                 /* virtual generic call */
9289                                                 g_assert (!imt_arg);
9290                                                 /* Same as the virtual generic case above */
9291                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9292                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9293                                                 /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
9294                                                 vtable_arg = NULL;
9295                                         } else if ((cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !imt_arg) {
9296                                                 /* This can happen when we call a fully instantiated iface method */
9297                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9298                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9299                                                 vtable_arg = NULL;
9300                                         }
9301                                 }
9302
9303                                 if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
9304                                         keep_this_alive = sp [0];
9305
9306                                 if (virtual && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
9307                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
9308                                 else
9309                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
9310                                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
9311
9312                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9313                                 goto call_end;
9314                         }
9315
9316                         /* Generic sharing */
9317
9318                         /*
9319                          * Use this if the callee is gsharedvt sharable too, since
9320                          * at runtime we might find an instantiation so the call cannot
9321                          * be patched (the 'no_patch' code path in mini-trampolines.c).
9322                          */
9323                         if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
9324                                 (!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
9325                                  !mono_class_generic_sharing_enabled (cmethod->klass)) &&
9326                                 (!virtual || MONO_METHOD_IS_FINAL (cmethod) ||
9327                                  !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
9328                                 INLINE_FAILURE ("gshared");
9329
9330                                 g_assert (cfg->gshared && cmethod);
9331                                 g_assert (!addr);
9332
9333                                 /*
9334                                  * We are compiling a call to a
9335                                  * generic method from shared code,
9336                                  * which means that we have to look up
9337                                  * the method in the rgctx and do an
9338                                  * indirect call.
9339                                  */
9340                                 if (fsig->hasthis)
9341                                         MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9342
9343                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9344                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9345                                 goto call_end;
9346                         }
9347
9348                         /* Direct calls to icalls */
9349                         if (direct_icall) {
9350                                 MonoMethod *wrapper;
9351                                 int costs;
9352
9353                                 /* Inline the wrapper */
9354                                 wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
9355
9356                                 costs = inline_method (cfg, wrapper, fsig, sp, ip, cfg->real_offset, TRUE);
9357                                 g_assert (costs > 0);
9358                                 cfg->real_offset += 5;
9359
9360                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9361                                         /* *sp is already set by inline_method */
9362                                         sp++;
9363                                         push_res = FALSE;
9364                                 }
9365
9366                                 inline_costs += costs;
9367
9368                                 goto call_end;
9369                         }
9370                                         
9371                         /* Array methods */
9372                         if (array_rank) {
9373                                 MonoInst *addr;
9374
9375                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
9376                                         MonoInst *val = sp [fsig->param_count];
9377
9378                                         if (val->type == STACK_OBJ) {
9379                                                 MonoInst *iargs [2];
9380
9381                                                 iargs [0] = sp [0];
9382                                                 iargs [1] = val;
9383                                                 
9384                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
9385                                         }
9386                                         
9387                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
9388                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
9389                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !(val->opcode == OP_PCONST && val->inst_c0 == 0))
9390                                                 emit_write_barrier (cfg, addr, val);
9391                                         if (cfg->gen_write_barriers && mini_is_gsharedvt_klass (cmethod->klass))
9392                                                 GSHAREDVT_FAILURE (*ip);
9393                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
9394                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9395
9396                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
9397                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
9398                                         if (!cmethod->klass->element_class->valuetype && !readonly)
9399                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
9400                                         CHECK_TYPELOAD (cmethod->klass);
9401                                         
9402                                         readonly = FALSE;
9403                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9404                                         ins = addr;
9405                                 } else {
9406                                         g_assert_not_reached ();
9407                                 }
9408
9409                                 emit_widen = FALSE;
9410                                 goto call_end;
9411                         }
9412
9413                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL);
9414                         if (ins)
9415                                 goto call_end;
9416
9417                         /* Tail prefix / tail call optimization */
9418
9419                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
9420                         /* FIXME: runtime generic context pointer for jumps? */
9421                         /* FIXME: handle this for generic sharing eventually */
9422                         if ((ins_flag & MONO_INST_TAILCALL) &&
9423                                 !vtable_arg && !cfg->gshared && is_supported_tail_call (cfg, method, cmethod, fsig, call_opcode))
9424                                 supported_tail_call = TRUE;
9425
9426                         if (supported_tail_call) {
9427                                 MonoCallInst *call;
9428
9429                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9430                                 INLINE_FAILURE ("tail call");
9431
9432                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
9433
9434                                 if (ARCH_HAVE_OP_TAIL_CALL) {
9435                                         /* Handle tail calls similarly to normal calls */
9436                                         tail_call = TRUE;
9437                                 } else {
9438                                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
9439
9440                                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9441                                         call->tail_call = TRUE;
9442                                         call->method = cmethod;
9443                                         call->signature = mono_method_signature (cmethod);
9444
9445                                         /*
9446                                          * We implement tail calls by storing the actual arguments into the 
9447                                          * argument variables, then emitting a CEE_JMP.
9448                                          */
9449                                         for (i = 0; i < n; ++i) {
9450                                                 /* Prevent argument from being register allocated */
9451                                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
9452                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9453                                         }
9454                                         ins = (MonoInst*)call;
9455                                         ins->inst_p0 = cmethod;
9456                                         ins->inst_p1 = arg_array [0];
9457                                         MONO_ADD_INS (cfg->cbb, ins);
9458                                         link_bblock (cfg, cfg->cbb, end_bblock);
9459                                         start_new_bblock = 1;
9460
9461                                         // FIXME: Eliminate unreachable epilogs
9462
9463                                         /*
9464                                          * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9465                                          * only reachable from this call.
9466                                          */
9467                                         GET_BBLOCK (cfg, tblock, ip + 5);
9468                                         if (tblock == cfg->cbb || tblock->in_count == 0)
9469                                                 skip_ret = TRUE;
9470                                         push_res = FALSE;
9471
9472                                         goto call_end;
9473                                 }
9474                         }
9475
9476                         /* 
9477                          * Synchronized wrappers.
9478                          * Its hard to determine where to replace a method with its synchronized
9479                          * wrapper without causing an infinite recursion. The current solution is
9480                          * to add the synchronized wrapper in the trampolines, and to
9481                          * change the called method to a dummy wrapper, and resolve that wrapper
9482                          * to the real method in mono_jit_compile_method ().
9483                          */
9484                         if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
9485                                 MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
9486                                 if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
9487                                         cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
9488                         }
9489
9490                         /* Common call */
9491                         INLINE_FAILURE ("call");
9492                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual ? sp [0] : NULL,
9493                                                                                           imt_arg, vtable_arg);
9494
9495                         if (tail_call) {
9496                                 link_bblock (cfg, cfg->cbb, end_bblock);
9497                                 start_new_bblock = 1;
9498
9499                                 // FIXME: Eliminate unreachable epilogs
9500
9501                                 /*
9502                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9503                                  * only reachable from this call.
9504                                  */
9505                                 GET_BBLOCK (cfg, tblock, ip + 5);
9506                                 if (tblock == cfg->cbb || tblock->in_count == 0)
9507                                         skip_ret = TRUE;
9508                                 push_res = FALSE;
9509                         }
9510
9511                         call_end:
9512
9513                         /* End of call, INS should contain the result of the call, if any */
9514
9515                         if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
9516                                 g_assert (ins);
9517                                 if (emit_widen)
9518                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
9519                                 else
9520                                         *sp++ = ins;
9521                         }
9522
9523                         if (keep_this_alive) {
9524                                 MonoInst *dummy_use;
9525
9526                                 /* See mono_emit_method_call_full () */
9527                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
9528                         }
9529
9530                         CHECK_CFG_EXCEPTION;
9531
9532                         ip += 5;
9533                         if (skip_ret) {
9534                                 g_assert (*ip == CEE_RET);
9535                                 ip += 1;
9536                         }
9537                         ins_flag = 0;
9538                         constrained_class = NULL;
9539                         if (need_seq_point)
9540                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
9541                         break;
9542                 }
9543                 case CEE_RET:
9544                         if (cfg->method != method) {
9545                                 /* return from inlined method */
9546                                 /* 
9547                                  * If in_count == 0, that means the ret is unreachable due to
9548                                  * being preceeded by a throw. In that case, inline_method () will
9549                                  * handle setting the return value 
9550                                  * (test case: test_0_inline_throw ()).
9551                                  */
9552                                 if (return_var && cfg->cbb->in_count) {
9553                                         MonoType *ret_type = mono_method_signature (method)->ret;
9554
9555                                         MonoInst *store;
9556                                         CHECK_STACK (1);
9557                                         --sp;
9558
9559                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9560                                                 UNVERIFIED;
9561
9562                                         //g_assert (returnvar != -1);
9563                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
9564                                         cfg->ret_var_set = TRUE;
9565                                 } 
9566                         } else {
9567                                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
9568
9569                                 if (cfg->lmf_var && cfg->cbb->in_count)
9570                                         emit_pop_lmf (cfg);
9571
9572                                 if (cfg->ret) {
9573                                         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (method)->ret);
9574
9575                                         if (seq_points && !sym_seq_points) {
9576                                                 /* 
9577                                                  * Place a seq point here too even through the IL stack is not
9578                                                  * empty, so a step over on
9579                                                  * call <FOO>
9580                                                  * ret
9581                                                  * will work correctly.
9582                                                  */
9583                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
9584                                                 MONO_ADD_INS (cfg->cbb, ins);
9585                                         }
9586
9587                                         g_assert (!return_var);
9588                                         CHECK_STACK (1);
9589                                         --sp;
9590
9591                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9592                                                 UNVERIFIED;
9593
9594                                         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
9595                                                 MonoInst *ret_addr;
9596
9597                                                 if (!cfg->vret_addr) {
9598                                                         MonoInst *ins;
9599
9600                                                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, (*sp));
9601                                                 } else {
9602                                                         EMIT_NEW_RETLOADA (cfg, ret_addr);
9603
9604                                                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, (*sp)->dreg);
9605                                                         ins->klass = mono_class_from_mono_type (ret_type);
9606                                                 }
9607                                         } else {
9608 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
9609                                                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
9610                                                         MonoInst *iargs [1];
9611                                                         MonoInst *conv;
9612
9613                                                         iargs [0] = *sp;
9614                                                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
9615                                                         mono_arch_emit_setret (cfg, method, conv);
9616                                                 } else {
9617                                                         mono_arch_emit_setret (cfg, method, *sp);
9618                                                 }
9619 #else
9620                                                 mono_arch_emit_setret (cfg, method, *sp);
9621 #endif
9622                                         }
9623                                 }
9624                         }
9625                         if (sp != stack_start)
9626                                 UNVERIFIED;
9627                         MONO_INST_NEW (cfg, ins, OP_BR);
9628                         ip++;
9629                         ins->inst_target_bb = end_bblock;
9630                         MONO_ADD_INS (cfg->cbb, ins);
9631                         link_bblock (cfg, cfg->cbb, end_bblock);
9632                         start_new_bblock = 1;
9633                         break;
9634                 case CEE_BR_S:
9635                         CHECK_OPSIZE (2);
9636                         MONO_INST_NEW (cfg, ins, OP_BR);
9637                         ip++;
9638                         target = ip + 1 + (signed char)(*ip);
9639                         ++ip;
9640                         GET_BBLOCK (cfg, tblock, target);
9641                         link_bblock (cfg, cfg->cbb, tblock);
9642                         ins->inst_target_bb = tblock;
9643                         if (sp != stack_start) {
9644                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9645                                 sp = stack_start;
9646                                 CHECK_UNVERIFIABLE (cfg);
9647                         }
9648                         MONO_ADD_INS (cfg->cbb, ins);
9649                         start_new_bblock = 1;
9650                         inline_costs += BRANCH_COST;
9651                         break;
9652                 case CEE_BEQ_S:
9653                 case CEE_BGE_S:
9654                 case CEE_BGT_S:
9655                 case CEE_BLE_S:
9656                 case CEE_BLT_S:
9657                 case CEE_BNE_UN_S:
9658                 case CEE_BGE_UN_S:
9659                 case CEE_BGT_UN_S:
9660                 case CEE_BLE_UN_S:
9661                 case CEE_BLT_UN_S:
9662                         CHECK_OPSIZE (2);
9663                         CHECK_STACK (2);
9664                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
9665                         ip++;
9666                         target = ip + 1 + *(signed char*)ip;
9667                         ip++;
9668
9669                         ADD_BINCOND (NULL);
9670
9671                         sp = stack_start;
9672                         inline_costs += BRANCH_COST;
9673                         break;
9674                 case CEE_BR:
9675                         CHECK_OPSIZE (5);
9676                         MONO_INST_NEW (cfg, ins, OP_BR);
9677                         ip++;
9678
9679                         target = ip + 4 + (gint32)read32(ip);
9680                         ip += 4;
9681                         GET_BBLOCK (cfg, tblock, target);
9682                         link_bblock (cfg, cfg->cbb, tblock);
9683                         ins->inst_target_bb = tblock;
9684                         if (sp != stack_start) {
9685                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9686                                 sp = stack_start;
9687                                 CHECK_UNVERIFIABLE (cfg);
9688                         }
9689
9690                         MONO_ADD_INS (cfg->cbb, ins);
9691
9692                         start_new_bblock = 1;
9693                         inline_costs += BRANCH_COST;
9694                         break;
9695                 case CEE_BRFALSE_S:
9696                 case CEE_BRTRUE_S:
9697                 case CEE_BRFALSE:
9698                 case CEE_BRTRUE: {
9699                         MonoInst *cmp;
9700                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
9701                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
9702                         guint32 opsize = is_short ? 1 : 4;
9703
9704                         CHECK_OPSIZE (opsize);
9705                         CHECK_STACK (1);
9706                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
9707                                 UNVERIFIED;
9708                         ip ++;
9709                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
9710                         ip += opsize;
9711
9712                         sp--;
9713
9714                         GET_BBLOCK (cfg, tblock, target);
9715                         link_bblock (cfg, cfg->cbb, tblock);
9716                         GET_BBLOCK (cfg, tblock, ip);
9717                         link_bblock (cfg, cfg->cbb, tblock);
9718
9719                         if (sp != stack_start) {
9720                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9721                                 CHECK_UNVERIFIABLE (cfg);
9722                         }
9723
9724                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
9725                         cmp->sreg1 = sp [0]->dreg;
9726                         type_from_op (cfg, cmp, sp [0], NULL);
9727                         CHECK_TYPE (cmp);
9728
9729 #if SIZEOF_REGISTER == 4
9730                         if (cmp->opcode == OP_LCOMPARE_IMM) {
9731                                 /* Convert it to OP_LCOMPARE */
9732                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
9733                                 ins->type = STACK_I8;
9734                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
9735                                 ins->inst_l = 0;
9736                                 MONO_ADD_INS (cfg->cbb, ins);
9737                                 cmp->opcode = OP_LCOMPARE;
9738                                 cmp->sreg2 = ins->dreg;
9739                         }
9740 #endif
9741                         MONO_ADD_INS (cfg->cbb, cmp);
9742
9743                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
9744                         type_from_op (cfg, ins, sp [0], NULL);
9745                         MONO_ADD_INS (cfg->cbb, ins);
9746                         ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
9747                         GET_BBLOCK (cfg, tblock, target);
9748                         ins->inst_true_bb = tblock;
9749                         GET_BBLOCK (cfg, tblock, ip);
9750                         ins->inst_false_bb = tblock;
9751                         start_new_bblock = 2;
9752
9753                         sp = stack_start;
9754                         inline_costs += BRANCH_COST;
9755                         break;
9756                 }
9757                 case CEE_BEQ:
9758                 case CEE_BGE:
9759                 case CEE_BGT:
9760                 case CEE_BLE:
9761                 case CEE_BLT:
9762                 case CEE_BNE_UN:
9763                 case CEE_BGE_UN:
9764                 case CEE_BGT_UN:
9765                 case CEE_BLE_UN:
9766                 case CEE_BLT_UN:
9767                         CHECK_OPSIZE (5);
9768                         CHECK_STACK (2);
9769                         MONO_INST_NEW (cfg, ins, *ip);
9770                         ip++;
9771                         target = ip + 4 + (gint32)read32(ip);
9772                         ip += 4;
9773
9774                         ADD_BINCOND (NULL);
9775
9776                         sp = stack_start;
9777                         inline_costs += BRANCH_COST;
9778                         break;
9779                 case CEE_SWITCH: {
9780                         MonoInst *src1;
9781                         MonoBasicBlock **targets;
9782                         MonoBasicBlock *default_bblock;
9783                         MonoJumpInfoBBTable *table;
9784                         int offset_reg = alloc_preg (cfg);
9785                         int target_reg = alloc_preg (cfg);
9786                         int table_reg = alloc_preg (cfg);
9787                         int sum_reg = alloc_preg (cfg);
9788                         gboolean use_op_switch;
9789
9790                         CHECK_OPSIZE (5);
9791                         CHECK_STACK (1);
9792                         n = read32 (ip + 1);
9793                         --sp;
9794                         src1 = sp [0];
9795                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
9796                                 UNVERIFIED;
9797
9798                         ip += 5;
9799                         CHECK_OPSIZE (n * sizeof (guint32));
9800                         target = ip + n * sizeof (guint32);
9801
9802                         GET_BBLOCK (cfg, default_bblock, target);
9803                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
9804
9805                         targets = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
9806                         for (i = 0; i < n; ++i) {
9807                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
9808                                 targets [i] = tblock;
9809                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
9810                                 ip += 4;
9811                         }
9812
9813                         if (sp != stack_start) {
9814                                 /* 
9815                                  * Link the current bb with the targets as well, so handle_stack_args
9816                                  * will set their in_stack correctly.
9817                                  */
9818                                 link_bblock (cfg, cfg->cbb, default_bblock);
9819                                 for (i = 0; i < n; ++i)
9820                                         link_bblock (cfg, cfg->cbb, targets [i]);
9821
9822                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9823                                 sp = stack_start;
9824                                 CHECK_UNVERIFIABLE (cfg);
9825                         }
9826
9827                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
9828                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
9829
9830                         for (i = 0; i < n; ++i)
9831                                 link_bblock (cfg, cfg->cbb, targets [i]);
9832
9833                         table = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
9834                         table->table = targets;
9835                         table->table_size = n;
9836
9837                         use_op_switch = FALSE;
9838 #ifdef TARGET_ARM
9839                         /* ARM implements SWITCH statements differently */
9840                         /* FIXME: Make it use the generic implementation */
9841                         if (!cfg->compile_aot)
9842                                 use_op_switch = TRUE;
9843 #endif
9844
9845                         if (COMPILE_LLVM (cfg))
9846                                 use_op_switch = TRUE;
9847
9848                         cfg->cbb->has_jump_table = 1;
9849
9850                         if (use_op_switch) {
9851                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
9852                                 ins->sreg1 = src1->dreg;
9853                                 ins->inst_p0 = table;
9854                                 ins->inst_many_bb = targets;
9855                                 ins->klass = GUINT_TO_POINTER (n);
9856                                 MONO_ADD_INS (cfg->cbb, ins);
9857                         } else {
9858                                 if (sizeof (gpointer) == 8)
9859                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
9860                                 else
9861                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
9862
9863 #if SIZEOF_REGISTER == 8
9864                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
9865                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
9866 #endif
9867
9868                                 if (cfg->compile_aot) {
9869                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
9870                                 } else {
9871                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
9872                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
9873                                         ins->inst_p0 = table;
9874                                         ins->dreg = table_reg;
9875                                         MONO_ADD_INS (cfg->cbb, ins);
9876                                 }
9877
9878                                 /* FIXME: Use load_memindex */
9879                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
9880                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
9881                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
9882                         }
9883                         start_new_bblock = 1;
9884                         inline_costs += (BRANCH_COST * 2);
9885                         break;
9886                 }
9887                 case CEE_LDIND_I1:
9888                 case CEE_LDIND_U1:
9889                 case CEE_LDIND_I2:
9890                 case CEE_LDIND_U2:
9891                 case CEE_LDIND_I4:
9892                 case CEE_LDIND_U4:
9893                 case CEE_LDIND_I8:
9894                 case CEE_LDIND_I:
9895                 case CEE_LDIND_R4:
9896                 case CEE_LDIND_R8:
9897                 case CEE_LDIND_REF:
9898                         CHECK_STACK (1);
9899                         --sp;
9900
9901                         switch (*ip) {
9902                         case CEE_LDIND_R4:
9903                         case CEE_LDIND_R8:
9904                                 dreg = alloc_freg (cfg);
9905                                 break;
9906                         case CEE_LDIND_I8:
9907                                 dreg = alloc_lreg (cfg);
9908                                 break;
9909                         case CEE_LDIND_REF:
9910                                 dreg = alloc_ireg_ref (cfg);
9911                                 break;
9912                         default:
9913                                 dreg = alloc_preg (cfg);
9914                         }
9915
9916                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
9917                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
9918                         if (*ip == CEE_LDIND_R4)
9919                                 ins->type = cfg->r4_stack_type;
9920                         ins->flags |= ins_flag;
9921                         MONO_ADD_INS (cfg->cbb, ins);
9922                         *sp++ = ins;
9923                         if (ins_flag & MONO_INST_VOLATILE) {
9924                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
9925                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
9926                         }
9927                         ins_flag = 0;
9928                         ++ip;
9929                         break;
9930                 case CEE_STIND_REF:
9931                 case CEE_STIND_I1:
9932                 case CEE_STIND_I2:
9933                 case CEE_STIND_I4:
9934                 case CEE_STIND_I8:
9935                 case CEE_STIND_R4:
9936                 case CEE_STIND_R8:
9937                 case CEE_STIND_I:
9938                         CHECK_STACK (2);
9939                         sp -= 2;
9940
9941                         if (ins_flag & MONO_INST_VOLATILE) {
9942                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
9943                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
9944                         }
9945
9946                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
9947                         ins->flags |= ins_flag;
9948                         ins_flag = 0;
9949
9950                         MONO_ADD_INS (cfg->cbb, ins);
9951
9952                         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)))
9953                                 emit_write_barrier (cfg, sp [0], sp [1]);
9954
9955                         inline_costs += 1;
9956                         ++ip;
9957                         break;
9958
9959                 case CEE_MUL:
9960                         CHECK_STACK (2);
9961
9962                         MONO_INST_NEW (cfg, ins, (*ip));
9963                         sp -= 2;
9964                         ins->sreg1 = sp [0]->dreg;
9965                         ins->sreg2 = sp [1]->dreg;
9966                         type_from_op (cfg, ins, sp [0], sp [1]);
9967                         CHECK_TYPE (ins);
9968                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
9969
9970                         /* Use the immediate opcodes if possible */
9971                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
9972                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
9973                                 if (imm_opcode != -1) {
9974                                         ins->opcode = imm_opcode;
9975                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
9976                                         ins->sreg2 = -1;
9977
9978                                         NULLIFY_INS (sp [1]);
9979                                 }
9980                         }
9981
9982                         MONO_ADD_INS ((cfg)->cbb, (ins));
9983
9984                         *sp++ = mono_decompose_opcode (cfg, ins);
9985                         ip++;
9986                         break;
9987                 case CEE_ADD:
9988                 case CEE_SUB:
9989                 case CEE_DIV:
9990                 case CEE_DIV_UN:
9991                 case CEE_REM:
9992                 case CEE_REM_UN:
9993                 case CEE_AND:
9994                 case CEE_OR:
9995                 case CEE_XOR:
9996                 case CEE_SHL:
9997                 case CEE_SHR:
9998                 case CEE_SHR_UN:
9999                         CHECK_STACK (2);
10000
10001                         MONO_INST_NEW (cfg, ins, (*ip));
10002                         sp -= 2;
10003                         ins->sreg1 = sp [0]->dreg;
10004                         ins->sreg2 = sp [1]->dreg;
10005                         type_from_op (cfg, ins, sp [0], sp [1]);
10006                         CHECK_TYPE (ins);
10007                         add_widen_op (cfg, ins, &sp [0], &sp [1]);
10008                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
10009
10010                         /* FIXME: Pass opcode to is_inst_imm */
10011
10012                         /* Use the immediate opcodes if possible */
10013                         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)) {
10014                                 int imm_opcode;
10015
10016                                 imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
10017 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
10018                                 /* Keep emulated opcodes which are optimized away later */
10019                                 if ((ins->opcode == OP_IREM_UN || ins->opcode == OP_IDIV_UN_IMM) && (cfg->opt & (MONO_OPT_CONSPROP | MONO_OPT_COPYPROP)) && sp [1]->opcode == OP_ICONST && mono_is_power_of_two (sp [1]->inst_c0) >= 0) {
10020                                         imm_opcode = mono_op_to_op_imm (ins->opcode);
10021                                 }
10022 #endif
10023                                 if (imm_opcode != -1) {
10024                                         ins->opcode = imm_opcode;
10025                                         if (sp [1]->opcode == OP_I8CONST) {
10026 #if SIZEOF_REGISTER == 8
10027                                                 ins->inst_imm = sp [1]->inst_l;
10028 #else
10029                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
10030                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
10031 #endif
10032                                         }
10033                                         else
10034                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
10035                                         ins->sreg2 = -1;
10036
10037                                         /* Might be followed by an instruction added by add_widen_op */
10038                                         if (sp [1]->next == NULL)
10039                                                 NULLIFY_INS (sp [1]);
10040                                 }
10041                         }
10042                         MONO_ADD_INS ((cfg)->cbb, (ins));
10043
10044                         *sp++ = mono_decompose_opcode (cfg, ins);
10045                         ip++;
10046                         break;
10047                 case CEE_NEG:
10048                 case CEE_NOT:
10049                 case CEE_CONV_I1:
10050                 case CEE_CONV_I2:
10051                 case CEE_CONV_I4:
10052                 case CEE_CONV_R4:
10053                 case CEE_CONV_R8:
10054                 case CEE_CONV_U4:
10055                 case CEE_CONV_I8:
10056                 case CEE_CONV_U8:
10057                 case CEE_CONV_OVF_I8:
10058                 case CEE_CONV_OVF_U8:
10059                 case CEE_CONV_R_UN:
10060                         CHECK_STACK (1);
10061
10062                         /* Special case this earlier so we have long constants in the IR */
10063                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
10064                                 int data = sp [-1]->inst_c0;
10065                                 sp [-1]->opcode = OP_I8CONST;
10066                                 sp [-1]->type = STACK_I8;
10067 #if SIZEOF_REGISTER == 8
10068                                 if ((*ip) == CEE_CONV_U8)
10069                                         sp [-1]->inst_c0 = (guint32)data;
10070                                 else
10071                                         sp [-1]->inst_c0 = data;
10072 #else
10073                                 sp [-1]->inst_ls_word = data;
10074                                 if ((*ip) == CEE_CONV_U8)
10075                                         sp [-1]->inst_ms_word = 0;
10076                                 else
10077                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
10078 #endif
10079                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
10080                         }
10081                         else {
10082                                 ADD_UNOP (*ip);
10083                         }
10084                         ip++;
10085                         break;
10086                 case CEE_CONV_OVF_I4:
10087                 case CEE_CONV_OVF_I1:
10088                 case CEE_CONV_OVF_I2:
10089                 case CEE_CONV_OVF_I:
10090                 case CEE_CONV_OVF_U:
10091                         CHECK_STACK (1);
10092
10093                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10094                                 ADD_UNOP (CEE_CONV_OVF_I8);
10095                                 ADD_UNOP (*ip);
10096                         } else {
10097                                 ADD_UNOP (*ip);
10098                         }
10099                         ip++;
10100                         break;
10101                 case CEE_CONV_OVF_U1:
10102                 case CEE_CONV_OVF_U2:
10103                 case CEE_CONV_OVF_U4:
10104                         CHECK_STACK (1);
10105
10106                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10107                                 ADD_UNOP (CEE_CONV_OVF_U8);
10108                                 ADD_UNOP (*ip);
10109                         } else {
10110                                 ADD_UNOP (*ip);
10111                         }
10112                         ip++;
10113                         break;
10114                 case CEE_CONV_OVF_I1_UN:
10115                 case CEE_CONV_OVF_I2_UN:
10116                 case CEE_CONV_OVF_I4_UN:
10117                 case CEE_CONV_OVF_I8_UN:
10118                 case CEE_CONV_OVF_U1_UN:
10119                 case CEE_CONV_OVF_U2_UN:
10120                 case CEE_CONV_OVF_U4_UN:
10121                 case CEE_CONV_OVF_U8_UN:
10122                 case CEE_CONV_OVF_I_UN:
10123                 case CEE_CONV_OVF_U_UN:
10124                 case CEE_CONV_U2:
10125                 case CEE_CONV_U1:
10126                 case CEE_CONV_I:
10127                 case CEE_CONV_U:
10128                         CHECK_STACK (1);
10129                         ADD_UNOP (*ip);
10130                         CHECK_CFG_EXCEPTION;
10131                         ip++;
10132                         break;
10133                 case CEE_ADD_OVF:
10134                 case CEE_ADD_OVF_UN:
10135                 case CEE_MUL_OVF:
10136                 case CEE_MUL_OVF_UN:
10137                 case CEE_SUB_OVF:
10138                 case CEE_SUB_OVF_UN:
10139                         CHECK_STACK (2);
10140                         ADD_BINOP (*ip);
10141                         ip++;
10142                         break;
10143                 case CEE_CPOBJ:
10144                         GSHAREDVT_FAILURE (*ip);
10145                         CHECK_OPSIZE (5);
10146                         CHECK_STACK (2);
10147                         token = read32 (ip + 1);
10148                         klass = mini_get_class (method, token, generic_context);
10149                         CHECK_TYPELOAD (klass);
10150                         sp -= 2;
10151                         if (generic_class_is_reference_type (cfg, klass)) {
10152                                 MonoInst *store, *load;
10153                                 int dreg = alloc_ireg_ref (cfg);
10154
10155                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
10156                                 load->flags |= ins_flag;
10157                                 MONO_ADD_INS (cfg->cbb, load);
10158
10159                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
10160                                 store->flags |= ins_flag;
10161                                 MONO_ADD_INS (cfg->cbb, store);
10162
10163                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
10164                                         emit_write_barrier (cfg, sp [0], sp [1]);
10165                         } else {
10166                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10167                         }
10168                         ins_flag = 0;
10169                         ip += 5;
10170                         break;
10171                 case CEE_LDOBJ: {
10172                         int loc_index = -1;
10173                         int stloc_len = 0;
10174
10175                         CHECK_OPSIZE (5);
10176                         CHECK_STACK (1);
10177                         --sp;
10178                         token = read32 (ip + 1);
10179                         klass = mini_get_class (method, token, generic_context);
10180                         CHECK_TYPELOAD (klass);
10181
10182                         /* Optimize the common ldobj+stloc combination */
10183                         switch (ip [5]) {
10184                         case CEE_STLOC_S:
10185                                 loc_index = ip [6];
10186                                 stloc_len = 2;
10187                                 break;
10188                         case CEE_STLOC_0:
10189                         case CEE_STLOC_1:
10190                         case CEE_STLOC_2:
10191                         case CEE_STLOC_3:
10192                                 loc_index = ip [5] - CEE_STLOC_0;
10193                                 stloc_len = 1;
10194                                 break;
10195                         default:
10196                                 break;
10197                         }
10198
10199                         if ((loc_index != -1) && ip_in_bb (cfg, cfg->cbb, ip + 5)) {
10200                                 CHECK_LOCAL (loc_index);
10201
10202                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10203                                 ins->dreg = cfg->locals [loc_index]->dreg;
10204                                 ins->flags |= ins_flag;
10205                                 ip += 5;
10206                                 ip += stloc_len;
10207                                 if (ins_flag & MONO_INST_VOLATILE) {
10208                                         /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10209                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10210                                 }
10211                                 ins_flag = 0;
10212                                 break;
10213                         }
10214
10215                         /* Optimize the ldobj+stobj combination */
10216                         /* The reference case ends up being a load+store anyway */
10217                         /* Skip this if the operation is volatile. */
10218                         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)) {
10219                                 CHECK_STACK (1);
10220
10221                                 sp --;
10222
10223                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10224
10225                                 ip += 5 + 5;
10226                                 ins_flag = 0;
10227                                 break;
10228                         }
10229
10230                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10231                         ins->flags |= ins_flag;
10232                         *sp++ = ins;
10233
10234                         if (ins_flag & MONO_INST_VOLATILE) {
10235                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10236                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10237                         }
10238
10239                         ip += 5;
10240                         ins_flag = 0;
10241                         inline_costs += 1;
10242                         break;
10243                 }
10244                 case CEE_LDSTR:
10245                         CHECK_STACK_OVF (1);
10246                         CHECK_OPSIZE (5);
10247                         n = read32 (ip + 1);
10248
10249                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
10250                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
10251                                 ins->type = STACK_OBJ;
10252                                 *sp = ins;
10253                         }
10254                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
10255                                 MonoInst *iargs [1];
10256                                 char *str = mono_method_get_wrapper_data (method, n);
10257
10258                                 if (cfg->compile_aot)
10259                                         EMIT_NEW_LDSTRLITCONST (cfg, iargs [0], str);
10260                                 else
10261                                         EMIT_NEW_PCONST (cfg, iargs [0], str);
10262                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
10263                         } else {
10264                                 if (cfg->opt & MONO_OPT_SHARED) {
10265                                         MonoInst *iargs [3];
10266
10267                                         if (cfg->compile_aot) {
10268                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
10269                                         }
10270                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10271                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
10272                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
10273                                         *sp = mono_emit_jit_icall (cfg, mono_ldstr, iargs);
10274                                         mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
10275                                 } else {
10276                                         if (cfg->cbb->out_of_line) {
10277                                                 MonoInst *iargs [2];
10278
10279                                                 if (image == mono_defaults.corlib) {
10280                                                         /* 
10281                                                          * Avoid relocations in AOT and save some space by using a 
10282                                                          * version of helper_ldstr specialized to mscorlib.
10283                                                          */
10284                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
10285                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
10286                                                 } else {
10287                                                         /* Avoid creating the string object */
10288                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
10289                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
10290                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
10291                                                 }
10292                                         } 
10293                                         else
10294                                         if (cfg->compile_aot) {
10295                                                 NEW_LDSTRCONST (cfg, ins, image, n);
10296                                                 *sp = ins;
10297                                                 MONO_ADD_INS (cfg->cbb, ins);
10298                                         } 
10299                                         else {
10300                                                 NEW_PCONST (cfg, ins, NULL);
10301                                                 ins->type = STACK_OBJ;
10302                                                 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
10303                                                 if (!ins->inst_p0)
10304                                                         OUT_OF_MEMORY_FAILURE;
10305
10306                                                 *sp = ins;
10307                                                 MONO_ADD_INS (cfg->cbb, ins);
10308                                         }
10309                                 }
10310                         }
10311
10312                         sp++;
10313                         ip += 5;
10314                         break;
10315                 case CEE_NEWOBJ: {
10316                         MonoInst *iargs [2];
10317                         MonoMethodSignature *fsig;
10318                         MonoInst this_ins;
10319                         MonoInst *alloc;
10320                         MonoInst *vtable_arg = NULL;
10321
10322                         CHECK_OPSIZE (5);
10323                         token = read32 (ip + 1);
10324                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
10325                         if (!cmethod || mono_loader_get_last_error ())
10326                                 LOAD_ERROR;
10327                         fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
10328                         CHECK_CFG_ERROR;
10329
10330                         mono_save_token_info (cfg, image, token, cmethod);
10331
10332                         if (!mono_class_init (cmethod->klass))
10333                                 TYPE_LOAD_ERROR (cmethod->klass);
10334
10335                         context_used = mini_method_check_context_used (cfg, cmethod);
10336
10337                         if (mono_security_core_clr_enabled ())
10338                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
10339
10340                         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)) {
10341                                 emit_class_init (cfg, cmethod->klass);
10342                                 CHECK_TYPELOAD (cmethod->klass);
10343                         }
10344
10345                         /*
10346                         if (cfg->gsharedvt) {
10347                                 if (mini_is_gsharedvt_variable_signature (sig))
10348                                         GSHAREDVT_FAILURE (*ip);
10349                         }
10350                         */
10351
10352                         n = fsig->param_count;
10353                         CHECK_STACK (n);
10354
10355                         /* 
10356                          * Generate smaller code for the common newobj <exception> instruction in
10357                          * argument checking code.
10358                          */
10359                         if (cfg->cbb->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
10360                                 is_exception_class (cmethod->klass) && n <= 2 &&
10361                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
10362                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
10363                                 MonoInst *iargs [3];
10364
10365                                 sp -= n;
10366
10367                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
10368                                 switch (n) {
10369                                 case 0:
10370                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
10371                                         break;
10372                                 case 1:
10373                                         iargs [1] = sp [0];
10374                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
10375                                         break;
10376                                 case 2:
10377                                         iargs [1] = sp [0];
10378                                         iargs [2] = sp [1];
10379                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
10380                                         break;
10381                                 default:
10382                                         g_assert_not_reached ();
10383                                 }
10384
10385                                 ip += 5;
10386                                 inline_costs += 5;
10387                                 break;
10388                         }
10389
10390                         /* move the args to allow room for 'this' in the first position */
10391                         while (n--) {
10392                                 --sp;
10393                                 sp [1] = sp [0];
10394                         }
10395
10396                         /* check_call_signature () requires sp[0] to be set */
10397                         this_ins.type = STACK_OBJ;
10398                         sp [0] = &this_ins;
10399                         if (check_call_signature (cfg, fsig, sp))
10400                                 UNVERIFIED;
10401
10402                         iargs [0] = NULL;
10403
10404                         if (mini_class_is_system_array (cmethod->klass)) {
10405                                 *sp = emit_get_rgctx_method (cfg, context_used,
10406                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
10407
10408                                 /* Avoid varargs in the common case */
10409                                 if (fsig->param_count == 1)
10410                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
10411                                 else if (fsig->param_count == 2)
10412                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
10413                                 else if (fsig->param_count == 3)
10414                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
10415                                 else if (fsig->param_count == 4)
10416                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
10417                                 else
10418                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
10419                         } else if (cmethod->string_ctor) {
10420                                 g_assert (!context_used);
10421                                 g_assert (!vtable_arg);
10422                                 /* we simply pass a null pointer */
10423                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
10424                                 /* now call the string ctor */
10425                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
10426                         } else {
10427                                 if (cmethod->klass->valuetype) {
10428                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
10429                                         emit_init_rvar (cfg, iargs [0]->dreg, &cmethod->klass->byval_arg);
10430                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
10431
10432                                         alloc = NULL;
10433
10434                                         /* 
10435                                          * The code generated by mini_emit_virtual_call () expects
10436                                          * iargs [0] to be a boxed instance, but luckily the vcall
10437                                          * will be transformed into a normal call there.
10438                                          */
10439                                 } else if (context_used) {
10440                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
10441                                         *sp = alloc;
10442                                 } else {
10443                                         MonoVTable *vtable = NULL;
10444
10445                                         if (!cfg->compile_aot)
10446                                                 vtable = mono_class_vtable (cfg->domain, cmethod->klass);
10447                                         CHECK_TYPELOAD (cmethod->klass);
10448
10449                                         /*
10450                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
10451                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
10452                                          * As a workaround, we call class cctors before allocating objects.
10453                                          */
10454                                         if (mini_field_access_needs_cctor_run (cfg, method, cmethod->klass, vtable) && !(g_slist_find (class_inits, cmethod->klass))) {
10455                                                 emit_class_init (cfg, cmethod->klass);
10456                                                 if (cfg->verbose_level > 2)
10457                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
10458                                                 class_inits = g_slist_prepend (class_inits, cmethod->klass);
10459                                         }
10460
10461                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
10462                                         *sp = alloc;
10463                                 }
10464                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
10465
10466                                 if (alloc)
10467                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
10468
10469                                 /* Now call the actual ctor */
10470                                 handle_ctor_call (cfg, cmethod, fsig, context_used, sp, ip, &inline_costs);
10471                                 CHECK_CFG_EXCEPTION;
10472                         }
10473
10474                         if (alloc == NULL) {
10475                                 /* Valuetype */
10476                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
10477                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
10478                                 *sp++= ins;
10479                         } else {
10480                                 *sp++ = alloc;
10481                         }
10482                         
10483                         ip += 5;
10484                         inline_costs += 5;
10485                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip - header->code)))
10486                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10487                         break;
10488                 }
10489                 case CEE_CASTCLASS:
10490                         CHECK_STACK (1);
10491                         --sp;
10492                         CHECK_OPSIZE (5);
10493                         token = read32 (ip + 1);
10494                         klass = mini_get_class (method, token, generic_context);
10495                         CHECK_TYPELOAD (klass);
10496                         if (sp [0]->type != STACK_OBJ)
10497                                 UNVERIFIED;
10498
10499                         ins = handle_castclass (cfg, klass, *sp, ip, &inline_costs);
10500                         CHECK_CFG_EXCEPTION;
10501
10502                         *sp ++ = ins;
10503                         ip += 5;
10504                         break;
10505                 case CEE_ISINST: {
10506                         CHECK_STACK (1);
10507                         --sp;
10508                         CHECK_OPSIZE (5);
10509                         token = read32 (ip + 1);
10510                         klass = mini_get_class (method, token, generic_context);
10511                         CHECK_TYPELOAD (klass);
10512                         if (sp [0]->type != STACK_OBJ)
10513                                 UNVERIFIED;
10514  
10515                         context_used = mini_class_check_context_used (cfg, klass);
10516
10517                         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
10518                                 MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
10519                                 MonoInst *args [3];
10520                                 int idx;
10521
10522                                 /* obj */
10523                                 args [0] = *sp;
10524
10525                                 /* klass */
10526                                 EMIT_NEW_CLASSCONST (cfg, args [1], klass);
10527
10528                                 /* inline cache*/
10529                                 if (cfg->compile_aot) {
10530                                         idx = get_castclass_cache_idx (cfg);
10531                                         EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
10532                                 } else {
10533                                         EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
10534                                 }
10535
10536                                 *sp++ = mono_emit_method_call (cfg, mono_isinst, args, NULL);
10537                                 ip += 5;
10538                                 inline_costs += 2;
10539                         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
10540                                 MonoMethod *mono_isinst;
10541                                 MonoInst *iargs [1];
10542                                 int costs;
10543
10544                                 mono_isinst = mono_marshal_get_isinst (klass); 
10545                                 iargs [0] = sp [0];
10546
10547                                 costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), 
10548                                                                            iargs, ip, cfg->real_offset, TRUE);
10549                                 CHECK_CFG_EXCEPTION;
10550                                 g_assert (costs > 0);
10551                                 
10552                                 ip += 5;
10553                                 cfg->real_offset += 5;
10554
10555                                 *sp++= iargs [0];
10556
10557                                 inline_costs += costs;
10558                         }
10559                         else {
10560                                 ins = handle_isinst (cfg, klass, *sp, context_used);
10561                                 CHECK_CFG_EXCEPTION;
10562                                 *sp ++ = ins;
10563                                 ip += 5;
10564                         }
10565                         break;
10566                 }
10567                 case CEE_UNBOX_ANY: {
10568                         MonoInst *res, *addr;
10569
10570                         CHECK_STACK (1);
10571                         --sp;
10572                         CHECK_OPSIZE (5);
10573                         token = read32 (ip + 1);
10574                         klass = mini_get_class (method, token, generic_context);
10575                         CHECK_TYPELOAD (klass);
10576
10577                         mono_save_token_info (cfg, image, token, klass);
10578
10579                         context_used = mini_class_check_context_used (cfg, klass);
10580
10581                         if (mini_is_gsharedvt_klass (klass)) {
10582                                 res = handle_unbox_gsharedvt (cfg, klass, *sp);
10583                                 inline_costs += 2;
10584                         } else if (generic_class_is_reference_type (cfg, klass)) {
10585                                 res = handle_castclass (cfg, klass, *sp, ip, &inline_costs);
10586                                 CHECK_CFG_EXCEPTION;
10587                         } else if (mono_class_is_nullable (klass)) {
10588                                 res = handle_unbox_nullable (cfg, *sp, klass, context_used);
10589                         } else {
10590                                 addr = handle_unbox (cfg, klass, sp, context_used);
10591                                 /* LDOBJ */
10592                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
10593                                 res = ins;
10594                                 inline_costs += 2;
10595                         }
10596
10597                         *sp ++ = res;
10598                         ip += 5;
10599                         break;
10600                 }
10601                 case CEE_BOX: {
10602                         MonoInst *val;
10603                         MonoClass *enum_class;
10604                         MonoMethod *has_flag;
10605
10606                         CHECK_STACK (1);
10607                         --sp;
10608                         val = *sp;
10609                         CHECK_OPSIZE (5);
10610                         token = read32 (ip + 1);
10611                         klass = mini_get_class (method, token, generic_context);
10612                         CHECK_TYPELOAD (klass);
10613
10614                         mono_save_token_info (cfg, image, token, klass);
10615
10616                         context_used = mini_class_check_context_used (cfg, klass);
10617
10618                         if (generic_class_is_reference_type (cfg, klass)) {
10619                                 *sp++ = val;
10620                                 ip += 5;
10621                                 break;
10622                         }
10623
10624                         if (klass == mono_defaults.void_class)
10625                                 UNVERIFIED;
10626                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
10627                                 UNVERIFIED;
10628                         /* frequent check in generic code: box (struct), brtrue */
10629
10630                         /*
10631                          * Look for:
10632                          *
10633                          *   <push int/long ptr>
10634                          *   <push int/long>
10635                          *   box MyFlags
10636                          *   constrained. MyFlags
10637                          *   callvirt instace bool class [mscorlib] System.Enum::HasFlag (class [mscorlib] System.Enum)
10638                          *
10639                          * If we find this sequence and the operand types on box and constrained
10640                          * are equal, we can emit a specialized instruction sequence instead of
10641                          * the very slow HasFlag () call.
10642                          */
10643                         if ((cfg->opt & MONO_OPT_INTRINS) &&
10644                             /* Cheap checks first. */
10645                             ip + 5 + 6 + 5 < end &&
10646                             ip [5] == CEE_PREFIX1 &&
10647                             ip [6] == CEE_CONSTRAINED_ &&
10648                             ip [11] == CEE_CALLVIRT &&
10649                             ip_in_bb (cfg, cfg->cbb, ip + 5 + 6 + 5) &&
10650                             mono_class_is_enum (klass) &&
10651                             (enum_class = mini_get_class (method, read32 (ip + 7), generic_context)) &&
10652                             (has_flag = mini_get_method (cfg, method, read32 (ip + 12), NULL, generic_context)) &&
10653                             has_flag->klass == mono_defaults.enum_class &&
10654                             !strcmp (has_flag->name, "HasFlag") &&
10655                             has_flag->signature->hasthis &&
10656                             has_flag->signature->param_count == 1) {
10657                                 CHECK_TYPELOAD (enum_class);
10658
10659                                 if (enum_class == klass) {
10660                                         MonoInst *enum_this, *enum_flag;
10661
10662                                         ip += 5 + 6 + 5;
10663                                         --sp;
10664
10665                                         enum_this = sp [0];
10666                                         enum_flag = sp [1];
10667
10668                                         *sp++ = handle_enum_has_flag (cfg, klass, enum_this, enum_flag);
10669                                         break;
10670                                 }
10671                         }
10672
10673                         // FIXME: LLVM can't handle the inconsistent bb linking
10674                         if (!mono_class_is_nullable (klass) &&
10675                                 ip + 5 < end && ip_in_bb (cfg, cfg->cbb, ip + 5) &&
10676                                 (ip [5] == CEE_BRTRUE || 
10677                                  ip [5] == CEE_BRTRUE_S ||
10678                                  ip [5] == CEE_BRFALSE ||
10679                                  ip [5] == CEE_BRFALSE_S)) {
10680                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
10681                                 int dreg;
10682                                 MonoBasicBlock *true_bb, *false_bb;
10683
10684                                 ip += 5;
10685
10686                                 if (cfg->verbose_level > 3) {
10687                                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
10688                                         printf ("<box+brtrue opt>\n");
10689                                 }
10690
10691                                 switch (*ip) {
10692                                 case CEE_BRTRUE_S:
10693                                 case CEE_BRFALSE_S:
10694                                         CHECK_OPSIZE (2);
10695                                         ip++;
10696                                         target = ip + 1 + (signed char)(*ip);
10697                                         ip++;
10698                                         break;
10699                                 case CEE_BRTRUE:
10700                                 case CEE_BRFALSE:
10701                                         CHECK_OPSIZE (5);
10702                                         ip++;
10703                                         target = ip + 4 + (gint)(read32 (ip));
10704                                         ip += 4;
10705                                         break;
10706                                 default:
10707                                         g_assert_not_reached ();
10708                                 }
10709
10710                                 /* 
10711                                  * We need to link both bblocks, since it is needed for handling stack
10712                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
10713                                  * Branching to only one of them would lead to inconsistencies, so
10714                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
10715                                  */
10716                                 GET_BBLOCK (cfg, true_bb, target);
10717                                 GET_BBLOCK (cfg, false_bb, ip);
10718
10719                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
10720                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
10721
10722                                 if (sp != stack_start) {
10723                                         handle_stack_args (cfg, stack_start, sp - stack_start);
10724                                         sp = stack_start;
10725                                         CHECK_UNVERIFIABLE (cfg);
10726                                 }
10727
10728                                 if (COMPILE_LLVM (cfg)) {
10729                                         dreg = alloc_ireg (cfg);
10730                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
10731                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
10732
10733                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
10734                                 } else {
10735                                         /* The JIT can't eliminate the iconst+compare */
10736                                         MONO_INST_NEW (cfg, ins, OP_BR);
10737                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
10738                                         MONO_ADD_INS (cfg->cbb, ins);
10739                                 }
10740
10741                                 start_new_bblock = 1;
10742                                 break;
10743                         }
10744
10745                         *sp++ = handle_box (cfg, val, klass, context_used);
10746
10747                         CHECK_CFG_EXCEPTION;
10748                         ip += 5;
10749                         inline_costs += 1;
10750                         break;
10751                 }
10752                 case CEE_UNBOX: {
10753                         CHECK_STACK (1);
10754                         --sp;
10755                         CHECK_OPSIZE (5);
10756                         token = read32 (ip + 1);
10757                         klass = mini_get_class (method, token, generic_context);
10758                         CHECK_TYPELOAD (klass);
10759
10760                         mono_save_token_info (cfg, image, token, klass);
10761
10762                         context_used = mini_class_check_context_used (cfg, klass);
10763
10764                         if (mono_class_is_nullable (klass)) {
10765                                 MonoInst *val;
10766
10767                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
10768                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
10769
10770                                 *sp++= ins;
10771                         } else {
10772                                 ins = handle_unbox (cfg, klass, sp, context_used);
10773                                 *sp++ = ins;
10774                         }
10775                         ip += 5;
10776                         inline_costs += 2;
10777                         break;
10778                 }
10779                 case CEE_LDFLD:
10780                 case CEE_LDFLDA:
10781                 case CEE_STFLD:
10782                 case CEE_LDSFLD:
10783                 case CEE_LDSFLDA:
10784                 case CEE_STSFLD: {
10785                         MonoClassField *field;
10786 #ifndef DISABLE_REMOTING
10787                         int costs;
10788 #endif
10789                         guint foffset;
10790                         gboolean is_instance;
10791                         int op;
10792                         gpointer addr = NULL;
10793                         gboolean is_special_static;
10794                         MonoType *ftype;
10795                         MonoInst *store_val = NULL;
10796                         MonoInst *thread_ins;
10797
10798                         op = *ip;
10799                         is_instance = (op == CEE_LDFLD || op == CEE_LDFLDA || op == CEE_STFLD);
10800                         if (is_instance) {
10801                                 if (op == CEE_STFLD) {
10802                                         CHECK_STACK (2);
10803                                         sp -= 2;
10804                                         store_val = sp [1];
10805                                 } else {
10806                                         CHECK_STACK (1);
10807                                         --sp;
10808                                 }
10809                                 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
10810                                         UNVERIFIED;
10811                                 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
10812                                         UNVERIFIED;
10813                         } else {
10814                                 if (op == CEE_STSFLD) {
10815                                         CHECK_STACK (1);
10816                                         sp--;
10817                                         store_val = sp [0];
10818                                 }
10819                         }
10820
10821                         CHECK_OPSIZE (5);
10822                         token = read32 (ip + 1);
10823                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
10824                                 field = mono_method_get_wrapper_data (method, token);
10825                                 klass = field->parent;
10826                         }
10827                         else {
10828                                 field = mono_field_from_token_checked (image, token, &klass, generic_context, &cfg->error);
10829                                 CHECK_CFG_ERROR;
10830                         }
10831                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
10832                                 FIELD_ACCESS_FAILURE (method, field);
10833                         mono_class_init (klass);
10834
10835                         /* if the class is Critical then transparent code cannot access it's fields */
10836                         if (!is_instance && mono_security_core_clr_enabled ())
10837                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
10838
10839                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
10840                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
10841                         if (mono_security_core_clr_enabled ())
10842                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
10843                         */
10844
10845                         /*
10846                          * LDFLD etc. is usable on static fields as well, so convert those cases to
10847                          * the static case.
10848                          */
10849                         if (is_instance && field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
10850                                 switch (op) {
10851                                 case CEE_LDFLD:
10852                                         op = CEE_LDSFLD;
10853                                         break;
10854                                 case CEE_STFLD:
10855                                         op = CEE_STSFLD;
10856                                         break;
10857                                 case CEE_LDFLDA:
10858                                         op = CEE_LDSFLDA;
10859                                         break;
10860                                 default:
10861                                         g_assert_not_reached ();
10862                                 }
10863                                 is_instance = FALSE;
10864                         }
10865
10866                         context_used = mini_class_check_context_used (cfg, klass);
10867
10868                         /* INSTANCE CASE */
10869
10870                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
10871                         if (op == CEE_STFLD) {
10872                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
10873                                         UNVERIFIED;
10874 #ifndef DISABLE_REMOTING
10875                                 if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
10876                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
10877                                         MonoInst *iargs [5];
10878
10879                                         GSHAREDVT_FAILURE (op);
10880
10881                                         iargs [0] = sp [0];
10882                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10883                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
10884                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
10885                                                     field->offset);
10886                                         iargs [4] = sp [1];
10887
10888                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
10889                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
10890                                                                                            iargs, ip, cfg->real_offset, TRUE);
10891                                                 CHECK_CFG_EXCEPTION;
10892                                                 g_assert (costs > 0);
10893                                                       
10894                                                 cfg->real_offset += 5;
10895
10896                                                 inline_costs += costs;
10897                                         } else {
10898                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
10899                                         }
10900                                 } else
10901 #endif
10902                                 {
10903                                         MonoInst *store;
10904
10905                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
10906
10907                                         if (mini_is_gsharedvt_klass (klass)) {
10908                                                 MonoInst *offset_ins;
10909
10910                                                 context_used = mini_class_check_context_used (cfg, klass);
10911
10912                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10913                                                 dreg = alloc_ireg_mp (cfg);
10914                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10915                                                 /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
10916                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
10917                                         } else {
10918                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
10919                                         }
10920                                         if (sp [0]->opcode != OP_LDADDR)
10921                                                 store->flags |= MONO_INST_FAULT;
10922
10923                                 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)) {
10924                                         /* insert call to write barrier */
10925                                         MonoInst *ptr;
10926                                         int dreg;
10927
10928                                         dreg = alloc_ireg_mp (cfg);
10929                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
10930                                         emit_write_barrier (cfg, ptr, sp [1]);
10931                                 }
10932
10933                                         store->flags |= ins_flag;
10934                                 }
10935                                 ins_flag = 0;
10936                                 ip += 5;
10937                                 break;
10938                         }
10939
10940 #ifndef DISABLE_REMOTING
10941                         if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
10942                                 MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
10943                                 MonoInst *iargs [4];
10944
10945                                 GSHAREDVT_FAILURE (op);
10946
10947                                 iargs [0] = sp [0];
10948                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10949                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
10950                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
10951                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
10952                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
10953                                                                                    iargs, ip, cfg->real_offset, TRUE);
10954                                         CHECK_CFG_EXCEPTION;
10955                                         g_assert (costs > 0);
10956                                                       
10957                                         cfg->real_offset += 5;
10958
10959                                         *sp++ = iargs [0];
10960
10961                                         inline_costs += costs;
10962                                 } else {
10963                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
10964                                         *sp++ = ins;
10965                                 }
10966                         } else 
10967 #endif
10968                         if (is_instance) {
10969                                 if (sp [0]->type == STACK_VTYPE) {
10970                                         MonoInst *var;
10971
10972                                         /* Have to compute the address of the variable */
10973
10974                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
10975                                         if (!var)
10976                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
10977                                         else
10978                                                 g_assert (var->klass == klass);
10979                                         
10980                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
10981                                         sp [0] = ins;
10982                                 }
10983
10984                                 if (op == CEE_LDFLDA) {
10985                                         if (sp [0]->type == STACK_OBJ) {
10986                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
10987                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
10988                                         }
10989
10990                                         dreg = alloc_ireg_mp (cfg);
10991
10992                                         if (mini_is_gsharedvt_klass (klass)) {
10993                                                 MonoInst *offset_ins;
10994
10995                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10996                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10997                                         } else {
10998                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
10999                                         }
11000                                         ins->klass = mono_class_from_mono_type (field->type);
11001                                         ins->type = STACK_MP;
11002                                         *sp++ = ins;
11003                                 } else {
11004                                         MonoInst *load;
11005
11006                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
11007
11008                                         if (mini_is_gsharedvt_klass (klass)) {
11009                                                 MonoInst *offset_ins;
11010
11011                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11012                                                 dreg = alloc_ireg_mp (cfg);
11013                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11014                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
11015                                         } else {
11016                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
11017                                         }
11018                                         load->flags |= ins_flag;
11019                                         if (sp [0]->opcode != OP_LDADDR)
11020                                                 load->flags |= MONO_INST_FAULT;
11021                                         *sp++ = load;
11022                                 }
11023                         }
11024
11025                         if (is_instance) {
11026                                 ins_flag = 0;
11027                                 ip += 5;
11028                                 break;
11029                         }
11030
11031                         /* STATIC CASE */
11032                         context_used = mini_class_check_context_used (cfg, klass);
11033
11034                         ftype = mono_field_get_type (field);
11035
11036                         if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL)
11037                                 UNVERIFIED;
11038
11039                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
11040                          * to be called here.
11041                          */
11042                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
11043                                 mono_class_vtable (cfg->domain, klass);
11044                                 CHECK_TYPELOAD (klass);
11045                         }
11046                         mono_domain_lock (cfg->domain);
11047                         if (cfg->domain->special_static_fields)
11048                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
11049                         mono_domain_unlock (cfg->domain);
11050
11051                         is_special_static = mono_class_field_is_special_static (field);
11052
11053                         if (is_special_static && ((gsize)addr & 0x80000000) == 0)
11054                                 thread_ins = mono_get_thread_intrinsic (cfg);
11055                         else
11056                                 thread_ins = NULL;
11057
11058                         /* Generate IR to compute the field address */
11059                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && thread_ins && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
11060                                 /*
11061                                  * Fast access to TLS data
11062                                  * Inline version of get_thread_static_data () in
11063                                  * threads.c.
11064                                  */
11065                                 guint32 offset;
11066                                 int idx, static_data_reg, array_reg, dreg;
11067
11068                                 GSHAREDVT_FAILURE (op);
11069
11070                                 MONO_ADD_INS (cfg->cbb, thread_ins);
11071                                 static_data_reg = alloc_ireg (cfg);
11072                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
11073
11074                                 if (cfg->compile_aot) {
11075                                         int offset_reg, offset2_reg, idx_reg;
11076
11077                                         /* For TLS variables, this will return the TLS offset */
11078                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
11079                                         offset_reg = ins->dreg;
11080                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
11081                                         idx_reg = alloc_ireg (cfg);
11082                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, idx_reg, offset_reg, 0x3f);
11083                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
11084                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
11085                                         array_reg = alloc_ireg (cfg);
11086                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
11087                                         offset2_reg = alloc_ireg (cfg);
11088                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, offset2_reg, offset_reg, 6);
11089                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset2_reg, 0x1ffffff);
11090                                         dreg = alloc_ireg (cfg);
11091                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
11092                                 } else {
11093                                         offset = (gsize)addr & 0x7fffffff;
11094                                         idx = offset & 0x3f;
11095
11096                                         array_reg = alloc_ireg (cfg);
11097                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
11098                                         dreg = alloc_ireg (cfg);
11099                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, ((offset >> 6) & 0x1ffffff));
11100                                 }
11101                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
11102                                         (cfg->compile_aot && is_special_static) ||
11103                                         (context_used && is_special_static)) {
11104                                 MonoInst *iargs [2];
11105
11106                                 g_assert (field->parent);
11107                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11108                                 if (context_used) {
11109                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
11110                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
11111                                 } else {
11112                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11113                                 }
11114                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11115                         } else if (context_used) {
11116                                 MonoInst *static_data;
11117
11118                                 /*
11119                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
11120                                         method->klass->name_space, method->klass->name, method->name,
11121                                         depth, field->offset);
11122                                 */
11123
11124                                 if (mono_class_needs_cctor_run (klass, method))
11125                                         emit_class_init (cfg, klass);
11126
11127                                 /*
11128                                  * The pointer we're computing here is
11129                                  *
11130                                  *   super_info.static_data + field->offset
11131                                  */
11132                                 static_data = emit_get_rgctx_klass (cfg, context_used,
11133                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
11134
11135                                 if (mini_is_gsharedvt_klass (klass)) {
11136                                         MonoInst *offset_ins;
11137
11138                                         offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11139                                         dreg = alloc_ireg_mp (cfg);
11140                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
11141                                 } else if (field->offset == 0) {
11142                                         ins = static_data;
11143                                 } else {
11144                                         int addr_reg = mono_alloc_preg (cfg);
11145                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
11146                                 }
11147                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
11148                                 MonoInst *iargs [2];
11149
11150                                 g_assert (field->parent);
11151                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11152                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11153                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11154                         } else {
11155                                 MonoVTable *vtable = NULL;
11156
11157                                 if (!cfg->compile_aot)
11158                                         vtable = mono_class_vtable (cfg->domain, klass);
11159                                 CHECK_TYPELOAD (klass);
11160
11161                                 if (!addr) {
11162                                         if (mini_field_access_needs_cctor_run (cfg, method, klass, vtable)) {
11163                                                 if (!(g_slist_find (class_inits, klass))) {
11164                                                         emit_class_init (cfg, klass);
11165                                                         if (cfg->verbose_level > 2)
11166                                                                 printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
11167                                                         class_inits = g_slist_prepend (class_inits, klass);
11168                                                 }
11169                                         } else {
11170                                                 if (cfg->run_cctors) {
11171                                                         MonoException *ex;
11172                                                         /* This makes so that inline cannot trigger */
11173                                                         /* .cctors: too many apps depend on them */
11174                                                         /* running with a specific order... */
11175                                                         g_assert (vtable);
11176                                                         if (! vtable->initialized)
11177                                                                 INLINE_FAILURE ("class init");
11178                                                         ex = mono_runtime_class_init_full (vtable, FALSE);
11179                                                         if (ex) {
11180                                                                 set_exception_object (cfg, ex);
11181                                                                 goto exception_exit;
11182                                                         }
11183                                                 }
11184                                         }
11185                                         if (cfg->compile_aot)
11186                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
11187                                         else {
11188                                                 g_assert (vtable);
11189                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11190                                                 g_assert (addr);
11191                                                 EMIT_NEW_PCONST (cfg, ins, addr);
11192                                         }
11193                                 } else {
11194                                         MonoInst *iargs [1];
11195                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
11196                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
11197                                 }
11198                         }
11199
11200                         /* Generate IR to do the actual load/store operation */
11201
11202                         if ((op == CEE_STFLD || op == CEE_STSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11203                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11204                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11205                         }
11206
11207                         if (op == CEE_LDSFLDA) {
11208                                 ins->klass = mono_class_from_mono_type (ftype);
11209                                 ins->type = STACK_PTR;
11210                                 *sp++ = ins;
11211                         } else if (op == CEE_STSFLD) {
11212                                 MonoInst *store;
11213
11214                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
11215                                 store->flags |= ins_flag;
11216                         } else {
11217                                 gboolean is_const = FALSE;
11218                                 MonoVTable *vtable = NULL;
11219                                 gpointer addr = NULL;
11220
11221                                 if (!context_used) {
11222                                         vtable = mono_class_vtable (cfg->domain, klass);
11223                                         CHECK_TYPELOAD (klass);
11224                                 }
11225                                 if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) ||
11226                                                 (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) {
11227                                         int ro_type = ftype->type;
11228                                         if (!addr)
11229                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11230                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
11231                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
11232                                         }
11233
11234                                         GSHAREDVT_FAILURE (op);
11235
11236                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
11237                                         is_const = TRUE;
11238                                         switch (ro_type) {
11239                                         case MONO_TYPE_BOOLEAN:
11240                                         case MONO_TYPE_U1:
11241                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
11242                                                 sp++;
11243                                                 break;
11244                                         case MONO_TYPE_I1:
11245                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
11246                                                 sp++;
11247                                                 break;                                          
11248                                         case MONO_TYPE_CHAR:
11249                                         case MONO_TYPE_U2:
11250                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
11251                                                 sp++;
11252                                                 break;
11253                                         case MONO_TYPE_I2:
11254                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
11255                                                 sp++;
11256                                                 break;
11257                                                 break;
11258                                         case MONO_TYPE_I4:
11259                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
11260                                                 sp++;
11261                                                 break;                                          
11262                                         case MONO_TYPE_U4:
11263                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
11264                                                 sp++;
11265                                                 break;
11266                                         case MONO_TYPE_I:
11267                                         case MONO_TYPE_U:
11268                                         case MONO_TYPE_PTR:
11269                                         case MONO_TYPE_FNPTR:
11270                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11271                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
11272                                                 sp++;
11273                                                 break;
11274                                         case MONO_TYPE_STRING:
11275                                         case MONO_TYPE_OBJECT:
11276                                         case MONO_TYPE_CLASS:
11277                                         case MONO_TYPE_SZARRAY:
11278                                         case MONO_TYPE_ARRAY:
11279                                                 if (!mono_gc_is_moving ()) {
11280                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11281                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
11282                                                         sp++;
11283                                                 } else {
11284                                                         is_const = FALSE;
11285                                                 }
11286                                                 break;
11287                                         case MONO_TYPE_I8:
11288                                         case MONO_TYPE_U8:
11289                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
11290                                                 sp++;
11291                                                 break;
11292                                         case MONO_TYPE_R4:
11293                                         case MONO_TYPE_R8:
11294                                         case MONO_TYPE_VALUETYPE:
11295                                         default:
11296                                                 is_const = FALSE;
11297                                                 break;
11298                                         }
11299                                 }
11300
11301                                 if (!is_const) {
11302                                         MonoInst *load;
11303
11304                                         CHECK_STACK_OVF (1);
11305
11306                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
11307                                         load->flags |= ins_flag;
11308                                         ins_flag = 0;
11309                                         *sp++ = load;
11310                                 }
11311                         }
11312
11313                         if ((op == CEE_LDFLD || op == CEE_LDSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11314                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
11315                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
11316                         }
11317
11318                         ins_flag = 0;
11319                         ip += 5;
11320                         break;
11321                 }
11322                 case CEE_STOBJ:
11323                         CHECK_STACK (2);
11324                         sp -= 2;
11325                         CHECK_OPSIZE (5);
11326                         token = read32 (ip + 1);
11327                         klass = mini_get_class (method, token, generic_context);
11328                         CHECK_TYPELOAD (klass);
11329                         if (ins_flag & MONO_INST_VOLATILE) {
11330                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11331                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11332                         }
11333                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
11334                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
11335                         ins->flags |= ins_flag;
11336                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
11337                                         generic_class_is_reference_type (cfg, klass)) {
11338                                 /* insert call to write barrier */
11339                                 emit_write_barrier (cfg, sp [0], sp [1]);
11340                         }
11341                         ins_flag = 0;
11342                         ip += 5;
11343                         inline_costs += 1;
11344                         break;
11345
11346                         /*
11347                          * Array opcodes
11348                          */
11349                 case CEE_NEWARR: {
11350                         MonoInst *len_ins;
11351                         const char *data_ptr;
11352                         int data_size = 0;
11353                         guint32 field_token;
11354
11355                         CHECK_STACK (1);
11356                         --sp;
11357
11358                         CHECK_OPSIZE (5);
11359                         token = read32 (ip + 1);
11360
11361                         klass = mini_get_class (method, token, generic_context);
11362                         CHECK_TYPELOAD (klass);
11363
11364                         context_used = mini_class_check_context_used (cfg, klass);
11365
11366                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
11367                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_OVF_U4);
11368                                 ins->sreg1 = sp [0]->dreg;
11369                                 ins->type = STACK_I4;
11370                                 ins->dreg = alloc_ireg (cfg);
11371                                 MONO_ADD_INS (cfg->cbb, ins);
11372                                 *sp = mono_decompose_opcode (cfg, ins);
11373                         }
11374
11375                         if (context_used) {
11376                                 MonoInst *args [3];
11377                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11378                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
11379
11380                                 /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
11381
11382                                 /* vtable */
11383                                 args [0] = emit_get_rgctx_klass (cfg, context_used,
11384                                         array_class, MONO_RGCTX_INFO_VTABLE);
11385                                 /* array len */
11386                                 args [1] = sp [0];
11387
11388                                 if (managed_alloc)
11389                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
11390                                 else
11391                                         ins = mono_emit_jit_icall (cfg, mono_array_new_specific, args);
11392                         } else {
11393                                 if (cfg->opt & MONO_OPT_SHARED) {
11394                                         /* Decompose now to avoid problems with references to the domainvar */
11395                                         MonoInst *iargs [3];
11396
11397                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11398                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11399                                         iargs [2] = sp [0];
11400
11401                                         ins = mono_emit_jit_icall (cfg, mono_array_new, iargs);
11402                                 } else {
11403                                         /* Decompose later since it is needed by abcrem */
11404                                         MonoClass *array_type = mono_array_class_get (klass, 1);
11405                                         mono_class_vtable (cfg->domain, array_type);
11406                                         CHECK_TYPELOAD (array_type);
11407
11408                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
11409                                         ins->dreg = alloc_ireg_ref (cfg);
11410                                         ins->sreg1 = sp [0]->dreg;
11411                                         ins->inst_newa_class = klass;
11412                                         ins->type = STACK_OBJ;
11413                                         ins->klass = array_type;
11414                                         MONO_ADD_INS (cfg->cbb, ins);
11415                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11416                                         cfg->cbb->has_array_access = TRUE;
11417
11418                                         /* Needed so mono_emit_load_get_addr () gets called */
11419                                         mono_get_got_var (cfg);
11420                                 }
11421                         }
11422
11423                         len_ins = sp [0];
11424                         ip += 5;
11425                         *sp++ = ins;
11426                         inline_costs += 1;
11427
11428                         /* 
11429                          * we inline/optimize the initialization sequence if possible.
11430                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
11431                          * for small sizes open code the memcpy
11432                          * ensure the rva field is big enough
11433                          */
11434                         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))) {
11435                                 MonoMethod *memcpy_method = get_memcpy_method ();
11436                                 MonoInst *iargs [3];
11437                                 int add_reg = alloc_ireg_mp (cfg);
11438
11439                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, MONO_STRUCT_OFFSET (MonoArray, vector));
11440                                 if (cfg->compile_aot) {
11441                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
11442                                 } else {
11443                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
11444                                 }
11445                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
11446                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
11447                                 ip += 11;
11448                         }
11449
11450                         break;
11451                 }
11452                 case CEE_LDLEN:
11453                         CHECK_STACK (1);
11454                         --sp;
11455                         if (sp [0]->type != STACK_OBJ)
11456                                 UNVERIFIED;
11457
11458                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
11459                         ins->dreg = alloc_preg (cfg);
11460                         ins->sreg1 = sp [0]->dreg;
11461                         ins->type = STACK_I4;
11462                         /* This flag will be inherited by the decomposition */
11463                         ins->flags |= MONO_INST_FAULT;
11464                         MONO_ADD_INS (cfg->cbb, ins);
11465                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11466                         cfg->cbb->has_array_access = TRUE;
11467                         ip ++;
11468                         *sp++ = ins;
11469                         break;
11470                 case CEE_LDELEMA:
11471                         CHECK_STACK (2);
11472                         sp -= 2;
11473                         CHECK_OPSIZE (5);
11474                         if (sp [0]->type != STACK_OBJ)
11475                                 UNVERIFIED;
11476
11477                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11478
11479                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11480                         CHECK_TYPELOAD (klass);
11481                         /* we need to make sure that this array is exactly the type it needs
11482                          * to be for correctness. the wrappers are lax with their usage
11483                          * so we need to ignore them here
11484                          */
11485                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
11486                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11487                                 mini_emit_check_array_type (cfg, sp [0], array_class);
11488                                 CHECK_TYPELOAD (array_class);
11489                         }
11490
11491                         readonly = FALSE;
11492                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11493                         *sp++ = ins;
11494                         ip += 5;
11495                         break;
11496                 case CEE_LDELEM:
11497                 case CEE_LDELEM_I1:
11498                 case CEE_LDELEM_U1:
11499                 case CEE_LDELEM_I2:
11500                 case CEE_LDELEM_U2:
11501                 case CEE_LDELEM_I4:
11502                 case CEE_LDELEM_U4:
11503                 case CEE_LDELEM_I8:
11504                 case CEE_LDELEM_I:
11505                 case CEE_LDELEM_R4:
11506                 case CEE_LDELEM_R8:
11507                 case CEE_LDELEM_REF: {
11508                         MonoInst *addr;
11509
11510                         CHECK_STACK (2);
11511                         sp -= 2;
11512
11513                         if (*ip == CEE_LDELEM) {
11514                                 CHECK_OPSIZE (5);
11515                                 token = read32 (ip + 1);
11516                                 klass = mini_get_class (method, token, generic_context);
11517                                 CHECK_TYPELOAD (klass);
11518                                 mono_class_init (klass);
11519                         }
11520                         else
11521                                 klass = array_access_to_klass (*ip);
11522
11523                         if (sp [0]->type != STACK_OBJ)
11524                                 UNVERIFIED;
11525
11526                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11527
11528                         if (mini_is_gsharedvt_variable_klass (klass)) {
11529                                 // FIXME-VT: OP_ICONST optimization
11530                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11531                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11532                                 ins->opcode = OP_LOADV_MEMBASE;
11533                         } else if (sp [1]->opcode == OP_ICONST) {
11534                                 int array_reg = sp [0]->dreg;
11535                                 int index_reg = sp [1]->dreg;
11536                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
11537
11538                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
11539                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
11540                         } else {
11541                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11542                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11543                         }
11544                         *sp++ = ins;
11545                         if (*ip == CEE_LDELEM)
11546                                 ip += 5;
11547                         else
11548                                 ++ip;
11549                         break;
11550                 }
11551                 case CEE_STELEM_I:
11552                 case CEE_STELEM_I1:
11553                 case CEE_STELEM_I2:
11554                 case CEE_STELEM_I4:
11555                 case CEE_STELEM_I8:
11556                 case CEE_STELEM_R4:
11557                 case CEE_STELEM_R8:
11558                 case CEE_STELEM_REF:
11559                 case CEE_STELEM: {
11560                         CHECK_STACK (3);
11561                         sp -= 3;
11562
11563                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11564
11565                         if (*ip == CEE_STELEM) {
11566                                 CHECK_OPSIZE (5);
11567                                 token = read32 (ip + 1);
11568                                 klass = mini_get_class (method, token, generic_context);
11569                                 CHECK_TYPELOAD (klass);
11570                                 mono_class_init (klass);
11571                         }
11572                         else
11573                                 klass = array_access_to_klass (*ip);
11574
11575                         if (sp [0]->type != STACK_OBJ)
11576                                 UNVERIFIED;
11577
11578                         emit_array_store (cfg, klass, sp, TRUE);
11579
11580                         if (*ip == CEE_STELEM)
11581                                 ip += 5;
11582                         else
11583                                 ++ip;
11584                         inline_costs += 1;
11585                         break;
11586                 }
11587                 case CEE_CKFINITE: {
11588                         CHECK_STACK (1);
11589                         --sp;
11590
11591                         MONO_INST_NEW (cfg, ins, OP_CKFINITE);
11592                         ins->sreg1 = sp [0]->dreg;
11593                         ins->dreg = alloc_freg (cfg);
11594                         ins->type = STACK_R8;
11595                         MONO_ADD_INS (cfg->cbb, ins);
11596
11597                         *sp++ = mono_decompose_opcode (cfg, ins);
11598
11599                         ++ip;
11600                         break;
11601                 }
11602                 case CEE_REFANYVAL: {
11603                         MonoInst *src_var, *src;
11604
11605                         int klass_reg = alloc_preg (cfg);
11606                         int dreg = alloc_preg (cfg);
11607
11608                         GSHAREDVT_FAILURE (*ip);
11609
11610                         CHECK_STACK (1);
11611                         MONO_INST_NEW (cfg, ins, *ip);
11612                         --sp;
11613                         CHECK_OPSIZE (5);
11614                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11615                         CHECK_TYPELOAD (klass);
11616
11617                         context_used = mini_class_check_context_used (cfg, klass);
11618
11619                         // FIXME:
11620                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
11621                         if (!src_var)
11622                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
11623                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
11624                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass));
11625
11626                         if (context_used) {
11627                                 MonoInst *klass_ins;
11628
11629                                 klass_ins = emit_get_rgctx_klass (cfg, context_used,
11630                                                 klass, MONO_RGCTX_INFO_KLASS);
11631
11632                                 // FIXME:
11633                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
11634                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
11635                         } else {
11636                                 mini_emit_class_check (cfg, klass_reg, klass);
11637                         }
11638                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value));
11639                         ins->type = STACK_MP;
11640                         ins->klass = klass;
11641                         *sp++ = ins;
11642                         ip += 5;
11643                         break;
11644                 }
11645                 case CEE_MKREFANY: {
11646                         MonoInst *loc, *addr;
11647
11648                         GSHAREDVT_FAILURE (*ip);
11649
11650                         CHECK_STACK (1);
11651                         MONO_INST_NEW (cfg, ins, *ip);
11652                         --sp;
11653                         CHECK_OPSIZE (5);
11654                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11655                         CHECK_TYPELOAD (klass);
11656
11657                         context_used = mini_class_check_context_used (cfg, klass);
11658
11659                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
11660                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
11661
11662                         if (context_used) {
11663                                 MonoInst *const_ins;
11664                                 int type_reg = alloc_preg (cfg);
11665
11666                                 const_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
11667                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
11668                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11669                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11670                         } else if (cfg->compile_aot) {
11671                                 int const_reg = alloc_preg (cfg);
11672                                 int type_reg = alloc_preg (cfg);
11673
11674                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
11675                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
11676                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11677                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11678                         } else {
11679                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), &klass->byval_arg);
11680                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), klass);
11681                         }
11682                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
11683
11684                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
11685                         ins->type = STACK_VTYPE;
11686                         ins->klass = mono_defaults.typed_reference_class;
11687                         *sp++ = ins;
11688                         ip += 5;
11689                         break;
11690                 }
11691                 case CEE_LDTOKEN: {
11692                         gpointer handle;
11693                         MonoClass *handle_class;
11694
11695                         CHECK_STACK_OVF (1);
11696
11697                         CHECK_OPSIZE (5);
11698                         n = read32 (ip + 1);
11699
11700                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
11701                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
11702                                 handle = mono_method_get_wrapper_data (method, n);
11703                                 handle_class = mono_method_get_wrapper_data (method, n + 1);
11704                                 if (handle_class == mono_defaults.typehandle_class)
11705                                         handle = &((MonoClass*)handle)->byval_arg;
11706                         }
11707                         else {
11708                                 handle = mono_ldtoken_checked (image, n, &handle_class, generic_context, &cfg->error);
11709                                 CHECK_CFG_ERROR;
11710                         }
11711                         if (!handle)
11712                                 LOAD_ERROR;
11713                         mono_class_init (handle_class);
11714                         if (cfg->gshared) {
11715                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
11716                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
11717                                         /* This case handles ldtoken
11718                                            of an open type, like for
11719                                            typeof(Gen<>). */
11720                                         context_used = 0;
11721                                 } else if (handle_class == mono_defaults.typehandle_class) {
11722                                         context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type (handle));
11723                                 } else if (handle_class == mono_defaults.fieldhandle_class)
11724                                         context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
11725                                 else if (handle_class == mono_defaults.methodhandle_class)
11726                                         context_used = mini_method_check_context_used (cfg, handle);
11727                                 else
11728                                         g_assert_not_reached ();
11729                         }
11730
11731                         if ((cfg->opt & MONO_OPT_SHARED) &&
11732                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
11733                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
11734                                 MonoInst *addr, *vtvar, *iargs [3];
11735                                 int method_context_used;
11736
11737                                 method_context_used = mini_method_check_context_used (cfg, method);
11738
11739                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
11740
11741                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
11742                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
11743                                 if (method_context_used) {
11744                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
11745                                                 method, MONO_RGCTX_INFO_METHOD);
11746                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
11747                                 } else {
11748                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
11749                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
11750                                 }
11751                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11752
11753                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11754
11755                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11756                         } else {
11757                                 if ((ip + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 5) && 
11758                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
11759                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
11760                                         (cmethod->klass == mono_defaults.systemtype_class) &&
11761                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
11762                                         MonoClass *tclass = mono_class_from_mono_type (handle);
11763
11764                                         mono_class_init (tclass);
11765                                         if (context_used) {
11766                                                 ins = emit_get_rgctx_klass (cfg, context_used,
11767                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
11768                                         } else if (cfg->compile_aot) {
11769                                                 if (method->wrapper_type) {
11770                                                         mono_error_init (&error); //got to do it since there are multiple conditionals below
11771                                                         if (mono_class_get_checked (tclass->image, tclass->type_token, &error) == tclass && !generic_context) {
11772                                                                 /* Special case for static synchronized wrappers */
11773                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
11774                                                         } else {
11775                                                                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
11776                                                                 /* FIXME: n is not a normal token */
11777                                                                 DISABLE_AOT (cfg);
11778                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11779                                                         }
11780                                                 } else {
11781                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
11782                                                 }
11783                                         } else {
11784                                                 EMIT_NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
11785                                         }
11786                                         ins->type = STACK_OBJ;
11787                                         ins->klass = cmethod->klass;
11788                                         ip += 5;
11789                                 } else {
11790                                         MonoInst *addr, *vtvar;
11791
11792                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
11793
11794                                         if (context_used) {
11795                                                 if (handle_class == mono_defaults.typehandle_class) {
11796                                                         ins = emit_get_rgctx_klass (cfg, context_used,
11797                                                                         mono_class_from_mono_type (handle),
11798                                                                         MONO_RGCTX_INFO_TYPE);
11799                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
11800                                                         ins = emit_get_rgctx_method (cfg, context_used,
11801                                                                         handle, MONO_RGCTX_INFO_METHOD);
11802                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
11803                                                         ins = emit_get_rgctx_field (cfg, context_used,
11804                                                                         handle, MONO_RGCTX_INFO_CLASS_FIELD);
11805                                                 } else {
11806                                                         g_assert_not_reached ();
11807                                                 }
11808                                         } else if (cfg->compile_aot) {
11809                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n, generic_context);
11810                                         } else {
11811                                                 EMIT_NEW_PCONST (cfg, ins, handle);
11812                                         }
11813                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11814                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11815                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11816                                 }
11817                         }
11818
11819                         *sp++ = ins;
11820                         ip += 5;
11821                         break;
11822                 }
11823                 case CEE_THROW:
11824                         CHECK_STACK (1);
11825                         MONO_INST_NEW (cfg, ins, OP_THROW);
11826                         --sp;
11827                         ins->sreg1 = sp [0]->dreg;
11828                         ip++;
11829                         cfg->cbb->out_of_line = TRUE;
11830                         MONO_ADD_INS (cfg->cbb, ins);
11831                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
11832                         MONO_ADD_INS (cfg->cbb, ins);
11833                         sp = stack_start;
11834                         
11835                         link_bblock (cfg, cfg->cbb, end_bblock);
11836                         start_new_bblock = 1;
11837                         break;
11838                 case CEE_ENDFINALLY:
11839                         /* mono_save_seq_point_info () depends on this */
11840                         if (sp != stack_start)
11841                                 emit_seq_point (cfg, method, ip, FALSE, FALSE);
11842                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
11843                         MONO_ADD_INS (cfg->cbb, ins);
11844                         ip++;
11845                         start_new_bblock = 1;
11846
11847                         /*
11848                          * Control will leave the method so empty the stack, otherwise
11849                          * the next basic block will start with a nonempty stack.
11850                          */
11851                         while (sp != stack_start) {
11852                                 sp--;
11853                         }
11854                         break;
11855                 case CEE_LEAVE:
11856                 case CEE_LEAVE_S: {
11857                         GList *handlers;
11858
11859                         if (*ip == CEE_LEAVE) {
11860                                 CHECK_OPSIZE (5);
11861                                 target = ip + 5 + (gint32)read32(ip + 1);
11862                         } else {
11863                                 CHECK_OPSIZE (2);
11864                                 target = ip + 2 + (signed char)(ip [1]);
11865                         }
11866
11867                         /* empty the stack */
11868                         while (sp != stack_start) {
11869                                 sp--;
11870                         }
11871
11872                         /* 
11873                          * If this leave statement is in a catch block, check for a
11874                          * pending exception, and rethrow it if necessary.
11875                          * We avoid doing this in runtime invoke wrappers, since those are called
11876                          * by native code which excepts the wrapper to catch all exceptions.
11877                          */
11878                         for (i = 0; i < header->num_clauses; ++i) {
11879                                 MonoExceptionClause *clause = &header->clauses [i];
11880
11881                                 /* 
11882                                  * Use <= in the final comparison to handle clauses with multiple
11883                                  * leave statements, like in bug #78024.
11884                                  * The ordering of the exception clauses guarantees that we find the
11885                                  * innermost clause.
11886                                  */
11887                                 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) {
11888                                         MonoInst *exc_ins;
11889                                         MonoBasicBlock *dont_throw;
11890
11891                                         /*
11892                                           MonoInst *load;
11893
11894                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
11895                                         */
11896
11897                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
11898
11899                                         NEW_BBLOCK (cfg, dont_throw);
11900
11901                                         /*
11902                                          * Currently, we always rethrow the abort exception, despite the 
11903                                          * fact that this is not correct. See thread6.cs for an example. 
11904                                          * But propagating the abort exception is more important than 
11905                                          * getting the sematics right.
11906                                          */
11907                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
11908                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
11909                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
11910
11911                                         MONO_START_BB (cfg, dont_throw);
11912                                 }
11913                         }
11914
11915                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
11916                                 GList *tmp;
11917                                 MonoExceptionClause *clause;
11918
11919                                 for (tmp = handlers; tmp; tmp = tmp->next) {
11920                                         clause = tmp->data;
11921                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
11922                                         g_assert (tblock);
11923                                         link_bblock (cfg, cfg->cbb, tblock);
11924                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
11925                                         ins->inst_target_bb = tblock;
11926                                         ins->inst_eh_block = clause;
11927                                         MONO_ADD_INS (cfg->cbb, ins);
11928                                         cfg->cbb->has_call_handler = 1;
11929                                         if (COMPILE_LLVM (cfg)) {
11930                                                 MonoBasicBlock *target_bb;
11931
11932                                                 /* 
11933                                                  * Link the finally bblock with the target, since it will
11934                                                  * conceptually branch there.
11935                                                  * FIXME: Have to link the bblock containing the endfinally.
11936                                                  */
11937                                                 GET_BBLOCK (cfg, target_bb, target);
11938                                                 link_bblock (cfg, tblock, target_bb);
11939                                         }
11940                                 }
11941                                 g_list_free (handlers);
11942                         } 
11943
11944                         MONO_INST_NEW (cfg, ins, OP_BR);
11945                         MONO_ADD_INS (cfg->cbb, ins);
11946                         GET_BBLOCK (cfg, tblock, target);
11947                         link_bblock (cfg, cfg->cbb, tblock);
11948                         ins->inst_target_bb = tblock;
11949                         start_new_bblock = 1;
11950
11951                         if (*ip == CEE_LEAVE)
11952                                 ip += 5;
11953                         else
11954                                 ip += 2;
11955
11956                         break;
11957                 }
11958
11959                         /*
11960                          * Mono specific opcodes
11961                          */
11962                 case MONO_CUSTOM_PREFIX: {
11963
11964                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
11965
11966                         CHECK_OPSIZE (2);
11967                         switch (ip [1]) {
11968                         case CEE_MONO_ICALL: {
11969                                 gpointer func;
11970                                 MonoJitICallInfo *info;
11971
11972                                 token = read32 (ip + 2);
11973                                 func = mono_method_get_wrapper_data (method, token);
11974                                 info = mono_find_jit_icall_by_addr (func);
11975                                 if (!info)
11976                                         g_error ("Could not find icall address in wrapper %s", mono_method_full_name (method, 1));
11977                                 g_assert (info);
11978
11979                                 CHECK_STACK (info->sig->param_count);
11980                                 sp -= info->sig->param_count;
11981
11982                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
11983                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
11984                                         *sp++ = ins;
11985
11986                                 ip += 6;
11987                                 inline_costs += 10 * num_calls++;
11988
11989                                 break;
11990                         }
11991                         case CEE_MONO_LDPTR_CARD_TABLE: {
11992                                 int shift_bits;
11993                                 gpointer card_mask;
11994                                 CHECK_STACK_OVF (1);
11995
11996                                 if (cfg->compile_aot)
11997                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
11998                                 else
11999                                         EMIT_NEW_PCONST (cfg, ins, mono_gc_get_card_table (&shift_bits, &card_mask));
12000
12001                                 *sp++ = ins;
12002                                 ip += 2;
12003                                 inline_costs += 10 * num_calls++;
12004                                 break;
12005                         }
12006                         case CEE_MONO_LDPTR_NURSERY_START: {
12007                                 int shift_bits;
12008                                 size_t size;
12009                                 CHECK_STACK_OVF (1);
12010
12011                                 if (cfg->compile_aot)
12012                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_GC_NURSERY_START, NULL);
12013                                 else
12014                                         EMIT_NEW_PCONST (cfg, ins, mono_gc_get_nursery (&shift_bits, &size));
12015
12016                                 *sp++ = ins;
12017                                 ip += 2;
12018                                 inline_costs += 10 * num_calls++;
12019                                 break;
12020                         }
12021                         case CEE_MONO_LDPTR_INT_REQ_FLAG: {
12022                                 CHECK_STACK_OVF (1);
12023
12024                                 if (cfg->compile_aot)
12025                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
12026                                 else
12027                                         EMIT_NEW_PCONST (cfg, ins, mono_thread_interruption_request_flag ());
12028
12029                                 *sp++ = ins;
12030                                 ip += 2;
12031                                 inline_costs += 10 * num_calls++;
12032                                 break;
12033                         }
12034                         case CEE_MONO_LDPTR: {
12035                                 gpointer ptr;
12036
12037                                 CHECK_STACK_OVF (1);
12038                                 CHECK_OPSIZE (6);
12039                                 token = read32 (ip + 2);
12040
12041                                 ptr = mono_method_get_wrapper_data (method, token);
12042                                 EMIT_NEW_PCONST (cfg, ins, ptr);
12043                                 *sp++ = ins;
12044                                 ip += 6;
12045                                 inline_costs += 10 * num_calls++;
12046                                 /* Can't embed random pointers into AOT code */
12047                                 DISABLE_AOT (cfg);
12048                                 break;
12049                         }
12050                         case CEE_MONO_JIT_ICALL_ADDR: {
12051                                 MonoJitICallInfo *callinfo;
12052                                 gpointer ptr;
12053
12054                                 CHECK_STACK_OVF (1);
12055                                 CHECK_OPSIZE (6);
12056                                 token = read32 (ip + 2);
12057
12058                                 ptr = mono_method_get_wrapper_data (method, token);
12059                                 callinfo = mono_find_jit_icall_by_addr (ptr);
12060                                 g_assert (callinfo);
12061                                 EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
12062                                 *sp++ = ins;
12063                                 ip += 6;
12064                                 inline_costs += 10 * num_calls++;
12065                                 break;
12066                         }
12067                         case CEE_MONO_ICALL_ADDR: {
12068                                 MonoMethod *cmethod;
12069                                 gpointer ptr;
12070
12071                                 CHECK_STACK_OVF (1);
12072                                 CHECK_OPSIZE (6);
12073                                 token = read32 (ip + 2);
12074
12075                                 cmethod = mono_method_get_wrapper_data (method, token);
12076
12077                                 if (cfg->compile_aot) {
12078                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
12079                                 } else {
12080                                         ptr = mono_lookup_internal_call (cmethod);
12081                                         g_assert (ptr);
12082                                         EMIT_NEW_PCONST (cfg, ins, ptr);
12083                                 }
12084                                 *sp++ = ins;
12085                                 ip += 6;
12086                                 break;
12087                         }
12088                         case CEE_MONO_VTADDR: {
12089                                 MonoInst *src_var, *src;
12090
12091                                 CHECK_STACK (1);
12092                                 --sp;
12093
12094                                 // FIXME:
12095                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12096                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
12097                                 *sp++ = src;
12098                                 ip += 2;
12099                                 break;
12100                         }
12101                         case CEE_MONO_NEWOBJ: {
12102                                 MonoInst *iargs [2];
12103
12104                                 CHECK_STACK_OVF (1);
12105                                 CHECK_OPSIZE (6);
12106                                 token = read32 (ip + 2);
12107                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12108                                 mono_class_init (klass);
12109                                 NEW_DOMAINCONST (cfg, iargs [0]);
12110                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
12111                                 NEW_CLASSCONST (cfg, iargs [1], klass);
12112                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
12113                                 *sp++ = mono_emit_jit_icall (cfg, mono_object_new, iargs);
12114                                 ip += 6;
12115                                 inline_costs += 10 * num_calls++;
12116                                 break;
12117                         }
12118                         case CEE_MONO_OBJADDR:
12119                                 CHECK_STACK (1);
12120                                 --sp;
12121                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
12122                                 ins->dreg = alloc_ireg_mp (cfg);
12123                                 ins->sreg1 = sp [0]->dreg;
12124                                 ins->type = STACK_MP;
12125                                 MONO_ADD_INS (cfg->cbb, ins);
12126                                 *sp++ = ins;
12127                                 ip += 2;
12128                                 break;
12129                         case CEE_MONO_LDNATIVEOBJ:
12130                                 /*
12131                                  * Similar to LDOBJ, but instead load the unmanaged 
12132                                  * representation of the vtype to the stack.
12133                                  */
12134                                 CHECK_STACK (1);
12135                                 CHECK_OPSIZE (6);
12136                                 --sp;
12137                                 token = read32 (ip + 2);
12138                                 klass = mono_method_get_wrapper_data (method, token);
12139                                 g_assert (klass->valuetype);
12140                                 mono_class_init (klass);
12141
12142                                 {
12143                                         MonoInst *src, *dest, *temp;
12144
12145                                         src = sp [0];
12146                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
12147                                         temp->backend.is_pinvoke = 1;
12148                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
12149                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
12150
12151                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
12152                                         dest->type = STACK_VTYPE;
12153                                         dest->klass = klass;
12154
12155                                         *sp ++ = dest;
12156                                         ip += 6;
12157                                 }
12158                                 break;
12159                         case CEE_MONO_RETOBJ: {
12160                                 /*
12161                                  * Same as RET, but return the native representation of a vtype
12162                                  * to the caller.
12163                                  */
12164                                 g_assert (cfg->ret);
12165                                 g_assert (mono_method_signature (method)->pinvoke); 
12166                                 CHECK_STACK (1);
12167                                 --sp;
12168                                 
12169                                 CHECK_OPSIZE (6);
12170                                 token = read32 (ip + 2);    
12171                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12172
12173                                 if (!cfg->vret_addr) {
12174                                         g_assert (cfg->ret_var_is_local);
12175
12176                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
12177                                 } else {
12178                                         EMIT_NEW_RETLOADA (cfg, ins);
12179                                 }
12180                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
12181                                 
12182                                 if (sp != stack_start)
12183                                         UNVERIFIED;
12184                                 
12185                                 MONO_INST_NEW (cfg, ins, OP_BR);
12186                                 ins->inst_target_bb = end_bblock;
12187                                 MONO_ADD_INS (cfg->cbb, ins);
12188                                 link_bblock (cfg, cfg->cbb, end_bblock);
12189                                 start_new_bblock = 1;
12190                                 ip += 6;
12191                                 break;
12192                         }
12193                         case CEE_MONO_CISINST:
12194                         case CEE_MONO_CCASTCLASS: {
12195                                 int token;
12196                                 CHECK_STACK (1);
12197                                 --sp;
12198                                 CHECK_OPSIZE (6);
12199                                 token = read32 (ip + 2);
12200                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12201                                 if (ip [1] == CEE_MONO_CISINST)
12202                                         ins = handle_cisinst (cfg, klass, sp [0]);
12203                                 else
12204                                         ins = handle_ccastclass (cfg, klass, sp [0]);
12205                                 *sp++ = ins;
12206                                 ip += 6;
12207                                 break;
12208                         }
12209                         case CEE_MONO_SAVE_LMF:
12210                         case CEE_MONO_RESTORE_LMF:
12211 #ifdef MONO_ARCH_HAVE_LMF_OPS
12212                                 MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_SAVE_LMF) ? OP_SAVE_LMF : OP_RESTORE_LMF);
12213                                 MONO_ADD_INS (cfg->cbb, ins);
12214                                 cfg->need_lmf_area = TRUE;
12215 #endif
12216                                 ip += 2;
12217                                 break;
12218                         case CEE_MONO_CLASSCONST:
12219                                 CHECK_STACK_OVF (1);
12220                                 CHECK_OPSIZE (6);
12221                                 token = read32 (ip + 2);
12222                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
12223                                 *sp++ = ins;
12224                                 ip += 6;
12225                                 inline_costs += 10 * num_calls++;
12226                                 break;
12227                         case CEE_MONO_NOT_TAKEN:
12228                                 cfg->cbb->out_of_line = TRUE;
12229                                 ip += 2;
12230                                 break;
12231                         case CEE_MONO_TLS: {
12232                                 int key;
12233
12234                                 CHECK_STACK_OVF (1);
12235                                 CHECK_OPSIZE (6);
12236                                 key = (gint32)read32 (ip + 2);
12237                                 g_assert (key < TLS_KEY_NUM);
12238
12239                                 ins = mono_create_tls_get (cfg, key);
12240                                 if (!ins) {
12241                                         if (cfg->compile_aot) {
12242                                                 DISABLE_AOT (cfg);
12243                                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
12244                                                 ins->dreg = alloc_preg (cfg);
12245                                                 ins->type = STACK_PTR;
12246                                         } else {
12247                                                 g_assert_not_reached ();
12248                                         }
12249                                 }
12250                                 ins->type = STACK_PTR;
12251                                 MONO_ADD_INS (cfg->cbb, ins);
12252                                 *sp++ = ins;
12253                                 ip += 6;
12254                                 break;
12255                         }
12256                         case CEE_MONO_DYN_CALL: {
12257                                 MonoCallInst *call;
12258
12259                                 /* It would be easier to call a trampoline, but that would put an
12260                                  * extra frame on the stack, confusing exception handling. So
12261                                  * implement it inline using an opcode for now.
12262                                  */
12263
12264                                 if (!cfg->dyn_call_var) {
12265                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12266                                         /* prevent it from being register allocated */
12267                                         cfg->dyn_call_var->flags |= MONO_INST_VOLATILE;
12268                                 }
12269
12270                                 /* Has to use a call inst since it local regalloc expects it */
12271                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
12272                                 ins = (MonoInst*)call;
12273                                 sp -= 2;
12274                                 ins->sreg1 = sp [0]->dreg;
12275                                 ins->sreg2 = sp [1]->dreg;
12276                                 MONO_ADD_INS (cfg->cbb, ins);
12277
12278                                 cfg->param_area = MAX (cfg->param_area, MONO_ARCH_DYN_CALL_PARAM_AREA);
12279
12280                                 ip += 2;
12281                                 inline_costs += 10 * num_calls++;
12282
12283                                 break;
12284                         }
12285                         case CEE_MONO_MEMORY_BARRIER: {
12286                                 CHECK_OPSIZE (6);
12287                                 emit_memory_barrier (cfg, (int)read32 (ip + 2));
12288                                 ip += 6;
12289                                 break;
12290                         }
12291                         case CEE_MONO_JIT_ATTACH: {
12292                                 MonoInst *args [16], *domain_ins;
12293                                 MonoInst *ad_ins, *jit_tls_ins;
12294                                 MonoBasicBlock *next_bb = NULL, *call_bb = NULL;
12295
12296                                 cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12297
12298                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12299                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12300
12301                                 ad_ins = mono_get_domain_intrinsic (cfg);
12302                                 jit_tls_ins = mono_get_jit_tls_intrinsic (cfg);
12303
12304                                 if (MONO_ARCH_HAVE_TLS_GET && ad_ins && jit_tls_ins) {
12305                                         NEW_BBLOCK (cfg, next_bb);
12306                                         NEW_BBLOCK (cfg, call_bb);
12307
12308                                         if (cfg->compile_aot) {
12309                                                 /* AOT code is only used in the root domain */
12310                                                 EMIT_NEW_PCONST (cfg, domain_ins, NULL);
12311                                         } else {
12312                                                 EMIT_NEW_PCONST (cfg, domain_ins, cfg->domain);
12313                                         }
12314                                         MONO_ADD_INS (cfg->cbb, ad_ins);
12315                                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, ad_ins->dreg, domain_ins->dreg);
12316                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, call_bb);
12317
12318                                         MONO_ADD_INS (cfg->cbb, jit_tls_ins);
12319                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, jit_tls_ins->dreg, 0);
12320                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, call_bb);
12321
12322                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, next_bb);
12323                                         MONO_START_BB (cfg, call_bb);
12324                                 }
12325
12326                                 if (cfg->compile_aot) {
12327                                         /* AOT code is only used in the root domain */
12328                                         EMIT_NEW_PCONST (cfg, args [0], NULL);
12329                                 } else {
12330                                         EMIT_NEW_PCONST (cfg, args [0], cfg->domain);
12331                                 }
12332                                 ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
12333                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12334
12335                                 if (next_bb)
12336                                         MONO_START_BB (cfg, next_bb);
12337                                 ip += 2;
12338                                 break;
12339                         }
12340                         case CEE_MONO_JIT_DETACH: {
12341                                 MonoInst *args [16];
12342
12343                                 /* Restore the original domain */
12344                                 dreg = alloc_ireg (cfg);
12345                                 EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->orig_domain_var->dreg);
12346                                 mono_emit_jit_icall (cfg, mono_jit_set_domain, args);
12347                                 ip += 2;
12348                                 break;
12349                         }
12350                         default:
12351                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
12352                                 break;
12353                         }
12354                         break;
12355                 }
12356
12357                 case CEE_PREFIX1: {
12358                         CHECK_OPSIZE (2);
12359                         switch (ip [1]) {
12360                         case CEE_ARGLIST: {
12361                                 /* somewhat similar to LDTOKEN */
12362                                 MonoInst *addr, *vtvar;
12363                                 CHECK_STACK_OVF (1);
12364                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
12365
12366                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12367                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
12368
12369                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12370                                 ins->type = STACK_VTYPE;
12371                                 ins->klass = mono_defaults.argumenthandle_class;
12372                                 *sp++ = ins;
12373                                 ip += 2;
12374                                 break;
12375                         }
12376                         case CEE_CEQ:
12377                         case CEE_CGT:
12378                         case CEE_CGT_UN:
12379                         case CEE_CLT:
12380                         case CEE_CLT_UN: {
12381                                 MonoInst *cmp, *arg1, *arg2;
12382
12383                                 CHECK_STACK (2);
12384                                 sp -= 2;
12385                                 arg1 = sp [0];
12386                                 arg2 = sp [1];
12387
12388                                 /*
12389                                  * The following transforms:
12390                                  *    CEE_CEQ    into OP_CEQ
12391                                  *    CEE_CGT    into OP_CGT
12392                                  *    CEE_CGT_UN into OP_CGT_UN
12393                                  *    CEE_CLT    into OP_CLT
12394                                  *    CEE_CLT_UN into OP_CLT_UN
12395                                  */
12396                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
12397
12398                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
12399                                 cmp->sreg1 = arg1->dreg;
12400                                 cmp->sreg2 = arg2->dreg;
12401                                 type_from_op (cfg, cmp, arg1, arg2);
12402                                 CHECK_TYPE (cmp);
12403                                 add_widen_op (cfg, cmp, &arg1, &arg2);
12404                                 if ((arg1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((arg1->type == STACK_PTR) || (arg1->type == STACK_OBJ) || (arg1->type == STACK_MP))))
12405                                         cmp->opcode = OP_LCOMPARE;
12406                                 else if (arg1->type == STACK_R4)
12407                                         cmp->opcode = OP_RCOMPARE;
12408                                 else if (arg1->type == STACK_R8)
12409                                         cmp->opcode = OP_FCOMPARE;
12410                                 else
12411                                         cmp->opcode = OP_ICOMPARE;
12412                                 MONO_ADD_INS (cfg->cbb, cmp);
12413                                 ins->type = STACK_I4;
12414                                 ins->dreg = alloc_dreg (cfg, ins->type);
12415                                 type_from_op (cfg, ins, arg1, arg2);
12416
12417                                 if (cmp->opcode == OP_FCOMPARE || cmp->opcode == OP_RCOMPARE) {
12418                                         /*
12419                                          * The backends expect the fceq opcodes to do the
12420                                          * comparison too.
12421                                          */
12422                                         ins->sreg1 = cmp->sreg1;
12423                                         ins->sreg2 = cmp->sreg2;
12424                                         NULLIFY_INS (cmp);
12425                                 }
12426                                 MONO_ADD_INS (cfg->cbb, ins);
12427                                 *sp++ = ins;
12428                                 ip += 2;
12429                                 break;
12430                         }
12431                         case CEE_LDFTN: {
12432                                 MonoInst *argconst;
12433                                 MonoMethod *cil_method;
12434
12435                                 CHECK_STACK_OVF (1);
12436                                 CHECK_OPSIZE (6);
12437                                 n = read32 (ip + 2);
12438                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12439                                 if (!cmethod || mono_loader_get_last_error ())
12440                                         LOAD_ERROR;
12441                                 mono_class_init (cmethod->klass);
12442
12443                                 mono_save_token_info (cfg, image, n, cmethod);
12444
12445                                 context_used = mini_method_check_context_used (cfg, cmethod);
12446
12447                                 cil_method = cmethod;
12448                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
12449                                         METHOD_ACCESS_FAILURE (method, cil_method);
12450
12451                                 if (mono_security_core_clr_enabled ())
12452                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
12453
12454                                 /* 
12455                                  * Optimize the common case of ldftn+delegate creation
12456                                  */
12457                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
12458                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12459                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12460                                                 MonoInst *target_ins, *handle_ins;
12461                                                 MonoMethod *invoke;
12462                                                 int invoke_context_used;
12463
12464                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12465                                                 if (!invoke || !mono_method_signature (invoke))
12466                                                         LOAD_ERROR;
12467
12468                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12469
12470                                                 target_ins = sp [-1];
12471
12472                                                 if (mono_security_core_clr_enabled ())
12473                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
12474
12475                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
12476                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
12477                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
12478                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
12479                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
12480                                                         }
12481                                                 }
12482
12483                                                 /* FIXME: SGEN support */
12484                                                 if (invoke_context_used == 0) {
12485                                                         ip += 6;
12486                                                         if (cfg->verbose_level > 3)
12487                                                                 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));
12488                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, FALSE))) {
12489                                                                 sp --;
12490                                                                 *sp = handle_ins;
12491                                                                 CHECK_CFG_EXCEPTION;
12492                                                                 ip += 5;
12493                                                                 sp ++;
12494                                                                 break;
12495                                                         }
12496                                                         ip -= 6;
12497                                                 }
12498                                         }
12499                                 }
12500
12501                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
12502                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
12503                                 *sp++ = ins;
12504                                 
12505                                 ip += 6;
12506                                 inline_costs += 10 * num_calls++;
12507                                 break;
12508                         }
12509                         case CEE_LDVIRTFTN: {
12510                                 MonoInst *args [2];
12511
12512                                 CHECK_STACK (1);
12513                                 CHECK_OPSIZE (6);
12514                                 n = read32 (ip + 2);
12515                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12516                                 if (!cmethod || mono_loader_get_last_error ())
12517                                         LOAD_ERROR;
12518                                 mono_class_init (cmethod->klass);
12519  
12520                                 context_used = mini_method_check_context_used (cfg, cmethod);
12521
12522                                 if (mono_security_core_clr_enabled ())
12523                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
12524
12525                                 /*
12526                                  * Optimize the common case of ldvirtftn+delegate creation
12527                                  */
12528                                 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)) {
12529                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12530                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12531                                                 MonoInst *target_ins, *handle_ins;
12532                                                 MonoMethod *invoke;
12533                                                 int invoke_context_used;
12534                                                 gboolean is_virtual = cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL;
12535
12536                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12537                                                 if (!invoke || !mono_method_signature (invoke))
12538                                                         LOAD_ERROR;
12539
12540                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12541
12542                                                 target_ins = sp [-1];
12543
12544                                                 if (mono_security_core_clr_enabled ())
12545                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
12546
12547                                                 /* FIXME: SGEN support */
12548                                                 if (invoke_context_used == 0) {
12549                                                         ip += 6;
12550                                                         if (cfg->verbose_level > 3)
12551                                                                 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));
12552                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, is_virtual))) {
12553                                                                 sp -= 2;
12554                                                                 *sp = handle_ins;
12555                                                                 CHECK_CFG_EXCEPTION;
12556                                                                 ip += 5;
12557                                                                 sp ++;
12558                                                                 break;
12559                                                         }
12560                                                         ip -= 6;
12561                                                 }
12562                                         }
12563                                 }
12564
12565                                 --sp;
12566                                 args [0] = *sp;
12567
12568                                 args [1] = emit_get_rgctx_method (cfg, context_used,
12569                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
12570
12571                                 if (context_used)
12572                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
12573                                 else
12574                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
12575
12576                                 ip += 6;
12577                                 inline_costs += 10 * num_calls++;
12578                                 break;
12579                         }
12580                         case CEE_LDARG:
12581                                 CHECK_STACK_OVF (1);
12582                                 CHECK_OPSIZE (4);
12583                                 n = read16 (ip + 2);
12584                                 CHECK_ARG (n);
12585                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
12586                                 *sp++ = ins;
12587                                 ip += 4;
12588                                 break;
12589                         case CEE_LDARGA:
12590                                 CHECK_STACK_OVF (1);
12591                                 CHECK_OPSIZE (4);
12592                                 n = read16 (ip + 2);
12593                                 CHECK_ARG (n);
12594                                 NEW_ARGLOADA (cfg, ins, n);
12595                                 MONO_ADD_INS (cfg->cbb, ins);
12596                                 *sp++ = ins;
12597                                 ip += 4;
12598                                 break;
12599                         case CEE_STARG:
12600                                 CHECK_STACK (1);
12601                                 --sp;
12602                                 CHECK_OPSIZE (4);
12603                                 n = read16 (ip + 2);
12604                                 CHECK_ARG (n);
12605                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
12606                                         UNVERIFIED;
12607                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
12608                                 ip += 4;
12609                                 break;
12610                         case CEE_LDLOC:
12611                                 CHECK_STACK_OVF (1);
12612                                 CHECK_OPSIZE (4);
12613                                 n = read16 (ip + 2);
12614                                 CHECK_LOCAL (n);
12615                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
12616                                 *sp++ = ins;
12617                                 ip += 4;
12618                                 break;
12619                         case CEE_LDLOCA: {
12620                                 unsigned char *tmp_ip;
12621                                 CHECK_STACK_OVF (1);
12622                                 CHECK_OPSIZE (4);
12623                                 n = read16 (ip + 2);
12624                                 CHECK_LOCAL (n);
12625
12626                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
12627                                         ip = tmp_ip;
12628                                         inline_costs += 1;
12629                                         break;
12630                                 }                       
12631                                 
12632                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
12633                                 *sp++ = ins;
12634                                 ip += 4;
12635                                 break;
12636                         }
12637                         case CEE_STLOC:
12638                                 CHECK_STACK (1);
12639                                 --sp;
12640                                 CHECK_OPSIZE (4);
12641                                 n = read16 (ip + 2);
12642                                 CHECK_LOCAL (n);
12643                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
12644                                         UNVERIFIED;
12645                                 emit_stloc_ir (cfg, sp, header, n);
12646                                 ip += 4;
12647                                 inline_costs += 1;
12648                                 break;
12649                         case CEE_LOCALLOC:
12650                                 CHECK_STACK (1);
12651                                 --sp;
12652                                 if (sp != stack_start) 
12653                                         UNVERIFIED;
12654                                 if (cfg->method != method) 
12655                                         /* 
12656                                          * Inlining this into a loop in a parent could lead to 
12657                                          * stack overflows which is different behavior than the
12658                                          * non-inlined case, thus disable inlining in this case.
12659                                          */
12660                                         INLINE_FAILURE("localloc");
12661
12662                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
12663                                 ins->dreg = alloc_preg (cfg);
12664                                 ins->sreg1 = sp [0]->dreg;
12665                                 ins->type = STACK_PTR;
12666                                 MONO_ADD_INS (cfg->cbb, ins);
12667
12668                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12669                                 if (init_locals)
12670                                         ins->flags |= MONO_INST_INIT;
12671
12672                                 *sp++ = ins;
12673                                 ip += 2;
12674                                 break;
12675                         case CEE_ENDFILTER: {
12676                                 MonoExceptionClause *clause, *nearest;
12677                                 int cc;
12678
12679                                 CHECK_STACK (1);
12680                                 --sp;
12681                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
12682                                         UNVERIFIED;
12683                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
12684                                 ins->sreg1 = (*sp)->dreg;
12685                                 MONO_ADD_INS (cfg->cbb, ins);
12686                                 start_new_bblock = 1;
12687                                 ip += 2;
12688
12689                                 nearest = NULL;
12690                                 for (cc = 0; cc < header->num_clauses; ++cc) {
12691                                         clause = &header->clauses [cc];
12692                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
12693                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
12694                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset)))
12695                                                 nearest = clause;
12696                                 }
12697                                 g_assert (nearest);
12698                                 if ((ip - header->code) != nearest->handler_offset)
12699                                         UNVERIFIED;
12700
12701                                 break;
12702                         }
12703                         case CEE_UNALIGNED_:
12704                                 ins_flag |= MONO_INST_UNALIGNED;
12705                                 /* FIXME: record alignment? we can assume 1 for now */
12706                                 CHECK_OPSIZE (3);
12707                                 ip += 3;
12708                                 break;
12709                         case CEE_VOLATILE_:
12710                                 ins_flag |= MONO_INST_VOLATILE;
12711                                 ip += 2;
12712                                 break;
12713                         case CEE_TAIL_:
12714                                 ins_flag   |= MONO_INST_TAILCALL;
12715                                 cfg->flags |= MONO_CFG_HAS_TAIL;
12716                                 /* Can't inline tail calls at this time */
12717                                 inline_costs += 100000;
12718                                 ip += 2;
12719                                 break;
12720                         case CEE_INITOBJ:
12721                                 CHECK_STACK (1);
12722                                 --sp;
12723                                 CHECK_OPSIZE (6);
12724                                 token = read32 (ip + 2);
12725                                 klass = mini_get_class (method, token, generic_context);
12726                                 CHECK_TYPELOAD (klass);
12727                                 if (generic_class_is_reference_type (cfg, klass))
12728                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
12729                                 else
12730                                         mini_emit_initobj (cfg, *sp, NULL, klass);
12731                                 ip += 6;
12732                                 inline_costs += 1;
12733                                 break;
12734                         case CEE_CONSTRAINED_:
12735                                 CHECK_OPSIZE (6);
12736                                 token = read32 (ip + 2);
12737                                 constrained_class = mini_get_class (method, token, generic_context);
12738                                 CHECK_TYPELOAD (constrained_class);
12739                                 ip += 6;
12740                                 break;
12741                         case CEE_CPBLK:
12742                         case CEE_INITBLK: {
12743                                 MonoInst *iargs [3];
12744                                 CHECK_STACK (3);
12745                                 sp -= 3;
12746
12747                                 /* Skip optimized paths for volatile operations. */
12748                                 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)) {
12749                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
12750                                 } 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)) {
12751                                         /* emit_memset only works when val == 0 */
12752                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
12753                                 } else {
12754                                         MonoInst *call;
12755                                         iargs [0] = sp [0];
12756                                         iargs [1] = sp [1];
12757                                         iargs [2] = sp [2];
12758                                         if (ip [1] == CEE_CPBLK) {
12759                                                 /*
12760                                                  * FIXME: It's unclear whether we should be emitting both the acquire
12761                                                  * and release barriers for cpblk. It is technically both a load and
12762                                                  * store operation, so it seems like that's the sensible thing to do.
12763                                                  *
12764                                                  * FIXME: We emit full barriers on both sides of the operation for
12765                                                  * simplicity. We should have a separate atomic memcpy method instead.
12766                                                  */
12767                                                 MonoMethod *memcpy_method = get_memcpy_method ();
12768
12769                                                 if (ins_flag & MONO_INST_VOLATILE)
12770                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12771
12772                                                 call = mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
12773                                                 call->flags |= ins_flag;
12774
12775                                                 if (ins_flag & MONO_INST_VOLATILE)
12776                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12777                                         } else {
12778                                                 MonoMethod *memset_method = get_memset_method ();
12779                                                 if (ins_flag & MONO_INST_VOLATILE) {
12780                                                         /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
12781                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
12782                                                 }
12783                                                 call = mono_emit_method_call (cfg, memset_method, iargs, NULL);
12784                                                 call->flags |= ins_flag;
12785                                         }
12786                                 }
12787                                 ip += 2;
12788                                 ins_flag = 0;
12789                                 inline_costs += 1;
12790                                 break;
12791                         }
12792                         case CEE_NO_:
12793                                 CHECK_OPSIZE (3);
12794                                 if (ip [2] & 0x1)
12795                                         ins_flag |= MONO_INST_NOTYPECHECK;
12796                                 if (ip [2] & 0x2)
12797                                         ins_flag |= MONO_INST_NORANGECHECK;
12798                                 /* we ignore the no-nullcheck for now since we
12799                                  * really do it explicitly only when doing callvirt->call
12800                                  */
12801                                 ip += 3;
12802                                 break;
12803                         case CEE_RETHROW: {
12804                                 MonoInst *load;
12805                                 int handler_offset = -1;
12806
12807                                 for (i = 0; i < header->num_clauses; ++i) {
12808                                         MonoExceptionClause *clause = &header->clauses [i];
12809                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
12810                                                 handler_offset = clause->handler_offset;
12811                                                 break;
12812                                         }
12813                                 }
12814
12815                                 cfg->cbb->flags |= BB_EXCEPTION_UNSAFE;
12816
12817                                 if (handler_offset == -1)
12818                                         UNVERIFIED;
12819
12820                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
12821                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
12822                                 ins->sreg1 = load->dreg;
12823                                 MONO_ADD_INS (cfg->cbb, ins);
12824
12825                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
12826                                 MONO_ADD_INS (cfg->cbb, ins);
12827
12828                                 sp = stack_start;
12829                                 link_bblock (cfg, cfg->cbb, end_bblock);
12830                                 start_new_bblock = 1;
12831                                 ip += 2;
12832                                 break;
12833                         }
12834                         case CEE_SIZEOF: {
12835                                 guint32 val;
12836                                 int ialign;
12837
12838                                 CHECK_STACK_OVF (1);
12839                                 CHECK_OPSIZE (6);
12840                                 token = read32 (ip + 2);
12841                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !image_is_dynamic (method->klass->image) && !generic_context) {
12842                                         MonoType *type = mono_type_create_from_typespec_checked (image, token, &cfg->error);
12843                                         CHECK_CFG_ERROR;
12844
12845                                         val = mono_type_size (type, &ialign);
12846                                 } else {
12847                                         MonoClass *klass = mini_get_class (method, token, generic_context);
12848                                         CHECK_TYPELOAD (klass);
12849
12850                                         val = mono_type_size (&klass->byval_arg, &ialign);
12851
12852                                         if (mini_is_gsharedvt_klass (klass))
12853                                                 GSHAREDVT_FAILURE (*ip);
12854                                 }
12855                                 EMIT_NEW_ICONST (cfg, ins, val);
12856                                 *sp++= ins;
12857                                 ip += 6;
12858                                 break;
12859                         }
12860                         case CEE_REFANYTYPE: {
12861                                 MonoInst *src_var, *src;
12862
12863                                 GSHAREDVT_FAILURE (*ip);
12864
12865                                 CHECK_STACK (1);
12866                                 --sp;
12867
12868                                 // FIXME:
12869                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12870                                 if (!src_var)
12871                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
12872                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
12873                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type));
12874                                 *sp++ = ins;
12875                                 ip += 2;
12876                                 break;
12877                         }
12878                         case CEE_READONLY_:
12879                                 readonly = TRUE;
12880                                 ip += 2;
12881                                 break;
12882
12883                         case CEE_UNUSED56:
12884                         case CEE_UNUSED57:
12885                         case CEE_UNUSED70:
12886                         case CEE_UNUSED:
12887                         case CEE_UNUSED99:
12888                                 UNVERIFIED;
12889                                 
12890                         default:
12891                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
12892                                 UNVERIFIED;
12893                         }
12894                         break;
12895                 }
12896                 case CEE_UNUSED58:
12897                 case CEE_UNUSED1:
12898                         UNVERIFIED;
12899
12900                 default:
12901                         g_warning ("opcode 0x%02x not handled", *ip);
12902                         UNVERIFIED;
12903                 }
12904         }
12905         if (start_new_bblock != 1)
12906                 UNVERIFIED;
12907
12908         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
12909         if (cfg->cbb->next_bb) {
12910                 /* This could already be set because of inlining, #693905 */
12911                 MonoBasicBlock *bb = cfg->cbb;
12912
12913                 while (bb->next_bb)
12914                         bb = bb->next_bb;
12915                 bb->next_bb = end_bblock;
12916         } else {
12917                 cfg->cbb->next_bb = end_bblock;
12918         }
12919
12920         if (cfg->method == method && cfg->domainvar) {
12921                 MonoInst *store;
12922                 MonoInst *get_domain;
12923
12924                 cfg->cbb = init_localsbb;
12925
12926                 if ((get_domain = mono_get_domain_intrinsic (cfg))) {
12927                         MONO_ADD_INS (cfg->cbb, get_domain);
12928                 } else {
12929                         get_domain = mono_emit_jit_icall (cfg, mono_domain_get, NULL);
12930                 }
12931                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
12932                 MONO_ADD_INS (cfg->cbb, store);
12933         }
12934
12935 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
12936         if (cfg->compile_aot)
12937                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
12938                 mono_get_got_var (cfg);
12939 #endif
12940
12941         if (cfg->method == method && cfg->got_var)
12942                 mono_emit_load_got_addr (cfg);
12943
12944         if (init_localsbb) {
12945                 cfg->cbb = init_localsbb;
12946                 cfg->ip = NULL;
12947                 for (i = 0; i < header->num_locals; ++i) {
12948                         emit_init_local (cfg, i, header->locals [i], init_locals);
12949                 }
12950         }
12951
12952         if (cfg->init_ref_vars && cfg->method == method) {
12953                 /* Emit initialization for ref vars */
12954                 // FIXME: Avoid duplication initialization for IL locals.
12955                 for (i = 0; i < cfg->num_varinfo; ++i) {
12956                         MonoInst *ins = cfg->varinfo [i];
12957
12958                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
12959                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
12960                 }
12961         }
12962
12963         if (cfg->lmf_var && cfg->method == method) {
12964                 cfg->cbb = init_localsbb;
12965                 emit_push_lmf (cfg);
12966         }
12967
12968         cfg->cbb = init_localsbb;
12969         emit_instrumentation_call (cfg, mono_profiler_method_enter);
12970
12971         if (seq_points) {
12972                 MonoBasicBlock *bb;
12973
12974                 /*
12975                  * Make seq points at backward branch targets interruptable.
12976                  */
12977                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
12978                         if (bb->code && bb->in_count > 1 && bb->code->opcode == OP_SEQ_POINT)
12979                                 bb->code->flags |= MONO_INST_SINGLE_STEP_LOC;
12980         }
12981
12982         /* Add a sequence point for method entry/exit events */
12983         if (seq_points && cfg->gen_sdb_seq_points) {
12984                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
12985                 MONO_ADD_INS (init_localsbb, ins);
12986                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
12987                 MONO_ADD_INS (cfg->bb_exit, ins);
12988         }
12989
12990         /*
12991          * Add seq points for IL offsets which have line number info, but wasn't generated a seq point during JITting because
12992          * the code they refer to was dead (#11880).
12993          */
12994         if (sym_seq_points) {
12995                 for (i = 0; i < header->code_size; ++i) {
12996                         if (mono_bitset_test_fast (seq_point_locs, i) && !mono_bitset_test_fast (seq_point_set_locs, i)) {
12997                                 MonoInst *ins;
12998
12999                                 NEW_SEQ_POINT (cfg, ins, i, FALSE);
13000                                 mono_add_seq_point (cfg, NULL, ins, SEQ_POINT_NATIVE_OFFSET_DEAD_CODE);
13001                         }
13002                 }
13003         }
13004
13005         cfg->ip = NULL;
13006
13007         if (cfg->method == method) {
13008                 MonoBasicBlock *bb;
13009                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13010                         bb->region = mono_find_block_region (cfg, bb->real_offset);
13011                         if (cfg->spvars)
13012                                 mono_create_spvar_for_region (cfg, bb->region);
13013                         if (cfg->verbose_level > 2)
13014                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
13015                 }
13016         }
13017
13018         if (inline_costs < 0) {
13019                 char *mname;
13020
13021                 /* Method is too large */
13022                 mname = mono_method_full_name (method, TRUE);
13023                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
13024                 cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
13025                 g_free (mname);
13026         }
13027
13028         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
13029                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
13030
13031         goto cleanup;
13032
13033 mono_error_exit:
13034         g_assert (!mono_error_ok (&cfg->error));
13035         goto cleanup;
13036  
13037  exception_exit:
13038         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
13039         goto cleanup;
13040
13041  unverified:
13042         set_exception_type_from_invalid_il (cfg, method, ip);
13043         goto cleanup;
13044
13045  cleanup:
13046         g_slist_free (class_inits);
13047         mono_basic_block_free (original_bb);
13048         cfg->dont_inline = g_list_remove (cfg->dont_inline, method);
13049         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
13050         if (cfg->exception_type)
13051                 return -1;
13052         else
13053                 return inline_costs;
13054 }
13055
13056 static int
13057 store_membase_reg_to_store_membase_imm (int opcode)
13058 {
13059         switch (opcode) {
13060         case OP_STORE_MEMBASE_REG:
13061                 return OP_STORE_MEMBASE_IMM;
13062         case OP_STOREI1_MEMBASE_REG:
13063                 return OP_STOREI1_MEMBASE_IMM;
13064         case OP_STOREI2_MEMBASE_REG:
13065                 return OP_STOREI2_MEMBASE_IMM;
13066         case OP_STOREI4_MEMBASE_REG:
13067                 return OP_STOREI4_MEMBASE_IMM;
13068         case OP_STOREI8_MEMBASE_REG:
13069                 return OP_STOREI8_MEMBASE_IMM;
13070         default:
13071                 g_assert_not_reached ();
13072         }
13073
13074         return -1;
13075 }               
13076
13077 int
13078 mono_op_to_op_imm (int opcode)
13079 {
13080         switch (opcode) {
13081         case OP_IADD:
13082                 return OP_IADD_IMM;
13083         case OP_ISUB:
13084                 return OP_ISUB_IMM;
13085         case OP_IDIV:
13086                 return OP_IDIV_IMM;
13087         case OP_IDIV_UN:
13088                 return OP_IDIV_UN_IMM;
13089         case OP_IREM:
13090                 return OP_IREM_IMM;
13091         case OP_IREM_UN:
13092                 return OP_IREM_UN_IMM;
13093         case OP_IMUL:
13094                 return OP_IMUL_IMM;
13095         case OP_IAND:
13096                 return OP_IAND_IMM;
13097         case OP_IOR:
13098                 return OP_IOR_IMM;
13099         case OP_IXOR:
13100                 return OP_IXOR_IMM;
13101         case OP_ISHL:
13102                 return OP_ISHL_IMM;
13103         case OP_ISHR:
13104                 return OP_ISHR_IMM;
13105         case OP_ISHR_UN:
13106                 return OP_ISHR_UN_IMM;
13107
13108         case OP_LADD:
13109                 return OP_LADD_IMM;
13110         case OP_LSUB:
13111                 return OP_LSUB_IMM;
13112         case OP_LAND:
13113                 return OP_LAND_IMM;
13114         case OP_LOR:
13115                 return OP_LOR_IMM;
13116         case OP_LXOR:
13117                 return OP_LXOR_IMM;
13118         case OP_LSHL:
13119                 return OP_LSHL_IMM;
13120         case OP_LSHR:
13121                 return OP_LSHR_IMM;
13122         case OP_LSHR_UN:
13123                 return OP_LSHR_UN_IMM;
13124 #if SIZEOF_REGISTER == 8
13125         case OP_LREM:
13126                 return OP_LREM_IMM;
13127 #endif
13128
13129         case OP_COMPARE:
13130                 return OP_COMPARE_IMM;
13131         case OP_ICOMPARE:
13132                 return OP_ICOMPARE_IMM;
13133         case OP_LCOMPARE:
13134                 return OP_LCOMPARE_IMM;
13135
13136         case OP_STORE_MEMBASE_REG:
13137                 return OP_STORE_MEMBASE_IMM;
13138         case OP_STOREI1_MEMBASE_REG:
13139                 return OP_STOREI1_MEMBASE_IMM;
13140         case OP_STOREI2_MEMBASE_REG:
13141                 return OP_STOREI2_MEMBASE_IMM;
13142         case OP_STOREI4_MEMBASE_REG:
13143                 return OP_STOREI4_MEMBASE_IMM;
13144
13145 #if defined(TARGET_X86) || defined (TARGET_AMD64)
13146         case OP_X86_PUSH:
13147                 return OP_X86_PUSH_IMM;
13148         case OP_X86_COMPARE_MEMBASE_REG:
13149                 return OP_X86_COMPARE_MEMBASE_IMM;
13150 #endif
13151 #if defined(TARGET_AMD64)
13152         case OP_AMD64_ICOMPARE_MEMBASE_REG:
13153                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13154 #endif
13155         case OP_VOIDCALL_REG:
13156                 return OP_VOIDCALL;
13157         case OP_CALL_REG:
13158                 return OP_CALL;
13159         case OP_LCALL_REG:
13160                 return OP_LCALL;
13161         case OP_FCALL_REG:
13162                 return OP_FCALL;
13163         case OP_LOCALLOC:
13164                 return OP_LOCALLOC_IMM;
13165         }
13166
13167         return -1;
13168 }
13169
13170 static int
13171 ldind_to_load_membase (int opcode)
13172 {
13173         switch (opcode) {
13174         case CEE_LDIND_I1:
13175                 return OP_LOADI1_MEMBASE;
13176         case CEE_LDIND_U1:
13177                 return OP_LOADU1_MEMBASE;
13178         case CEE_LDIND_I2:
13179                 return OP_LOADI2_MEMBASE;
13180         case CEE_LDIND_U2:
13181                 return OP_LOADU2_MEMBASE;
13182         case CEE_LDIND_I4:
13183                 return OP_LOADI4_MEMBASE;
13184         case CEE_LDIND_U4:
13185                 return OP_LOADU4_MEMBASE;
13186         case CEE_LDIND_I:
13187                 return OP_LOAD_MEMBASE;
13188         case CEE_LDIND_REF:
13189                 return OP_LOAD_MEMBASE;
13190         case CEE_LDIND_I8:
13191                 return OP_LOADI8_MEMBASE;
13192         case CEE_LDIND_R4:
13193                 return OP_LOADR4_MEMBASE;
13194         case CEE_LDIND_R8:
13195                 return OP_LOADR8_MEMBASE;
13196         default:
13197                 g_assert_not_reached ();
13198         }
13199
13200         return -1;
13201 }
13202
13203 static int
13204 stind_to_store_membase (int opcode)
13205 {
13206         switch (opcode) {
13207         case CEE_STIND_I1:
13208                 return OP_STOREI1_MEMBASE_REG;
13209         case CEE_STIND_I2:
13210                 return OP_STOREI2_MEMBASE_REG;
13211         case CEE_STIND_I4:
13212                 return OP_STOREI4_MEMBASE_REG;
13213         case CEE_STIND_I:
13214         case CEE_STIND_REF:
13215                 return OP_STORE_MEMBASE_REG;
13216         case CEE_STIND_I8:
13217                 return OP_STOREI8_MEMBASE_REG;
13218         case CEE_STIND_R4:
13219                 return OP_STORER4_MEMBASE_REG;
13220         case CEE_STIND_R8:
13221                 return OP_STORER8_MEMBASE_REG;
13222         default:
13223                 g_assert_not_reached ();
13224         }
13225
13226         return -1;
13227 }
13228
13229 int
13230 mono_load_membase_to_load_mem (int opcode)
13231 {
13232         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
13233 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13234         switch (opcode) {
13235         case OP_LOAD_MEMBASE:
13236                 return OP_LOAD_MEM;
13237         case OP_LOADU1_MEMBASE:
13238                 return OP_LOADU1_MEM;
13239         case OP_LOADU2_MEMBASE:
13240                 return OP_LOADU2_MEM;
13241         case OP_LOADI4_MEMBASE:
13242                 return OP_LOADI4_MEM;
13243         case OP_LOADU4_MEMBASE:
13244                 return OP_LOADU4_MEM;
13245 #if SIZEOF_REGISTER == 8
13246         case OP_LOADI8_MEMBASE:
13247                 return OP_LOADI8_MEM;
13248 #endif
13249         }
13250 #endif
13251
13252         return -1;
13253 }
13254
13255 static inline int
13256 op_to_op_dest_membase (int store_opcode, int opcode)
13257 {
13258 #if defined(TARGET_X86)
13259         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
13260                 return -1;
13261
13262         switch (opcode) {
13263         case OP_IADD:
13264                 return OP_X86_ADD_MEMBASE_REG;
13265         case OP_ISUB:
13266                 return OP_X86_SUB_MEMBASE_REG;
13267         case OP_IAND:
13268                 return OP_X86_AND_MEMBASE_REG;
13269         case OP_IOR:
13270                 return OP_X86_OR_MEMBASE_REG;
13271         case OP_IXOR:
13272                 return OP_X86_XOR_MEMBASE_REG;
13273         case OP_ADD_IMM:
13274         case OP_IADD_IMM:
13275                 return OP_X86_ADD_MEMBASE_IMM;
13276         case OP_SUB_IMM:
13277         case OP_ISUB_IMM:
13278                 return OP_X86_SUB_MEMBASE_IMM;
13279         case OP_AND_IMM:
13280         case OP_IAND_IMM:
13281                 return OP_X86_AND_MEMBASE_IMM;
13282         case OP_OR_IMM:
13283         case OP_IOR_IMM:
13284                 return OP_X86_OR_MEMBASE_IMM;
13285         case OP_XOR_IMM:
13286         case OP_IXOR_IMM:
13287                 return OP_X86_XOR_MEMBASE_IMM;
13288         case OP_MOVE:
13289                 return OP_NOP;
13290         }
13291 #endif
13292
13293 #if defined(TARGET_AMD64)
13294         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
13295                 return -1;
13296
13297         switch (opcode) {
13298         case OP_IADD:
13299                 return OP_X86_ADD_MEMBASE_REG;
13300         case OP_ISUB:
13301                 return OP_X86_SUB_MEMBASE_REG;
13302         case OP_IAND:
13303                 return OP_X86_AND_MEMBASE_REG;
13304         case OP_IOR:
13305                 return OP_X86_OR_MEMBASE_REG;
13306         case OP_IXOR:
13307                 return OP_X86_XOR_MEMBASE_REG;
13308         case OP_IADD_IMM:
13309                 return OP_X86_ADD_MEMBASE_IMM;
13310         case OP_ISUB_IMM:
13311                 return OP_X86_SUB_MEMBASE_IMM;
13312         case OP_IAND_IMM:
13313                 return OP_X86_AND_MEMBASE_IMM;
13314         case OP_IOR_IMM:
13315                 return OP_X86_OR_MEMBASE_IMM;
13316         case OP_IXOR_IMM:
13317                 return OP_X86_XOR_MEMBASE_IMM;
13318         case OP_LADD:
13319                 return OP_AMD64_ADD_MEMBASE_REG;
13320         case OP_LSUB:
13321                 return OP_AMD64_SUB_MEMBASE_REG;
13322         case OP_LAND:
13323                 return OP_AMD64_AND_MEMBASE_REG;
13324         case OP_LOR:
13325                 return OP_AMD64_OR_MEMBASE_REG;
13326         case OP_LXOR:
13327                 return OP_AMD64_XOR_MEMBASE_REG;
13328         case OP_ADD_IMM:
13329         case OP_LADD_IMM:
13330                 return OP_AMD64_ADD_MEMBASE_IMM;
13331         case OP_SUB_IMM:
13332         case OP_LSUB_IMM:
13333                 return OP_AMD64_SUB_MEMBASE_IMM;
13334         case OP_AND_IMM:
13335         case OP_LAND_IMM:
13336                 return OP_AMD64_AND_MEMBASE_IMM;
13337         case OP_OR_IMM:
13338         case OP_LOR_IMM:
13339                 return OP_AMD64_OR_MEMBASE_IMM;
13340         case OP_XOR_IMM:
13341         case OP_LXOR_IMM:
13342                 return OP_AMD64_XOR_MEMBASE_IMM;
13343         case OP_MOVE:
13344                 return OP_NOP;
13345         }
13346 #endif
13347
13348         return -1;
13349 }
13350
13351 static inline int
13352 op_to_op_store_membase (int store_opcode, int opcode)
13353 {
13354 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13355         switch (opcode) {
13356         case OP_ICEQ:
13357                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13358                         return OP_X86_SETEQ_MEMBASE;
13359         case OP_CNE:
13360                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13361                         return OP_X86_SETNE_MEMBASE;
13362         }
13363 #endif
13364
13365         return -1;
13366 }
13367
13368 static inline int
13369 op_to_op_src1_membase (int load_opcode, int opcode)
13370 {
13371 #ifdef TARGET_X86
13372         /* FIXME: This has sign extension issues */
13373         /*
13374         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13375                 return OP_X86_COMPARE_MEMBASE8_IMM;
13376         */
13377
13378         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13379                 return -1;
13380
13381         switch (opcode) {
13382         case OP_X86_PUSH:
13383                 return OP_X86_PUSH_MEMBASE;
13384         case OP_COMPARE_IMM:
13385         case OP_ICOMPARE_IMM:
13386                 return OP_X86_COMPARE_MEMBASE_IMM;
13387         case OP_COMPARE:
13388         case OP_ICOMPARE:
13389                 return OP_X86_COMPARE_MEMBASE_REG;
13390         }
13391 #endif
13392
13393 #ifdef TARGET_AMD64
13394         /* FIXME: This has sign extension issues */
13395         /*
13396         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13397                 return OP_X86_COMPARE_MEMBASE8_IMM;
13398         */
13399
13400         switch (opcode) {
13401         case OP_X86_PUSH:
13402 #ifdef __mono_ilp32__
13403                 if (load_opcode == OP_LOADI8_MEMBASE)
13404 #else
13405                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13406 #endif
13407                         return OP_X86_PUSH_MEMBASE;
13408                 break;
13409                 /* FIXME: This only works for 32 bit immediates
13410         case OP_COMPARE_IMM:
13411         case OP_LCOMPARE_IMM:
13412                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13413                         return OP_AMD64_COMPARE_MEMBASE_IMM;
13414                 */
13415         case OP_ICOMPARE_IMM:
13416                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13417                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13418                 break;
13419         case OP_COMPARE:
13420         case OP_LCOMPARE:
13421 #ifdef __mono_ilp32__
13422                 if (load_opcode == OP_LOAD_MEMBASE)
13423                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13424                 if (load_opcode == OP_LOADI8_MEMBASE)
13425 #else
13426                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13427 #endif
13428                         return OP_AMD64_COMPARE_MEMBASE_REG;
13429                 break;
13430         case OP_ICOMPARE:
13431                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13432                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13433                 break;
13434         }
13435 #endif
13436
13437         return -1;
13438 }
13439
13440 static inline int
13441 op_to_op_src2_membase (int load_opcode, int opcode)
13442 {
13443 #ifdef TARGET_X86
13444         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13445                 return -1;
13446         
13447         switch (opcode) {
13448         case OP_COMPARE:
13449         case OP_ICOMPARE:
13450                 return OP_X86_COMPARE_REG_MEMBASE;
13451         case OP_IADD:
13452                 return OP_X86_ADD_REG_MEMBASE;
13453         case OP_ISUB:
13454                 return OP_X86_SUB_REG_MEMBASE;
13455         case OP_IAND:
13456                 return OP_X86_AND_REG_MEMBASE;
13457         case OP_IOR:
13458                 return OP_X86_OR_REG_MEMBASE;
13459         case OP_IXOR:
13460                 return OP_X86_XOR_REG_MEMBASE;
13461         }
13462 #endif
13463
13464 #ifdef TARGET_AMD64
13465 #ifdef __mono_ilp32__
13466         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE) ) {
13467 #else
13468         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)) {
13469 #endif
13470                 switch (opcode) {
13471                 case OP_ICOMPARE:
13472                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
13473                 case OP_IADD:
13474                         return OP_X86_ADD_REG_MEMBASE;
13475                 case OP_ISUB:
13476                         return OP_X86_SUB_REG_MEMBASE;
13477                 case OP_IAND:
13478                         return OP_X86_AND_REG_MEMBASE;
13479                 case OP_IOR:
13480                         return OP_X86_OR_REG_MEMBASE;
13481                 case OP_IXOR:
13482                         return OP_X86_XOR_REG_MEMBASE;
13483                 }
13484 #ifdef __mono_ilp32__
13485         } else if (load_opcode == OP_LOADI8_MEMBASE) {
13486 #else
13487         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE)) {
13488 #endif
13489                 switch (opcode) {
13490                 case OP_COMPARE:
13491                 case OP_LCOMPARE:
13492                         return OP_AMD64_COMPARE_REG_MEMBASE;
13493                 case OP_LADD:
13494                         return OP_AMD64_ADD_REG_MEMBASE;
13495                 case OP_LSUB:
13496                         return OP_AMD64_SUB_REG_MEMBASE;
13497                 case OP_LAND:
13498                         return OP_AMD64_AND_REG_MEMBASE;
13499                 case OP_LOR:
13500                         return OP_AMD64_OR_REG_MEMBASE;
13501                 case OP_LXOR:
13502                         return OP_AMD64_XOR_REG_MEMBASE;
13503                 }
13504         }
13505 #endif
13506
13507         return -1;
13508 }
13509
13510 int
13511 mono_op_to_op_imm_noemul (int opcode)
13512 {
13513         switch (opcode) {
13514 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
13515         case OP_LSHR:
13516         case OP_LSHL:
13517         case OP_LSHR_UN:
13518                 return -1;
13519 #endif
13520 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
13521         case OP_IDIV:
13522         case OP_IDIV_UN:
13523         case OP_IREM:
13524         case OP_IREM_UN:
13525                 return -1;
13526 #endif
13527 #if defined(MONO_ARCH_EMULATE_MUL_DIV)
13528         case OP_IMUL:
13529                 return -1;
13530 #endif
13531         default:
13532                 return mono_op_to_op_imm (opcode);
13533         }
13534 }
13535
13536 /**
13537  * mono_handle_global_vregs:
13538  *
13539  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
13540  * for them.
13541  */
13542 void
13543 mono_handle_global_vregs (MonoCompile *cfg)
13544 {
13545         gint32 *vreg_to_bb;
13546         MonoBasicBlock *bb;
13547         int i, pos;
13548
13549         vreg_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
13550
13551 #ifdef MONO_ARCH_SIMD_INTRINSICS
13552         if (cfg->uses_simd_intrinsics)
13553                 mono_simd_simplify_indirection (cfg);
13554 #endif
13555
13556         /* Find local vregs used in more than one bb */
13557         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13558                 MonoInst *ins = bb->code;       
13559                 int block_num = bb->block_num;
13560
13561                 if (cfg->verbose_level > 2)
13562                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
13563
13564                 cfg->cbb = bb;
13565                 for (; ins; ins = ins->next) {
13566                         const char *spec = INS_INFO (ins->opcode);
13567                         int regtype = 0, regindex;
13568                         gint32 prev_bb;
13569
13570                         if (G_UNLIKELY (cfg->verbose_level > 2))
13571                                 mono_print_ins (ins);
13572
13573                         g_assert (ins->opcode >= MONO_CEE_LAST);
13574
13575                         for (regindex = 0; regindex < 4; regindex ++) {
13576                                 int vreg = 0;
13577
13578                                 if (regindex == 0) {
13579                                         regtype = spec [MONO_INST_DEST];
13580                                         if (regtype == ' ')
13581                                                 continue;
13582                                         vreg = ins->dreg;
13583                                 } else if (regindex == 1) {
13584                                         regtype = spec [MONO_INST_SRC1];
13585                                         if (regtype == ' ')
13586                                                 continue;
13587                                         vreg = ins->sreg1;
13588                                 } else if (regindex == 2) {
13589                                         regtype = spec [MONO_INST_SRC2];
13590                                         if (regtype == ' ')
13591                                                 continue;
13592                                         vreg = ins->sreg2;
13593                                 } else if (regindex == 3) {
13594                                         regtype = spec [MONO_INST_SRC3];
13595                                         if (regtype == ' ')
13596                                                 continue;
13597                                         vreg = ins->sreg3;
13598                                 }
13599
13600 #if SIZEOF_REGISTER == 4
13601                                 /* In the LLVM case, the long opcodes are not decomposed */
13602                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
13603                                         /*
13604                                          * Since some instructions reference the original long vreg,
13605                                          * and some reference the two component vregs, it is quite hard
13606                                          * to determine when it needs to be global. So be conservative.
13607                                          */
13608                                         if (!get_vreg_to_inst (cfg, vreg)) {
13609                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13610
13611                                                 if (cfg->verbose_level > 2)
13612                                                         printf ("LONG VREG R%d made global.\n", vreg);
13613                                         }
13614
13615                                         /*
13616                                          * Make the component vregs volatile since the optimizations can
13617                                          * get confused otherwise.
13618                                          */
13619                                         get_vreg_to_inst (cfg, vreg + 1)->flags |= MONO_INST_VOLATILE;
13620                                         get_vreg_to_inst (cfg, vreg + 2)->flags |= MONO_INST_VOLATILE;
13621                                 }
13622 #endif
13623
13624                                 g_assert (vreg != -1);
13625
13626                                 prev_bb = vreg_to_bb [vreg];
13627                                 if (prev_bb == 0) {
13628                                         /* 0 is a valid block num */
13629                                         vreg_to_bb [vreg] = block_num + 1;
13630                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
13631                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
13632                                                 continue;
13633
13634                                         if (!get_vreg_to_inst (cfg, vreg)) {
13635                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13636                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
13637
13638                                                 switch (regtype) {
13639                                                 case 'i':
13640                                                         if (vreg_is_ref (cfg, vreg))
13641                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg);
13642                                                         else
13643                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
13644                                                         break;
13645                                                 case 'l':
13646                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13647                                                         break;
13648                                                 case 'f':
13649                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
13650                                                         break;
13651                                                 case 'v':
13652                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
13653                                                         break;
13654                                                 default:
13655                                                         g_assert_not_reached ();
13656                                                 }
13657                                         }
13658
13659                                         /* Flag as having been used in more than one bb */
13660                                         vreg_to_bb [vreg] = -1;
13661                                 }
13662                         }
13663                 }
13664         }
13665
13666         /* If a variable is used in only one bblock, convert it into a local vreg */
13667         for (i = 0; i < cfg->num_varinfo; i++) {
13668                 MonoInst *var = cfg->varinfo [i];
13669                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
13670
13671                 switch (var->type) {
13672                 case STACK_I4:
13673                 case STACK_OBJ:
13674                 case STACK_PTR:
13675                 case STACK_MP:
13676                 case STACK_VTYPE:
13677 #if SIZEOF_REGISTER == 8
13678                 case STACK_I8:
13679 #endif
13680 #if !defined(TARGET_X86)
13681                 /* Enabling this screws up the fp stack on x86 */
13682                 case STACK_R8:
13683 #endif
13684                         if (mono_arch_is_soft_float ())
13685                                 break;
13686
13687                         /* Arguments are implicitly global */
13688                         /* Putting R4 vars into registers doesn't work currently */
13689                         /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
13690                         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) {
13691                                 /* 
13692                                  * Make that the variable's liveness interval doesn't contain a call, since
13693                                  * that would cause the lvreg to be spilled, making the whole optimization
13694                                  * useless.
13695                                  */
13696                                 /* This is too slow for JIT compilation */
13697 #if 0
13698                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
13699                                         MonoInst *ins;
13700                                         int def_index, call_index, ins_index;
13701                                         gboolean spilled = FALSE;
13702
13703                                         def_index = -1;
13704                                         call_index = -1;
13705                                         ins_index = 0;
13706                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
13707                                                 const char *spec = INS_INFO (ins->opcode);
13708
13709                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
13710                                                         def_index = ins_index;
13711
13712                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
13713                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
13714                                                         if (call_index > def_index) {
13715                                                                 spilled = TRUE;
13716                                                                 break;
13717                                                         }
13718                                                 }
13719
13720                                                 if (MONO_IS_CALL (ins))
13721                                                         call_index = ins_index;
13722
13723                                                 ins_index ++;
13724                                         }
13725
13726                                         if (spilled)
13727                                                 break;
13728                                 }
13729 #endif
13730
13731                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13732                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
13733                                 var->flags |= MONO_INST_IS_DEAD;
13734                                 cfg->vreg_to_inst [var->dreg] = NULL;
13735                         }
13736                         break;
13737                 }
13738         }
13739
13740         /* 
13741          * Compress the varinfo and vars tables so the liveness computation is faster and
13742          * takes up less space.
13743          */
13744         pos = 0;
13745         for (i = 0; i < cfg->num_varinfo; ++i) {
13746                 MonoInst *var = cfg->varinfo [i];
13747                 if (pos < i && cfg->locals_start == i)
13748                         cfg->locals_start = pos;
13749                 if (!(var->flags & MONO_INST_IS_DEAD)) {
13750                         if (pos < i) {
13751                                 cfg->varinfo [pos] = cfg->varinfo [i];
13752                                 cfg->varinfo [pos]->inst_c0 = pos;
13753                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
13754                                 cfg->vars [pos].idx = pos;
13755 #if SIZEOF_REGISTER == 4
13756                                 if (cfg->varinfo [pos]->type == STACK_I8) {
13757                                         /* Modify the two component vars too */
13758                                         MonoInst *var1;
13759
13760                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 1);
13761                                         var1->inst_c0 = pos;
13762                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 2);
13763                                         var1->inst_c0 = pos;
13764                                 }
13765 #endif
13766                         }
13767                         pos ++;
13768                 }
13769         }
13770         cfg->num_varinfo = pos;
13771         if (cfg->locals_start > cfg->num_varinfo)
13772                 cfg->locals_start = cfg->num_varinfo;
13773 }
13774
13775 /**
13776  * mono_spill_global_vars:
13777  *
13778  *   Generate spill code for variables which are not allocated to registers, 
13779  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
13780  * code is generated which could be optimized by the local optimization passes.
13781  */
13782 void
13783 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
13784 {
13785         MonoBasicBlock *bb;
13786         char spec2 [16];
13787         int orig_next_vreg;
13788         guint32 *vreg_to_lvreg;
13789         guint32 *lvregs;
13790         guint32 i, lvregs_len;
13791         gboolean dest_has_lvreg = FALSE;
13792         guint32 stacktypes [128];
13793         MonoInst **live_range_start, **live_range_end;
13794         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
13795         int *gsharedvt_vreg_to_idx = NULL;
13796
13797         *need_local_opts = FALSE;
13798
13799         memset (spec2, 0, sizeof (spec2));
13800
13801         /* FIXME: Move this function to mini.c */
13802         stacktypes ['i'] = STACK_PTR;
13803         stacktypes ['l'] = STACK_I8;
13804         stacktypes ['f'] = STACK_R8;
13805 #ifdef MONO_ARCH_SIMD_INTRINSICS
13806         stacktypes ['x'] = STACK_VTYPE;
13807 #endif
13808
13809 #if SIZEOF_REGISTER == 4
13810         /* Create MonoInsts for longs */
13811         for (i = 0; i < cfg->num_varinfo; i++) {
13812                 MonoInst *ins = cfg->varinfo [i];
13813
13814                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
13815                         switch (ins->type) {
13816                         case STACK_R8:
13817                         case STACK_I8: {
13818                                 MonoInst *tree;
13819
13820                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
13821                                         break;
13822
13823                                 g_assert (ins->opcode == OP_REGOFFSET);
13824
13825                                 tree = get_vreg_to_inst (cfg, ins->dreg + 1);
13826                                 g_assert (tree);
13827                                 tree->opcode = OP_REGOFFSET;
13828                                 tree->inst_basereg = ins->inst_basereg;
13829                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
13830
13831                                 tree = get_vreg_to_inst (cfg, ins->dreg + 2);
13832                                 g_assert (tree);
13833                                 tree->opcode = OP_REGOFFSET;
13834                                 tree->inst_basereg = ins->inst_basereg;
13835                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
13836                                 break;
13837                         }
13838                         default:
13839                                 break;
13840                         }
13841                 }
13842         }
13843 #endif
13844
13845         if (cfg->compute_gc_maps) {
13846                 /* registers need liveness info even for !non refs */
13847                 for (i = 0; i < cfg->num_varinfo; i++) {
13848                         MonoInst *ins = cfg->varinfo [i];
13849
13850                         if (ins->opcode == OP_REGVAR)
13851                                 ins->flags |= MONO_INST_GC_TRACK;
13852                 }
13853         }
13854
13855         if (cfg->gsharedvt) {
13856                 gsharedvt_vreg_to_idx = mono_mempool_alloc0 (cfg->mempool, sizeof (int) * cfg->next_vreg);
13857
13858                 for (i = 0; i < cfg->num_varinfo; ++i) {
13859                         MonoInst *ins = cfg->varinfo [i];
13860                         int idx;
13861
13862                         if (mini_is_gsharedvt_variable_type (ins->inst_vtype)) {
13863                                 if (i >= cfg->locals_start) {
13864                                         /* Local */
13865                                         idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
13866                                         gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
13867                                         ins->opcode = OP_GSHAREDVT_LOCAL;
13868                                         ins->inst_imm = idx;
13869                                 } else {
13870                                         /* Arg */
13871                                         gsharedvt_vreg_to_idx [ins->dreg] = -1;
13872                                         ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
13873                                 }
13874                         }
13875                 }
13876         }
13877                 
13878         /* FIXME: widening and truncation */
13879
13880         /*
13881          * As an optimization, when a variable allocated to the stack is first loaded into 
13882          * an lvreg, we will remember the lvreg and use it the next time instead of loading
13883          * the variable again.
13884          */
13885         orig_next_vreg = cfg->next_vreg;
13886         vreg_to_lvreg = mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
13887         lvregs = mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
13888         lvregs_len = 0;
13889
13890         /* 
13891          * These arrays contain the first and last instructions accessing a given
13892          * variable.
13893          * Since we emit bblocks in the same order we process them here, and we
13894          * don't split live ranges, these will precisely describe the live range of
13895          * the variable, i.e. the instruction range where a valid value can be found
13896          * in the variables location.
13897          * The live range is computed using the liveness info computed by the liveness pass.
13898          * We can't use vmv->range, since that is an abstract live range, and we need
13899          * one which is instruction precise.
13900          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
13901          */
13902         /* FIXME: Only do this if debugging info is requested */
13903         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
13904         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
13905         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
13906         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
13907         
13908         /* Add spill loads/stores */
13909         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13910                 MonoInst *ins;
13911
13912                 if (cfg->verbose_level > 2)
13913                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
13914
13915                 /* Clear vreg_to_lvreg array */
13916                 for (i = 0; i < lvregs_len; i++)
13917                         vreg_to_lvreg [lvregs [i]] = 0;
13918                 lvregs_len = 0;
13919
13920                 cfg->cbb = bb;
13921                 MONO_BB_FOR_EACH_INS (bb, ins) {
13922                         const char *spec = INS_INFO (ins->opcode);
13923                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
13924                         gboolean store, no_lvreg;
13925                         int sregs [MONO_MAX_SRC_REGS];
13926
13927                         if (G_UNLIKELY (cfg->verbose_level > 2))
13928                                 mono_print_ins (ins);
13929
13930                         if (ins->opcode == OP_NOP)
13931                                 continue;
13932
13933                         /* 
13934                          * We handle LDADDR here as well, since it can only be decomposed
13935                          * when variable addresses are known.
13936                          */
13937                         if (ins->opcode == OP_LDADDR) {
13938                                 MonoInst *var = ins->inst_p0;
13939
13940                                 if (var->opcode == OP_VTARG_ADDR) {
13941                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
13942                                         MonoInst *vtaddr = var->inst_left;
13943                                         if (vtaddr->opcode == OP_REGVAR) {
13944                                                 ins->opcode = OP_MOVE;
13945                                                 ins->sreg1 = vtaddr->dreg;
13946                                         }
13947                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
13948                                                 ins->opcode = OP_LOAD_MEMBASE;
13949                                                 ins->inst_basereg = vtaddr->inst_basereg;
13950                                                 ins->inst_offset = vtaddr->inst_offset;
13951                                         } else
13952                                                 NOT_IMPLEMENTED;
13953                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg] < 0) {
13954                                         /* gsharedvt arg passed by ref */
13955                                         g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
13956
13957                                         ins->opcode = OP_LOAD_MEMBASE;
13958                                         ins->inst_basereg = var->inst_basereg;
13959                                         ins->inst_offset = var->inst_offset;
13960                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg]) {
13961                                         MonoInst *load, *load2, *load3;
13962                                         int idx = gsharedvt_vreg_to_idx [var->dreg] - 1;
13963                                         int reg1, reg2, reg3;
13964                                         MonoInst *info_var = cfg->gsharedvt_info_var;
13965                                         MonoInst *locals_var = cfg->gsharedvt_locals_var;
13966
13967                                         /*
13968                                          * gsharedvt local.
13969                                          * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
13970                                          */
13971
13972                                         g_assert (var->opcode == OP_GSHAREDVT_LOCAL);
13973
13974                                         g_assert (info_var);
13975                                         g_assert (locals_var);
13976
13977                                         /* Mark the instruction used to compute the locals var as used */
13978                                         cfg->gsharedvt_locals_var_ins = NULL;
13979
13980                                         /* Load the offset */
13981                                         if (info_var->opcode == OP_REGOFFSET) {
13982                                                 reg1 = alloc_ireg (cfg);
13983                                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, reg1, info_var->inst_basereg, info_var->inst_offset);
13984                                         } else if (info_var->opcode == OP_REGVAR) {
13985                                                 load = NULL;
13986                                                 reg1 = info_var->dreg;
13987                                         } else {
13988                                                 g_assert_not_reached ();
13989                                         }
13990                                         reg2 = alloc_ireg (cfg);
13991                                         NEW_LOAD_MEMBASE (cfg, load2, OP_LOADI4_MEMBASE, reg2, reg1, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
13992                                         /* Load the locals area address */
13993                                         reg3 = alloc_ireg (cfg);
13994                                         if (locals_var->opcode == OP_REGOFFSET) {
13995                                                 NEW_LOAD_MEMBASE (cfg, load3, OP_LOAD_MEMBASE, reg3, locals_var->inst_basereg, locals_var->inst_offset);
13996                                         } else if (locals_var->opcode == OP_REGVAR) {
13997                                                 NEW_UNALU (cfg, load3, OP_MOVE, reg3, locals_var->dreg);
13998                                         } else {
13999                                                 g_assert_not_reached ();
14000                                         }
14001                                         /* Compute the address */
14002                                         ins->opcode = OP_PADD;
14003                                         ins->sreg1 = reg3;
14004                                         ins->sreg2 = reg2;
14005
14006                                         mono_bblock_insert_before_ins (bb, ins, load3);
14007                                         mono_bblock_insert_before_ins (bb, load3, load2);
14008                                         if (load)
14009                                                 mono_bblock_insert_before_ins (bb, load2, load);
14010                                 } else {
14011                                         g_assert (var->opcode == OP_REGOFFSET);
14012
14013                                         ins->opcode = OP_ADD_IMM;
14014                                         ins->sreg1 = var->inst_basereg;
14015                                         ins->inst_imm = var->inst_offset;
14016                                 }
14017
14018                                 *need_local_opts = TRUE;
14019                                 spec = INS_INFO (ins->opcode);
14020                         }
14021
14022                         if (ins->opcode < MONO_CEE_LAST) {
14023                                 mono_print_ins (ins);
14024                                 g_assert_not_reached ();
14025                         }
14026
14027                         /*
14028                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
14029                          * src register.
14030                          * FIXME:
14031                          */
14032                         if (MONO_IS_STORE_MEMBASE (ins)) {
14033                                 tmp_reg = ins->dreg;
14034                                 ins->dreg = ins->sreg2;
14035                                 ins->sreg2 = tmp_reg;
14036                                 store = TRUE;
14037
14038                                 spec2 [MONO_INST_DEST] = ' ';
14039                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14040                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14041                                 spec2 [MONO_INST_SRC3] = ' ';
14042                                 spec = spec2;
14043                         } else if (MONO_IS_STORE_MEMINDEX (ins))
14044                                 g_assert_not_reached ();
14045                         else
14046                                 store = FALSE;
14047                         no_lvreg = FALSE;
14048
14049                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
14050                                 printf ("\t %.3s %d", spec, ins->dreg);
14051                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
14052                                 for (srcindex = 0; srcindex < num_sregs; ++srcindex)
14053                                         printf (" %d", sregs [srcindex]);
14054                                 printf ("\n");
14055                         }
14056
14057                         /***************/
14058                         /*    DREG     */
14059                         /***************/
14060                         regtype = spec [MONO_INST_DEST];
14061                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
14062                         prev_dreg = -1;
14063
14064                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
14065                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
14066                                 MonoInst *store_ins;
14067                                 int store_opcode;
14068                                 MonoInst *def_ins = ins;
14069                                 int dreg = ins->dreg; /* The original vreg */
14070
14071                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
14072
14073                                 if (var->opcode == OP_REGVAR) {
14074                                         ins->dreg = var->dreg;
14075                                 } 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)) {
14076                                         /* 
14077                                          * Instead of emitting a load+store, use a _membase opcode.
14078                                          */
14079                                         g_assert (var->opcode == OP_REGOFFSET);
14080                                         if (ins->opcode == OP_MOVE) {
14081                                                 NULLIFY_INS (ins);
14082                                                 def_ins = NULL;
14083                                         } else {
14084                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
14085                                                 ins->inst_basereg = var->inst_basereg;
14086                                                 ins->inst_offset = var->inst_offset;
14087                                                 ins->dreg = -1;
14088                                         }
14089                                         spec = INS_INFO (ins->opcode);
14090                                 } else {
14091                                         guint32 lvreg;
14092
14093                                         g_assert (var->opcode == OP_REGOFFSET);
14094
14095                                         prev_dreg = ins->dreg;
14096
14097                                         /* Invalidate any previous lvreg for this vreg */
14098                                         vreg_to_lvreg [ins->dreg] = 0;
14099
14100                                         lvreg = 0;
14101
14102                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
14103                                                 regtype = 'l';
14104                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
14105                                         }
14106
14107                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
14108
14109 #if SIZEOF_REGISTER != 8
14110                                         if (regtype == 'l') {
14111                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET, ins->dreg + 1);
14112                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14113                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET, ins->dreg + 2);
14114                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14115                                                 def_ins = store_ins;
14116                                         }
14117                                         else
14118 #endif
14119                                         {
14120                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
14121
14122                                                 /* Try to fuse the store into the instruction itself */
14123                                                 /* FIXME: Add more instructions */
14124                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
14125                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
14126                                                         ins->inst_imm = ins->inst_c0;
14127                                                         ins->inst_destbasereg = var->inst_basereg;
14128                                                         ins->inst_offset = var->inst_offset;
14129                                                         spec = INS_INFO (ins->opcode);
14130                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE) || (ins->opcode == OP_RMOVE))) {
14131                                                         ins->opcode = store_opcode;
14132                                                         ins->inst_destbasereg = var->inst_basereg;
14133                                                         ins->inst_offset = var->inst_offset;
14134
14135                                                         no_lvreg = TRUE;
14136
14137                                                         tmp_reg = ins->dreg;
14138                                                         ins->dreg = ins->sreg2;
14139                                                         ins->sreg2 = tmp_reg;
14140                                                         store = TRUE;
14141
14142                                                         spec2 [MONO_INST_DEST] = ' ';
14143                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14144                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14145                                                         spec2 [MONO_INST_SRC3] = ' ';
14146                                                         spec = spec2;
14147                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
14148                                                         // FIXME: The backends expect the base reg to be in inst_basereg
14149                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
14150                                                         ins->dreg = -1;
14151                                                         ins->inst_basereg = var->inst_basereg;
14152                                                         ins->inst_offset = var->inst_offset;
14153                                                         spec = INS_INFO (ins->opcode);
14154                                                 } else {
14155                                                         /* printf ("INS: "); mono_print_ins (ins); */
14156                                                         /* Create a store instruction */
14157                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
14158
14159                                                         /* Insert it after the instruction */
14160                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
14161
14162                                                         def_ins = store_ins;
14163
14164                                                         /* 
14165                                                          * We can't assign ins->dreg to var->dreg here, since the
14166                                                          * sregs could use it. So set a flag, and do it after
14167                                                          * the sregs.
14168                                                          */
14169                                                         if ((!MONO_ARCH_USE_FPSTACK || ((store_opcode != OP_STORER8_MEMBASE_REG) && (store_opcode != OP_STORER4_MEMBASE_REG))) && !((var)->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT)))
14170                                                                 dest_has_lvreg = TRUE;
14171                                                 }
14172                                         }
14173                                 }
14174
14175                                 if (def_ins && !live_range_start [dreg]) {
14176                                         live_range_start [dreg] = def_ins;
14177                                         live_range_start_bb [dreg] = bb;
14178                                 }
14179
14180                                 if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) {
14181                                         MonoInst *tmp;
14182
14183                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
14184                                         tmp->inst_c1 = dreg;
14185                                         mono_bblock_insert_after_ins (bb, def_ins, tmp);
14186                                 }
14187                         }
14188
14189                         /************/
14190                         /*  SREGS   */
14191                         /************/
14192                         num_sregs = mono_inst_get_src_registers (ins, sregs);
14193                         for (srcindex = 0; srcindex < 3; ++srcindex) {
14194                                 regtype = spec [MONO_INST_SRC1 + srcindex];
14195                                 sreg = sregs [srcindex];
14196
14197                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
14198                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
14199                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
14200                                         MonoInst *use_ins = ins;
14201                                         MonoInst *load_ins;
14202                                         guint32 load_opcode;
14203
14204                                         if (var->opcode == OP_REGVAR) {
14205                                                 sregs [srcindex] = var->dreg;
14206                                                 //mono_inst_set_src_registers (ins, sregs);
14207                                                 live_range_end [sreg] = use_ins;
14208                                                 live_range_end_bb [sreg] = bb;
14209
14210                                                 if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14211                                                         MonoInst *tmp;
14212
14213                                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14214                                                         /* var->dreg is a hreg */
14215                                                         tmp->inst_c1 = sreg;
14216                                                         mono_bblock_insert_after_ins (bb, ins, tmp);
14217                                                 }
14218
14219                                                 continue;
14220                                         }
14221
14222                                         g_assert (var->opcode == OP_REGOFFSET);
14223                                                 
14224                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
14225
14226                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
14227
14228                                         if (vreg_to_lvreg [sreg]) {
14229                                                 g_assert (vreg_to_lvreg [sreg] != -1);
14230
14231                                                 /* The variable is already loaded to an lvreg */
14232                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14233                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
14234                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
14235                                                 //mono_inst_set_src_registers (ins, sregs);
14236                                                 continue;
14237                                         }
14238
14239                                         /* Try to fuse the load into the instruction */
14240                                         if ((srcindex == 0) && (op_to_op_src1_membase (load_opcode, ins->opcode) != -1)) {
14241                                                 ins->opcode = op_to_op_src1_membase (load_opcode, ins->opcode);
14242                                                 sregs [0] = var->inst_basereg;
14243                                                 //mono_inst_set_src_registers (ins, sregs);
14244                                                 ins->inst_offset = var->inst_offset;
14245                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (load_opcode, ins->opcode) != -1)) {
14246                                                 ins->opcode = op_to_op_src2_membase (load_opcode, ins->opcode);
14247                                                 sregs [1] = var->inst_basereg;
14248                                                 //mono_inst_set_src_registers (ins, sregs);
14249                                                 ins->inst_offset = var->inst_offset;
14250                                         } else {
14251                                                 if (MONO_IS_REAL_MOVE (ins)) {
14252                                                         ins->opcode = OP_NOP;
14253                                                         sreg = ins->dreg;
14254                                                 } else {
14255                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
14256
14257                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
14258
14259                                                         if ((!MONO_ARCH_USE_FPSTACK || ((load_opcode != OP_LOADR8_MEMBASE) && (load_opcode != OP_LOADR4_MEMBASE))) && !((var)->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT)) && !no_lvreg) {
14260                                                                 if (var->dreg == prev_dreg) {
14261                                                                         /*
14262                                                                          * sreg refers to the value loaded by the load
14263                                                                          * emitted below, but we need to use ins->dreg
14264                                                                          * since it refers to the store emitted earlier.
14265                                                                          */
14266                                                                         sreg = ins->dreg;
14267                                                                 }
14268                                                                 g_assert (sreg != -1);
14269                                                                 vreg_to_lvreg [var->dreg] = sreg;
14270                                                                 g_assert (lvregs_len < 1024);
14271                                                                 lvregs [lvregs_len ++] = var->dreg;
14272                                                         }
14273                                                 }
14274
14275                                                 sregs [srcindex] = sreg;
14276                                                 //mono_inst_set_src_registers (ins, sregs);
14277
14278 #if SIZEOF_REGISTER != 8
14279                                                 if (regtype == 'l') {
14280                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 2, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
14281                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14282                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 1, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
14283                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14284                                                         use_ins = load_ins;
14285                                                 }
14286                                                 else
14287 #endif
14288                                                 {
14289 #if SIZEOF_REGISTER == 4
14290                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
14291 #endif
14292                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
14293                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14294                                                         use_ins = load_ins;
14295                                                 }
14296                                         }
14297
14298                                         if (var->dreg < orig_next_vreg) {
14299                                                 live_range_end [var->dreg] = use_ins;
14300                                                 live_range_end_bb [var->dreg] = bb;
14301                                         }
14302
14303                                         if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14304                                                 MonoInst *tmp;
14305
14306                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14307                                                 tmp->inst_c1 = var->dreg;
14308                                                 mono_bblock_insert_after_ins (bb, ins, tmp);
14309                                         }
14310                                 }
14311                         }
14312                         mono_inst_set_src_registers (ins, sregs);
14313
14314                         if (dest_has_lvreg) {
14315                                 g_assert (ins->dreg != -1);
14316                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
14317                                 g_assert (lvregs_len < 1024);
14318                                 lvregs [lvregs_len ++] = prev_dreg;
14319                                 dest_has_lvreg = FALSE;
14320                         }
14321
14322                         if (store) {
14323                                 tmp_reg = ins->dreg;
14324                                 ins->dreg = ins->sreg2;
14325                                 ins->sreg2 = tmp_reg;
14326                         }
14327
14328                         if (MONO_IS_CALL (ins)) {
14329                                 /* Clear vreg_to_lvreg array */
14330                                 for (i = 0; i < lvregs_len; i++)
14331                                         vreg_to_lvreg [lvregs [i]] = 0;
14332                                 lvregs_len = 0;
14333                         } else if (ins->opcode == OP_NOP) {
14334                                 ins->dreg = -1;
14335                                 MONO_INST_NULLIFY_SREGS (ins);
14336                         }
14337
14338                         if (cfg->verbose_level > 2)
14339                                 mono_print_ins_index (1, ins);
14340                 }
14341
14342                 /* Extend the live range based on the liveness info */
14343                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
14344                         for (i = 0; i < cfg->num_varinfo; i ++) {
14345                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
14346
14347                                 if (vreg_is_volatile (cfg, vi->vreg))
14348                                         /* The liveness info is incomplete */
14349                                         continue;
14350
14351                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
14352                                         /* Live from at least the first ins of this bb */
14353                                         live_range_start [vi->vreg] = bb->code;
14354                                         live_range_start_bb [vi->vreg] = bb;
14355                                 }
14356
14357                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
14358                                         /* Live at least until the last ins of this bb */
14359                                         live_range_end [vi->vreg] = bb->last_ins;
14360                                         live_range_end_bb [vi->vreg] = bb;
14361                                 }
14362                         }
14363                 }
14364         }
14365         
14366 #ifdef MONO_ARCH_HAVE_LIVERANGE_OPS
14367         /*
14368          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
14369          * by storing the current native offset into MonoMethodVar->live_range_start/end.
14370          */
14371         if (cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
14372                 for (i = 0; i < cfg->num_varinfo; ++i) {
14373                         int vreg = MONO_VARINFO (cfg, i)->vreg;
14374                         MonoInst *ins;
14375
14376                         if (live_range_start [vreg]) {
14377                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
14378                                 ins->inst_c0 = i;
14379                                 ins->inst_c1 = vreg;
14380                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
14381                         }
14382                         if (live_range_end [vreg]) {
14383                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
14384                                 ins->inst_c0 = i;
14385                                 ins->inst_c1 = vreg;
14386                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
14387                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
14388                                 else
14389                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
14390                         }
14391                 }
14392         }
14393 #endif
14394
14395         if (cfg->gsharedvt_locals_var_ins) {
14396                 /* Nullify if unused */
14397                 cfg->gsharedvt_locals_var_ins->opcode = OP_PCONST;
14398                 cfg->gsharedvt_locals_var_ins->inst_imm = 0;
14399         }
14400
14401         g_free (live_range_start);
14402         g_free (live_range_end);
14403         g_free (live_range_start_bb);
14404         g_free (live_range_end_bb);
14405 }
14406
14407 /**
14408  * FIXME:
14409  * - use 'iadd' instead of 'int_add'
14410  * - handling ovf opcodes: decompose in method_to_ir.
14411  * - unify iregs/fregs
14412  *   -> partly done, the missing parts are:
14413  *   - a more complete unification would involve unifying the hregs as well, so
14414  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
14415  *     would no longer map to the machine hregs, so the code generators would need to
14416  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
14417  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
14418  *     fp/non-fp branches speeds it up by about 15%.
14419  * - use sext/zext opcodes instead of shifts
14420  * - add OP_ICALL
14421  * - get rid of TEMPLOADs if possible and use vregs instead
14422  * - clean up usage of OP_P/OP_ opcodes
14423  * - cleanup usage of DUMMY_USE
14424  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
14425  *   stack
14426  * - set the stack type and allocate a dreg in the EMIT_NEW macros
14427  * - get rid of all the <foo>2 stuff when the new JIT is ready.
14428  * - make sure handle_stack_args () is called before the branch is emitted
14429  * - when the new IR is done, get rid of all unused stuff
14430  * - COMPARE/BEQ as separate instructions or unify them ?
14431  *   - keeping them separate allows specialized compare instructions like
14432  *     compare_imm, compare_membase
14433  *   - most back ends unify fp compare+branch, fp compare+ceq
14434  * - integrate mono_save_args into inline_method
14435  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
14436  * - handle long shift opts on 32 bit platforms somehow: they require 
14437  *   3 sregs (2 for arg1 and 1 for arg2)
14438  * - make byref a 'normal' type.
14439  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
14440  *   variable if needed.
14441  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
14442  *   like inline_method.
14443  * - remove inlining restrictions
14444  * - fix LNEG and enable cfold of INEG
14445  * - generalize x86 optimizations like ldelema as a peephole optimization
14446  * - add store_mem_imm for amd64
14447  * - optimize the loading of the interruption flag in the managed->native wrappers
14448  * - avoid special handling of OP_NOP in passes
14449  * - move code inserting instructions into one function/macro.
14450  * - try a coalescing phase after liveness analysis
14451  * - add float -> vreg conversion + local optimizations on !x86
14452  * - figure out how to handle decomposed branches during optimizations, ie.
14453  *   compare+branch, op_jump_table+op_br etc.
14454  * - promote RuntimeXHandles to vregs
14455  * - vtype cleanups:
14456  *   - add a NEW_VARLOADA_VREG macro
14457  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
14458  *   accessing vtype fields.
14459  * - get rid of I8CONST on 64 bit platforms
14460  * - dealing with the increase in code size due to branches created during opcode
14461  *   decomposition:
14462  *   - use extended basic blocks
14463  *     - all parts of the JIT
14464  *     - handle_global_vregs () && local regalloc
14465  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
14466  * - sources of increase in code size:
14467  *   - vtypes
14468  *   - long compares
14469  *   - isinst and castclass
14470  *   - lvregs not allocated to global registers even if used multiple times
14471  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
14472  *   meaningful.
14473  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
14474  * - add all micro optimizations from the old JIT
14475  * - put tree optimizations into the deadce pass
14476  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
14477  *   specific function.
14478  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
14479  *   fcompare + branchCC.
14480  * - create a helper function for allocating a stack slot, taking into account 
14481  *   MONO_CFG_HAS_SPILLUP.
14482  * - merge r68207.
14483  * - merge the ia64 switch changes.
14484  * - optimize mono_regstate2_alloc_int/float.
14485  * - fix the pessimistic handling of variables accessed in exception handler blocks.
14486  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
14487  *   parts of the tree could be separated by other instructions, killing the tree
14488  *   arguments, or stores killing loads etc. Also, should we fold loads into other
14489  *   instructions if the result of the load is used multiple times ?
14490  * - make the REM_IMM optimization in mini-x86.c arch-independent.
14491  * - LAST MERGE: 108395.
14492  * - when returning vtypes in registers, generate IR and append it to the end of the
14493  *   last bb instead of doing it in the epilog.
14494  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
14495  */
14496
14497 /*
14498
14499 NOTES
14500 -----
14501
14502 - When to decompose opcodes:
14503   - earlier: this makes some optimizations hard to implement, since the low level IR
14504   no longer contains the neccessary information. But it is easier to do.
14505   - later: harder to implement, enables more optimizations.
14506 - Branches inside bblocks:
14507   - created when decomposing complex opcodes. 
14508     - branches to another bblock: harmless, but not tracked by the branch 
14509       optimizations, so need to branch to a label at the start of the bblock.
14510     - branches to inside the same bblock: very problematic, trips up the local
14511       reg allocator. Can be fixed by spitting the current bblock, but that is a
14512       complex operation, since some local vregs can become global vregs etc.
14513 - Local/global vregs:
14514   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
14515     local register allocator.
14516   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
14517     structure, created by mono_create_var (). Assigned to hregs or the stack by
14518     the global register allocator.
14519 - When to do optimizations like alu->alu_imm:
14520   - earlier -> saves work later on since the IR will be smaller/simpler
14521   - later -> can work on more instructions
14522 - Handling of valuetypes:
14523   - When a vtype is pushed on the stack, a new temporary is created, an 
14524     instruction computing its address (LDADDR) is emitted and pushed on
14525     the stack. Need to optimize cases when the vtype is used immediately as in
14526     argument passing, stloc etc.
14527 - Instead of the to_end stuff in the old JIT, simply call the function handling
14528   the values on the stack before emitting the last instruction of the bb.
14529 */
14530
14531 #endif /* DISABLE_JIT */