Merge pull request #2488 from nealef/master
[mono.git] / mono / mini / method-to-ir.c
1 /*
2  * method-to-ir.c: Convert CIL to the JIT internal representation
3  *
4  * Author:
5  *   Paolo Molaro (lupus@ximian.com)
6  *   Dietmar Maurer (dietmar@ximian.com)
7  *
8  * (C) 2002 Ximian, Inc.
9  * Copyright 2003-2010 Novell, Inc (http://www.novell.com)
10  * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
11  */
12
13 #include <config.h>
14
15 #ifndef DISABLE_JIT
16
17 #include <signal.h>
18
19 #ifdef HAVE_UNISTD_H
20 #include <unistd.h>
21 #endif
22
23 #include <math.h>
24 #include <string.h>
25 #include <ctype.h>
26
27 #ifdef HAVE_SYS_TIME_H
28 #include <sys/time.h>
29 #endif
30
31 #ifdef HAVE_ALLOCA_H
32 #include <alloca.h>
33 #endif
34
35 #include <mono/utils/memcheck.h>
36 #include "mini.h"
37 #include <mono/metadata/abi-details.h>
38 #include <mono/metadata/assembly.h>
39 #include <mono/metadata/attrdefs.h>
40 #include <mono/metadata/loader.h>
41 #include <mono/metadata/tabledefs.h>
42 #include <mono/metadata/class.h>
43 #include <mono/metadata/object.h>
44 #include <mono/metadata/exception.h>
45 #include <mono/metadata/opcodes.h>
46 #include <mono/metadata/mono-endian.h>
47 #include <mono/metadata/tokentype.h>
48 #include <mono/metadata/tabledefs.h>
49 #include <mono/metadata/marshal.h>
50 #include <mono/metadata/debug-helpers.h>
51 #include <mono/metadata/mono-debug.h>
52 #include <mono/metadata/mono-debug-debugger.h>
53 #include <mono/metadata/gc-internals.h>
54 #include <mono/metadata/security-manager.h>
55 #include <mono/metadata/threads-types.h>
56 #include <mono/metadata/security-core-clr.h>
57 #include <mono/metadata/profiler-private.h>
58 #include <mono/metadata/profiler.h>
59 #include <mono/metadata/debug-mono-symfile.h>
60 #include <mono/utils/mono-compiler.h>
61 #include <mono/utils/mono-memory-model.h>
62 #include <mono/metadata/mono-basic-block.h>
63
64 #include "trace.h"
65
66 #include "ir-emit.h"
67
68 #include "jit-icalls.h"
69 #include "jit.h"
70 #include "debugger-agent.h"
71 #include "seq-points.h"
72 #include "aot-compiler.h"
73 #include "mini-llvm.h"
74
75 #define BRANCH_COST 10
76 #define INLINE_LENGTH_LIMIT 20
77
78 /* These have 'cfg' as an implicit argument */
79 #define INLINE_FAILURE(msg) do {                                                                        \
80         if ((cfg->method != cfg->current_method) && (cfg->current_method->wrapper_type == MONO_WRAPPER_NONE)) { \
81                 inline_failure (cfg, msg);                                                                              \
82                 goto exception_exit;                                                                                    \
83         } \
84         } while (0)
85 #define CHECK_CFG_EXCEPTION do {\
86                 if (cfg->exception_type != MONO_EXCEPTION_NONE) \
87                         goto exception_exit;                                            \
88         } while (0)
89 #define METHOD_ACCESS_FAILURE(method, cmethod) do {                     \
90                 method_access_failure ((cfg), (method), (cmethod));                     \
91                 goto exception_exit;                                                                            \
92         } while (0)
93 #define FIELD_ACCESS_FAILURE(method, field) do {                                        \
94                 field_access_failure ((cfg), (method), (field));                        \
95                 goto exception_exit;    \
96         } while (0)
97 #define GENERIC_SHARING_FAILURE(opcode) do {            \
98                 if (cfg->gshared) {                                                                     \
99                         gshared_failure (cfg, opcode, __FILE__, __LINE__);      \
100                         goto exception_exit;    \
101                 }                       \
102         } while (0)
103 #define GSHAREDVT_FAILURE(opcode) do {          \
104         if (cfg->gsharedvt) {                                                                                           \
105                 gsharedvt_failure (cfg, opcode, __FILE__, __LINE__);                    \
106                 goto exception_exit;                                                                                    \
107         }                                                                                                                                       \
108         } while (0)
109 #define OUT_OF_MEMORY_FAILURE do {      \
110                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_OUT_OF_MEMORY);             \
111                 goto exception_exit;    \
112         } while (0)
113 #define DISABLE_AOT(cfg) do { \
114                 if ((cfg)->verbose_level >= 2)                                            \
115                         printf ("AOT disabled: %s:%d\n", __FILE__, __LINE__);   \
116                 (cfg)->disable_aot = TRUE;                                                        \
117         } while (0)
118 #define LOAD_ERROR do { \
119                 break_on_unverified ();                                                         \
120                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD); \
121                 goto exception_exit;                                                                    \
122         } while (0)
123
124 #define TYPE_LOAD_ERROR(klass) do { \
125                 cfg->exception_ptr = klass; \
126                 LOAD_ERROR;                                     \
127         } while (0)
128
129 #define CHECK_CFG_ERROR do {\
130                 if (!mono_error_ok (&cfg->error)) { \
131                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);        \
132                         goto mono_error_exit; \
133                 } \
134         } while (0)
135
136 /* Determine whenever 'ins' represents a load of the 'this' argument */
137 #define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && ((ins)->opcode == OP_MOVE) && ((ins)->sreg1 == cfg->args [0]->dreg))
138
139 static int ldind_to_load_membase (int opcode);
140 static int stind_to_store_membase (int opcode);
141
142 int mono_op_to_op_imm (int opcode);
143 int mono_op_to_op_imm_noemul (int opcode);
144
145 MONO_API MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
146
147 static int inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
148                                                   guchar *ip, guint real_offset, gboolean inline_always);
149 static MonoInst*
150 emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used, MonoInst **sp);
151
152 /* helper methods signatures */
153 static MonoMethodSignature *helper_sig_domain_get;
154 static MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline;
155 static MonoMethodSignature *helper_sig_llvmonly_imt_thunk;
156
157 /*
158  * Instruction metadata
159  */
160 #ifdef MINI_OP
161 #undef MINI_OP
162 #endif
163 #ifdef MINI_OP3
164 #undef MINI_OP3
165 #endif
166 #define MINI_OP(a,b,dest,src1,src2) dest, src1, src2, ' ',
167 #define MINI_OP3(a,b,dest,src1,src2,src3) dest, src1, src2, src3,
168 #define NONE ' '
169 #define IREG 'i'
170 #define FREG 'f'
171 #define VREG 'v'
172 #define XREG 'x'
173 #if SIZEOF_REGISTER == 8 && SIZEOF_REGISTER == SIZEOF_VOID_P
174 #define LREG IREG
175 #else
176 #define LREG 'l'
177 #endif
178 /* keep in sync with the enum in mini.h */
179 const char
180 ins_info[] = {
181 #include "mini-ops.h"
182 };
183 #undef MINI_OP
184 #undef MINI_OP3
185
186 #define MINI_OP(a,b,dest,src1,src2) ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0)),
187 #define MINI_OP3(a,b,dest,src1,src2,src3) ((src3) != NONE ? 3 : ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0))),
188 /* 
189  * This should contain the index of the last sreg + 1. This is not the same
190  * as the number of sregs for opcodes like IA64_CMP_EQ_IMM.
191  */
192 const gint8 ins_sreg_counts[] = {
193 #include "mini-ops.h"
194 };
195 #undef MINI_OP
196 #undef MINI_OP3
197
198 #define MONO_INIT_VARINFO(vi,id) do { \
199         (vi)->range.first_use.pos.bid = 0xffff; \
200         (vi)->reg = -1; \
201         (vi)->idx = (id); \
202 } while (0)
203
204 guint32
205 mono_alloc_ireg (MonoCompile *cfg)
206 {
207         return alloc_ireg (cfg);
208 }
209
210 guint32
211 mono_alloc_lreg (MonoCompile *cfg)
212 {
213         return alloc_lreg (cfg);
214 }
215
216 guint32
217 mono_alloc_freg (MonoCompile *cfg)
218 {
219         return alloc_freg (cfg);
220 }
221
222 guint32
223 mono_alloc_preg (MonoCompile *cfg)
224 {
225         return alloc_preg (cfg);
226 }
227
228 guint32
229 mono_alloc_dreg (MonoCompile *cfg, MonoStackType stack_type)
230 {
231         return alloc_dreg (cfg, stack_type);
232 }
233
234 /*
235  * mono_alloc_ireg_ref:
236  *
237  *   Allocate an IREG, and mark it as holding a GC ref.
238  */
239 guint32
240 mono_alloc_ireg_ref (MonoCompile *cfg)
241 {
242         return alloc_ireg_ref (cfg);
243 }
244
245 /*
246  * mono_alloc_ireg_mp:
247  *
248  *   Allocate an IREG, and mark it as holding a managed pointer.
249  */
250 guint32
251 mono_alloc_ireg_mp (MonoCompile *cfg)
252 {
253         return alloc_ireg_mp (cfg);
254 }
255
256 /*
257  * mono_alloc_ireg_copy:
258  *
259  *   Allocate an IREG with the same GC type as VREG.
260  */
261 guint32
262 mono_alloc_ireg_copy (MonoCompile *cfg, guint32 vreg)
263 {
264         if (vreg_is_ref (cfg, vreg))
265                 return alloc_ireg_ref (cfg);
266         else if (vreg_is_mp (cfg, vreg))
267                 return alloc_ireg_mp (cfg);
268         else
269                 return alloc_ireg (cfg);
270 }
271
272 guint
273 mono_type_to_regmove (MonoCompile *cfg, MonoType *type)
274 {
275         if (type->byref)
276                 return OP_MOVE;
277
278         type = mini_get_underlying_type (type);
279 handle_enum:
280         switch (type->type) {
281         case MONO_TYPE_I1:
282         case MONO_TYPE_U1:
283                 return OP_MOVE;
284         case MONO_TYPE_I2:
285         case MONO_TYPE_U2:
286                 return OP_MOVE;
287         case MONO_TYPE_I4:
288         case MONO_TYPE_U4:
289                 return OP_MOVE;
290         case MONO_TYPE_I:
291         case MONO_TYPE_U:
292         case MONO_TYPE_PTR:
293         case MONO_TYPE_FNPTR:
294                 return OP_MOVE;
295         case MONO_TYPE_CLASS:
296         case MONO_TYPE_STRING:
297         case MONO_TYPE_OBJECT:
298         case MONO_TYPE_SZARRAY:
299         case MONO_TYPE_ARRAY:    
300                 return OP_MOVE;
301         case MONO_TYPE_I8:
302         case MONO_TYPE_U8:
303 #if SIZEOF_REGISTER == 8
304                 return OP_MOVE;
305 #else
306                 return OP_LMOVE;
307 #endif
308         case MONO_TYPE_R4:
309                 return cfg->r4fp ? OP_RMOVE : OP_FMOVE;
310         case MONO_TYPE_R8:
311                 return OP_FMOVE;
312         case MONO_TYPE_VALUETYPE:
313                 if (type->data.klass->enumtype) {
314                         type = mono_class_enum_basetype (type->data.klass);
315                         goto handle_enum;
316                 }
317                 if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
318                         return OP_XMOVE;
319                 return OP_VMOVE;
320         case MONO_TYPE_TYPEDBYREF:
321                 return OP_VMOVE;
322         case MONO_TYPE_GENERICINST:
323                 type = &type->data.generic_class->container_class->byval_arg;
324                 goto handle_enum;
325         case MONO_TYPE_VAR:
326         case MONO_TYPE_MVAR:
327                 g_assert (cfg->gshared);
328                 if (mini_type_var_is_vt (type))
329                         return OP_VMOVE;
330                 else
331                         return mono_type_to_regmove (cfg, mini_get_underlying_type (type));
332         default:
333                 g_error ("unknown type 0x%02x in type_to_regstore", type->type);
334         }
335         return -1;
336 }
337
338 void
339 mono_print_bb (MonoBasicBlock *bb, const char *msg)
340 {
341         int i;
342         MonoInst *tree;
343
344         printf ("\n%s %d: [IN: ", msg, bb->block_num);
345         for (i = 0; i < bb->in_count; ++i)
346                 printf (" BB%d(%d)", bb->in_bb [i]->block_num, bb->in_bb [i]->dfn);
347         printf (", OUT: ");
348         for (i = 0; i < bb->out_count; ++i)
349                 printf (" BB%d(%d)", bb->out_bb [i]->block_num, bb->out_bb [i]->dfn);
350         printf (" ]\n");
351         for (tree = bb->code; tree; tree = tree->next)
352                 mono_print_ins_index (-1, tree);
353 }
354
355 void
356 mono_create_helper_signatures (void)
357 {
358         helper_sig_domain_get = mono_create_icall_signature ("ptr");
359         helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
360         helper_sig_llvmonly_imt_thunk = mono_create_icall_signature ("ptr ptr ptr");
361 }
362
363 static MONO_NEVER_INLINE void
364 break_on_unverified (void)
365 {
366         if (mini_get_debug_options ()->break_on_unverified)
367                 G_BREAKPOINT ();
368 }
369
370 static MONO_NEVER_INLINE void
371 method_access_failure (MonoCompile *cfg, MonoMethod *method, MonoMethod *cil_method)
372 {
373         char *method_fname = mono_method_full_name (method, TRUE);
374         char *cil_method_fname = mono_method_full_name (cil_method, TRUE);
375         mono_cfg_set_exception (cfg, MONO_EXCEPTION_METHOD_ACCESS);
376         cfg->exception_message = g_strdup_printf ("Method `%s' is inaccessible from method `%s'\n", cil_method_fname, method_fname);
377         g_free (method_fname);
378         g_free (cil_method_fname);
379 }
380
381 static MONO_NEVER_INLINE void
382 field_access_failure (MonoCompile *cfg, MonoMethod *method, MonoClassField *field)
383 {
384         char *method_fname = mono_method_full_name (method, TRUE);
385         char *field_fname = mono_field_full_name (field);
386         mono_cfg_set_exception (cfg, MONO_EXCEPTION_FIELD_ACCESS);
387         cfg->exception_message = g_strdup_printf ("Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname);
388         g_free (method_fname);
389         g_free (field_fname);
390 }
391
392 static MONO_NEVER_INLINE void
393 inline_failure (MonoCompile *cfg, const char *msg)
394 {
395         if (cfg->verbose_level >= 2)
396                 printf ("inline failed: %s\n", msg);
397         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INLINE_FAILED);
398 }
399
400 static MONO_NEVER_INLINE void
401 gshared_failure (MonoCompile *cfg, int opcode, const char *file, int line)
402 {
403         if (cfg->verbose_level > 2)                                                                                     \
404                 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);
405         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
406 }
407
408 static MONO_NEVER_INLINE void
409 gsharedvt_failure (MonoCompile *cfg, int opcode, const char *file, int line)
410 {
411         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);
412         if (cfg->verbose_level >= 2)
413                 printf ("%s\n", cfg->exception_message);
414         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
415 }
416
417 /*
418  * When using gsharedvt, some instatiations might be verifiable, and some might be not. i.e. 
419  * foo<T> (int i) { ldarg.0; box T; }
420  */
421 #define UNVERIFIED do { \
422         if (cfg->gsharedvt) { \
423                 if (cfg->verbose_level > 2)                                                                     \
424                         printf ("gsharedvt method failed to verify, falling back to instantiation.\n"); \
425                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED); \
426                 goto exception_exit;                                                                                    \
427         }                                                                                                                                       \
428         break_on_unverified ();                                                                                         \
429         goto unverified;                                                                                                        \
430 } while (0)
431
432 #define GET_BBLOCK(cfg,tblock,ip) do {  \
433                 (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
434                 if (!(tblock)) {        \
435                         if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
436             NEW_BBLOCK (cfg, (tblock)); \
437                         (tblock)->cil_code = (ip);      \
438                         ADD_BBLOCK (cfg, (tblock));     \
439                 } \
440         } while (0)
441
442 #if defined(TARGET_X86) || defined(TARGET_AMD64)
443 #define EMIT_NEW_X86_LEA(cfg,dest,sr1,sr2,shift,imm) do { \
444                 MONO_INST_NEW (cfg, dest, OP_X86_LEA); \
445                 (dest)->dreg = alloc_ireg_mp ((cfg)); \
446                 (dest)->sreg1 = (sr1); \
447                 (dest)->sreg2 = (sr2); \
448                 (dest)->inst_imm = (imm); \
449                 (dest)->backend.shift_amount = (shift); \
450                 MONO_ADD_INS ((cfg)->cbb, (dest)); \
451         } while (0)
452 #endif
453
454 /* Emit conversions so both operands of a binary opcode are of the same type */
455 static void
456 add_widen_op (MonoCompile *cfg, MonoInst *ins, MonoInst **arg1_ref, MonoInst **arg2_ref)
457 {
458         MonoInst *arg1 = *arg1_ref;
459         MonoInst *arg2 = *arg2_ref;
460
461         if (cfg->r4fp &&
462                 ((arg1->type == STACK_R4 && arg2->type == STACK_R8) ||
463                  (arg1->type == STACK_R8 && arg2->type == STACK_R4))) {
464                 MonoInst *conv;
465
466                 /* Mixing r4/r8 is allowed by the spec */
467                 if (arg1->type == STACK_R4) {
468                         int dreg = alloc_freg (cfg);
469
470                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg1->dreg);
471                         conv->type = STACK_R8;
472                         ins->sreg1 = dreg;
473                         *arg1_ref = conv;
474                 }
475                 if (arg2->type == STACK_R4) {
476                         int dreg = alloc_freg (cfg);
477
478                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg2->dreg);
479                         conv->type = STACK_R8;
480                         ins->sreg2 = dreg;
481                         *arg2_ref = conv;
482                 }
483         }
484
485 #if SIZEOF_REGISTER == 8
486         /* FIXME: Need to add many more cases */
487         if ((arg1)->type == STACK_PTR && (arg2)->type == STACK_I4) {
488                 MonoInst *widen;
489
490                 int dr = alloc_preg (cfg);
491                 EMIT_NEW_UNALU (cfg, widen, OP_SEXT_I4, dr, (arg2)->dreg);
492                 (ins)->sreg2 = widen->dreg;
493         }
494 #endif
495 }
496
497 #define ADD_BINOP(op) do {      \
498                 MONO_INST_NEW (cfg, ins, (op)); \
499                 sp -= 2;        \
500                 ins->sreg1 = sp [0]->dreg;      \
501                 ins->sreg2 = sp [1]->dreg;      \
502                 type_from_op (cfg, ins, sp [0], sp [1]);        \
503                 CHECK_TYPE (ins);       \
504                 /* Have to insert a widening op */               \
505         add_widen_op (cfg, ins, &sp [0], &sp [1]);               \
506         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type); \
507         MONO_ADD_INS ((cfg)->cbb, (ins)); \
508         *sp++ = mono_decompose_opcode ((cfg), (ins));   \
509         } while (0)
510
511 #define ADD_UNOP(op) do {       \
512                 MONO_INST_NEW (cfg, ins, (op)); \
513                 sp--;   \
514                 ins->sreg1 = sp [0]->dreg;      \
515                 type_from_op (cfg, ins, sp [0], NULL);  \
516                 CHECK_TYPE (ins);       \
517         (ins)->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type); \
518         MONO_ADD_INS ((cfg)->cbb, (ins)); \
519                 *sp++ = mono_decompose_opcode (cfg, ins);       \
520         } while (0)
521
522 #define ADD_BINCOND(next_block) do {    \
523                 MonoInst *cmp;  \
524                 sp -= 2; \
525                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
526                 cmp->sreg1 = sp [0]->dreg;      \
527                 cmp->sreg2 = sp [1]->dreg;      \
528                 type_from_op (cfg, cmp, sp [0], sp [1]);        \
529                 CHECK_TYPE (cmp);       \
530                 add_widen_op (cfg, cmp, &sp [0], &sp [1]);                                              \
531                 type_from_op (cfg, ins, sp [0], sp [1]);                                                        \
532                 ins->inst_many_bb = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);   \
533                 GET_BBLOCK (cfg, tblock, target);               \
534                 link_bblock (cfg, cfg->cbb, tblock);    \
535                 ins->inst_true_bb = tblock;     \
536                 if ((next_block)) {     \
537                         link_bblock (cfg, cfg->cbb, (next_block));      \
538                         ins->inst_false_bb = (next_block);      \
539                         start_new_bblock = 1;   \
540                 } else {        \
541                         GET_BBLOCK (cfg, tblock, ip);           \
542                         link_bblock (cfg, cfg->cbb, tblock);    \
543                         ins->inst_false_bb = tblock;    \
544                         start_new_bblock = 2;   \
545                 }       \
546                 if (sp != stack_start) {                                                                        \
547                     handle_stack_args (cfg, stack_start, sp - stack_start); \
548                         CHECK_UNVERIFIABLE (cfg); \
549                 } \
550         MONO_ADD_INS (cfg->cbb, cmp); \
551                 MONO_ADD_INS (cfg->cbb, ins);   \
552         } while (0)
553
554 /* *
555  * link_bblock: Links two basic blocks
556  *
557  * links two basic blocks in the control flow graph, the 'from'
558  * argument is the starting block and the 'to' argument is the block
559  * the control flow ends to after 'from'.
560  */
561 static void
562 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
563 {
564         MonoBasicBlock **newa;
565         int i, found;
566
567 #if 0
568         if (from->cil_code) {
569                 if (to->cil_code)
570                         printf ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
571                 else
572                         printf ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
573         } else {
574                 if (to->cil_code)
575                         printf ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
576                 else
577                         printf ("edge from entry to exit\n");
578         }
579 #endif
580
581         found = FALSE;
582         for (i = 0; i < from->out_count; ++i) {
583                 if (to == from->out_bb [i]) {
584                         found = TRUE;
585                         break;
586                 }
587         }
588         if (!found) {
589                 newa = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
590                 for (i = 0; i < from->out_count; ++i) {
591                         newa [i] = from->out_bb [i];
592                 }
593                 newa [i] = to;
594                 from->out_count++;
595                 from->out_bb = newa;
596         }
597
598         found = FALSE;
599         for (i = 0; i < to->in_count; ++i) {
600                 if (from == to->in_bb [i]) {
601                         found = TRUE;
602                         break;
603                 }
604         }
605         if (!found) {
606                 newa = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
607                 for (i = 0; i < to->in_count; ++i) {
608                         newa [i] = to->in_bb [i];
609                 }
610                 newa [i] = from;
611                 to->in_count++;
612                 to->in_bb = newa;
613         }
614 }
615
616 void
617 mono_link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
618 {
619         link_bblock (cfg, from, to);
620 }
621
622 /**
623  * mono_find_block_region:
624  *
625  *   We mark each basic block with a region ID. We use that to avoid BB
626  *   optimizations when blocks are in different regions.
627  *
628  * Returns:
629  *   A region token that encodes where this region is, and information
630  *   about the clause owner for this block.
631  *
632  *   The region encodes the try/catch/filter clause that owns this block
633  *   as well as the type.  -1 is a special value that represents a block
634  *   that is in none of try/catch/filter.
635  */
636 static int
637 mono_find_block_region (MonoCompile *cfg, int offset)
638 {
639         MonoMethodHeader *header = cfg->header;
640         MonoExceptionClause *clause;
641         int i;
642
643         for (i = 0; i < header->num_clauses; ++i) {
644                 clause = &header->clauses [i];
645                 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
646                     (offset < (clause->handler_offset)))
647                         return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
648                            
649                 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
650                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
651                                 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
652                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
653                                 return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
654                         else
655                                 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
656                 }
657         }
658         for (i = 0; i < header->num_clauses; ++i) {
659                 clause = &header->clauses [i];
660
661                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
662                         return ((i + 1) << 8) | clause->flags;
663         }
664
665         return -1;
666 }
667
668 static GList*
669 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
670 {
671         MonoMethodHeader *header = cfg->header;
672         MonoExceptionClause *clause;
673         int i;
674         GList *res = NULL;
675
676         for (i = 0; i < header->num_clauses; ++i) {
677                 clause = &header->clauses [i];
678                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
679                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
680                         if (clause->flags == type)
681                                 res = g_list_append (res, clause);
682                 }
683         }
684         return res;
685 }
686
687 static void
688 mono_create_spvar_for_region (MonoCompile *cfg, int region)
689 {
690         MonoInst *var;
691
692         var = (MonoInst *)g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
693         if (var)
694                 return;
695
696         var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
697         /* prevent it from being register allocated */
698         var->flags |= MONO_INST_VOLATILE;
699
700         g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
701 }
702
703 MonoInst *
704 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
705 {
706         return (MonoInst *)g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
707 }
708
709 static MonoInst*
710 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
711 {
712         MonoInst *var;
713
714         var = (MonoInst *)g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
715         if (var)
716                 return var;
717
718         var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
719         /* prevent it from being register allocated */
720         var->flags |= MONO_INST_VOLATILE;
721
722         g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
723
724         return var;
725 }
726
727 /*
728  * Returns the type used in the eval stack when @type is loaded.
729  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
730  */
731 void
732 type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
733 {
734         MonoClass *klass;
735
736         type = mini_get_underlying_type (type);
737         inst->klass = klass = mono_class_from_mono_type (type);
738         if (type->byref) {
739                 inst->type = STACK_MP;
740                 return;
741         }
742
743 handle_enum:
744         switch (type->type) {
745         case MONO_TYPE_VOID:
746                 inst->type = STACK_INV;
747                 return;
748         case MONO_TYPE_I1:
749         case MONO_TYPE_U1:
750         case MONO_TYPE_I2:
751         case MONO_TYPE_U2:
752         case MONO_TYPE_I4:
753         case MONO_TYPE_U4:
754                 inst->type = STACK_I4;
755                 return;
756         case MONO_TYPE_I:
757         case MONO_TYPE_U:
758         case MONO_TYPE_PTR:
759         case MONO_TYPE_FNPTR:
760                 inst->type = STACK_PTR;
761                 return;
762         case MONO_TYPE_CLASS:
763         case MONO_TYPE_STRING:
764         case MONO_TYPE_OBJECT:
765         case MONO_TYPE_SZARRAY:
766         case MONO_TYPE_ARRAY:    
767                 inst->type = STACK_OBJ;
768                 return;
769         case MONO_TYPE_I8:
770         case MONO_TYPE_U8:
771                 inst->type = STACK_I8;
772                 return;
773         case MONO_TYPE_R4:
774                 inst->type = cfg->r4_stack_type;
775                 break;
776         case MONO_TYPE_R8:
777                 inst->type = STACK_R8;
778                 return;
779         case MONO_TYPE_VALUETYPE:
780                 if (type->data.klass->enumtype) {
781                         type = mono_class_enum_basetype (type->data.klass);
782                         goto handle_enum;
783                 } else {
784                         inst->klass = klass;
785                         inst->type = STACK_VTYPE;
786                         return;
787                 }
788         case MONO_TYPE_TYPEDBYREF:
789                 inst->klass = mono_defaults.typed_reference_class;
790                 inst->type = STACK_VTYPE;
791                 return;
792         case MONO_TYPE_GENERICINST:
793                 type = &type->data.generic_class->container_class->byval_arg;
794                 goto handle_enum;
795         case MONO_TYPE_VAR:
796         case MONO_TYPE_MVAR:
797                 g_assert (cfg->gshared);
798                 if (mini_is_gsharedvt_type (type)) {
799                         g_assert (cfg->gsharedvt);
800                         inst->type = STACK_VTYPE;
801                 } else {
802                         type_to_eval_stack_type (cfg, mini_get_underlying_type (type), inst);
803                 }
804                 return;
805         default:
806                 g_error ("unknown type 0x%02x in eval stack type", type->type);
807         }
808 }
809
810 /*
811  * The following tables are used to quickly validate the IL code in type_from_op ().
812  */
813 static const char
814 bin_num_table [STACK_MAX] [STACK_MAX] = {
815         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
816         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
817         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
818         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
819         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV, STACK_R8},
820         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
821         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, 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_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4}
824 };
825
826 static const char 
827 neg_table [] = {
828         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4
829 };
830
831 /* reduce the size of this table */
832 static const char
833 bin_int_table [STACK_MAX] [STACK_MAX] = {
834         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
835         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
836         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
837         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
838         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, 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 };
843
844 static const char
845 bin_comp_table [STACK_MAX] [STACK_MAX] = {
846 /*      Inv i  L  p  F  &  O  vt r4 */
847         {0},
848         {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
849         {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
850         {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
851         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* F, R8 */
852         {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
853         {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
854         {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
855         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* r, r4 */
856 };
857
858 /* reduce the size of this table */
859 static const char
860 shift_table [STACK_MAX] [STACK_MAX] = {
861         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
862         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
863         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
864         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
865         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, 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 };
870
871 /*
872  * Tables to map from the non-specific opcode to the matching
873  * type-specific opcode.
874  */
875 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
876 static const guint16
877 binops_op_map [STACK_MAX] = {
878         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
879 };
880
881 /* handles from CEE_NEG to CEE_CONV_U8 */
882 static const guint16
883 unops_op_map [STACK_MAX] = {
884         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
885 };
886
887 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
888 static const guint16
889 ovfops_op_map [STACK_MAX] = {
890         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
891 };
892
893 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
894 static const guint16
895 ovf2ops_op_map [STACK_MAX] = {
896         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
897 };
898
899 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
900 static const guint16
901 ovf3ops_op_map [STACK_MAX] = {
902         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
903 };
904
905 /* handles from CEE_BEQ to CEE_BLT_UN */
906 static const guint16
907 beqops_op_map [STACK_MAX] = {
908         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
909 };
910
911 /* handles from CEE_CEQ to CEE_CLT_UN */
912 static const guint16
913 ceqops_op_map [STACK_MAX] = {
914         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
915 };
916
917 /*
918  * Sets ins->type (the type on the eval stack) according to the
919  * type of the opcode and the arguments to it.
920  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
921  *
922  * FIXME: this function sets ins->type unconditionally in some cases, but
923  * it should set it to invalid for some types (a conv.x on an object)
924  */
925 static void
926 type_from_op (MonoCompile *cfg, MonoInst *ins, MonoInst *src1, MonoInst *src2)
927 {
928         switch (ins->opcode) {
929         /* binops */
930         case CEE_ADD:
931         case CEE_SUB:
932         case CEE_MUL:
933         case CEE_DIV:
934         case CEE_REM:
935                 /* FIXME: check unverifiable args for STACK_MP */
936                 ins->type = bin_num_table [src1->type] [src2->type];
937                 ins->opcode += binops_op_map [ins->type];
938                 break;
939         case CEE_DIV_UN:
940         case CEE_REM_UN:
941         case CEE_AND:
942         case CEE_OR:
943         case CEE_XOR:
944                 ins->type = bin_int_table [src1->type] [src2->type];
945                 ins->opcode += binops_op_map [ins->type];
946                 break;
947         case CEE_SHL:
948         case CEE_SHR:
949         case CEE_SHR_UN:
950                 ins->type = shift_table [src1->type] [src2->type];
951                 ins->opcode += binops_op_map [ins->type];
952                 break;
953         case OP_COMPARE:
954         case OP_LCOMPARE:
955         case OP_ICOMPARE:
956                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
957                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
958                         ins->opcode = OP_LCOMPARE;
959                 else if (src1->type == STACK_R4)
960                         ins->opcode = OP_RCOMPARE;
961                 else if (src1->type == STACK_R8)
962                         ins->opcode = OP_FCOMPARE;
963                 else
964                         ins->opcode = OP_ICOMPARE;
965                 break;
966         case OP_ICOMPARE_IMM:
967                 ins->type = bin_comp_table [src1->type] [src1->type] ? STACK_I4 : STACK_INV;
968                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
969                         ins->opcode = OP_LCOMPARE_IMM;          
970                 break;
971         case CEE_BEQ:
972         case CEE_BGE:
973         case CEE_BGT:
974         case CEE_BLE:
975         case CEE_BLT:
976         case CEE_BNE_UN:
977         case CEE_BGE_UN:
978         case CEE_BGT_UN:
979         case CEE_BLE_UN:
980         case CEE_BLT_UN:
981                 ins->opcode += beqops_op_map [src1->type];
982                 break;
983         case OP_CEQ:
984                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
985                 ins->opcode += ceqops_op_map [src1->type];
986                 break;
987         case OP_CGT:
988         case OP_CGT_UN:
989         case OP_CLT:
990         case OP_CLT_UN:
991                 ins->type = (bin_comp_table [src1->type] [src2->type] & 1) ? STACK_I4: STACK_INV;
992                 ins->opcode += ceqops_op_map [src1->type];
993                 break;
994         /* unops */
995         case CEE_NEG:
996                 ins->type = neg_table [src1->type];
997                 ins->opcode += unops_op_map [ins->type];
998                 break;
999         case CEE_NOT:
1000                 if (src1->type >= STACK_I4 && src1->type <= STACK_PTR)
1001                         ins->type = src1->type;
1002                 else
1003                         ins->type = STACK_INV;
1004                 ins->opcode += unops_op_map [ins->type];
1005                 break;
1006         case CEE_CONV_I1:
1007         case CEE_CONV_I2:
1008         case CEE_CONV_I4:
1009         case CEE_CONV_U4:
1010                 ins->type = STACK_I4;
1011                 ins->opcode += unops_op_map [src1->type];
1012                 break;
1013         case CEE_CONV_R_UN:
1014                 ins->type = STACK_R8;
1015                 switch (src1->type) {
1016                 case STACK_I4:
1017                 case STACK_PTR:
1018                         ins->opcode = OP_ICONV_TO_R_UN;
1019                         break;
1020                 case STACK_I8:
1021                         ins->opcode = OP_LCONV_TO_R_UN; 
1022                         break;
1023                 }
1024                 break;
1025         case CEE_CONV_OVF_I1:
1026         case CEE_CONV_OVF_U1:
1027         case CEE_CONV_OVF_I2:
1028         case CEE_CONV_OVF_U2:
1029         case CEE_CONV_OVF_I4:
1030         case CEE_CONV_OVF_U4:
1031                 ins->type = STACK_I4;
1032                 ins->opcode += ovf3ops_op_map [src1->type];
1033                 break;
1034         case CEE_CONV_OVF_I_UN:
1035         case CEE_CONV_OVF_U_UN:
1036                 ins->type = STACK_PTR;
1037                 ins->opcode += ovf2ops_op_map [src1->type];
1038                 break;
1039         case CEE_CONV_OVF_I1_UN:
1040         case CEE_CONV_OVF_I2_UN:
1041         case CEE_CONV_OVF_I4_UN:
1042         case CEE_CONV_OVF_U1_UN:
1043         case CEE_CONV_OVF_U2_UN:
1044         case CEE_CONV_OVF_U4_UN:
1045                 ins->type = STACK_I4;
1046                 ins->opcode += ovf2ops_op_map [src1->type];
1047                 break;
1048         case CEE_CONV_U:
1049                 ins->type = STACK_PTR;
1050                 switch (src1->type) {
1051                 case STACK_I4:
1052                         ins->opcode = OP_ICONV_TO_U;
1053                         break;
1054                 case STACK_PTR:
1055                 case STACK_MP:
1056 #if SIZEOF_VOID_P == 8
1057                         ins->opcode = OP_LCONV_TO_U;
1058 #else
1059                         ins->opcode = OP_MOVE;
1060 #endif
1061                         break;
1062                 case STACK_I8:
1063                         ins->opcode = OP_LCONV_TO_U;
1064                         break;
1065                 case STACK_R8:
1066                         ins->opcode = OP_FCONV_TO_U;
1067                         break;
1068                 }
1069                 break;
1070         case CEE_CONV_I8:
1071         case CEE_CONV_U8:
1072                 ins->type = STACK_I8;
1073                 ins->opcode += unops_op_map [src1->type];
1074                 break;
1075         case CEE_CONV_OVF_I8:
1076         case CEE_CONV_OVF_U8:
1077                 ins->type = STACK_I8;
1078                 ins->opcode += ovf3ops_op_map [src1->type];
1079                 break;
1080         case CEE_CONV_OVF_U8_UN:
1081         case CEE_CONV_OVF_I8_UN:
1082                 ins->type = STACK_I8;
1083                 ins->opcode += ovf2ops_op_map [src1->type];
1084                 break;
1085         case CEE_CONV_R4:
1086                 ins->type = cfg->r4_stack_type;
1087                 ins->opcode += unops_op_map [src1->type];
1088                 break;
1089         case CEE_CONV_R8:
1090                 ins->type = STACK_R8;
1091                 ins->opcode += unops_op_map [src1->type];
1092                 break;
1093         case OP_CKFINITE:
1094                 ins->type = STACK_R8;           
1095                 break;
1096         case CEE_CONV_U2:
1097         case CEE_CONV_U1:
1098                 ins->type = STACK_I4;
1099                 ins->opcode += ovfops_op_map [src1->type];
1100                 break;
1101         case CEE_CONV_I:
1102         case CEE_CONV_OVF_I:
1103         case CEE_CONV_OVF_U:
1104                 ins->type = STACK_PTR;
1105                 ins->opcode += ovfops_op_map [src1->type];
1106                 break;
1107         case CEE_ADD_OVF:
1108         case CEE_ADD_OVF_UN:
1109         case CEE_MUL_OVF:
1110         case CEE_MUL_OVF_UN:
1111         case CEE_SUB_OVF:
1112         case CEE_SUB_OVF_UN:
1113                 ins->type = bin_num_table [src1->type] [src2->type];
1114                 ins->opcode += ovfops_op_map [src1->type];
1115                 if (ins->type == STACK_R8)
1116                         ins->type = STACK_INV;
1117                 break;
1118         case OP_LOAD_MEMBASE:
1119                 ins->type = STACK_PTR;
1120                 break;
1121         case OP_LOADI1_MEMBASE:
1122         case OP_LOADU1_MEMBASE:
1123         case OP_LOADI2_MEMBASE:
1124         case OP_LOADU2_MEMBASE:
1125         case OP_LOADI4_MEMBASE:
1126         case OP_LOADU4_MEMBASE:
1127                 ins->type = STACK_PTR;
1128                 break;
1129         case OP_LOADI8_MEMBASE:
1130                 ins->type = STACK_I8;
1131                 break;
1132         case OP_LOADR4_MEMBASE:
1133                 ins->type = cfg->r4_stack_type;
1134                 break;
1135         case OP_LOADR8_MEMBASE:
1136                 ins->type = STACK_R8;
1137                 break;
1138         default:
1139                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1140                 break;
1141         }
1142
1143         if (ins->type == STACK_MP)
1144                 ins->klass = mono_defaults.object_class;
1145 }
1146
1147 static const char 
1148 ldind_type [] = {
1149         STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
1150 };
1151
1152 #if 0
1153
1154 static const char
1155 param_table [STACK_MAX] [STACK_MAX] = {
1156         {0},
1157 };
1158
1159 static int
1160 check_values_to_signature (MonoInst *args, MonoType *this_ins, MonoMethodSignature *sig)
1161 {
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         if (!cfg->compile_aot || !cfg->backend->need_got_var)
1237                 return NULL;
1238         if (!cfg->got_var) {
1239                 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1240         }
1241         return cfg->got_var;
1242 }
1243
1244 static MonoInst *
1245 mono_get_vtable_var (MonoCompile *cfg)
1246 {
1247         g_assert (cfg->gshared);
1248
1249         if (!cfg->rgctx_var) {
1250                 cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1251                 /* force the var to be stack allocated */
1252                 cfg->rgctx_var->flags |= MONO_INST_VOLATILE;
1253         }
1254
1255         return cfg->rgctx_var;
1256 }
1257
1258 static MonoType*
1259 type_from_stack_type (MonoInst *ins) {
1260         switch (ins->type) {
1261         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1262         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1263         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1264         case STACK_R4: return &mono_defaults.single_class->byval_arg;
1265         case STACK_R8: return &mono_defaults.double_class->byval_arg;
1266         case STACK_MP:
1267                 return &ins->klass->this_arg;
1268         case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1269         case STACK_VTYPE: return &ins->klass->byval_arg;
1270         default:
1271                 g_error ("stack type %d to monotype not handled\n", ins->type);
1272         }
1273         return NULL;
1274 }
1275
1276 static G_GNUC_UNUSED int
1277 type_to_stack_type (MonoCompile *cfg, MonoType *t)
1278 {
1279         t = mono_type_get_underlying_type (t);
1280         switch (t->type) {
1281         case MONO_TYPE_I1:
1282         case MONO_TYPE_U1:
1283         case MONO_TYPE_I2:
1284         case MONO_TYPE_U2:
1285         case MONO_TYPE_I4:
1286         case MONO_TYPE_U4:
1287                 return STACK_I4;
1288         case MONO_TYPE_I:
1289         case MONO_TYPE_U:
1290         case MONO_TYPE_PTR:
1291         case MONO_TYPE_FNPTR:
1292                 return STACK_PTR;
1293         case MONO_TYPE_CLASS:
1294         case MONO_TYPE_STRING:
1295         case MONO_TYPE_OBJECT:
1296         case MONO_TYPE_SZARRAY:
1297         case MONO_TYPE_ARRAY:    
1298                 return STACK_OBJ;
1299         case MONO_TYPE_I8:
1300         case MONO_TYPE_U8:
1301                 return STACK_I8;
1302         case MONO_TYPE_R4:
1303                 return cfg->r4_stack_type;
1304         case MONO_TYPE_R8:
1305                 return STACK_R8;
1306         case MONO_TYPE_VALUETYPE:
1307         case MONO_TYPE_TYPEDBYREF:
1308                 return STACK_VTYPE;
1309         case MONO_TYPE_GENERICINST:
1310                 if (mono_type_generic_inst_is_valuetype (t))
1311                         return STACK_VTYPE;
1312                 else
1313                         return STACK_OBJ;
1314                 break;
1315         default:
1316                 g_assert_not_reached ();
1317         }
1318
1319         return -1;
1320 }
1321
1322 static MonoClass*
1323 array_access_to_klass (int opcode)
1324 {
1325         switch (opcode) {
1326         case CEE_LDELEM_U1:
1327                 return mono_defaults.byte_class;
1328         case CEE_LDELEM_U2:
1329                 return mono_defaults.uint16_class;
1330         case CEE_LDELEM_I:
1331         case CEE_STELEM_I:
1332                 return mono_defaults.int_class;
1333         case CEE_LDELEM_I1:
1334         case CEE_STELEM_I1:
1335                 return mono_defaults.sbyte_class;
1336         case CEE_LDELEM_I2:
1337         case CEE_STELEM_I2:
1338                 return mono_defaults.int16_class;
1339         case CEE_LDELEM_I4:
1340         case CEE_STELEM_I4:
1341                 return mono_defaults.int32_class;
1342         case CEE_LDELEM_U4:
1343                 return mono_defaults.uint32_class;
1344         case CEE_LDELEM_I8:
1345         case CEE_STELEM_I8:
1346                 return mono_defaults.int64_class;
1347         case CEE_LDELEM_R4:
1348         case CEE_STELEM_R4:
1349                 return mono_defaults.single_class;
1350         case CEE_LDELEM_R8:
1351         case CEE_STELEM_R8:
1352                 return mono_defaults.double_class;
1353         case CEE_LDELEM_REF:
1354         case CEE_STELEM_REF:
1355                 return mono_defaults.object_class;
1356         default:
1357                 g_assert_not_reached ();
1358         }
1359         return NULL;
1360 }
1361
1362 /*
1363  * We try to share variables when possible
1364  */
1365 static MonoInst *
1366 mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
1367 {
1368         MonoInst *res;
1369         int pos, vnum;
1370
1371         /* inlining can result in deeper stacks */ 
1372         if (slot >= cfg->header->max_stack)
1373                 return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1374
1375         pos = ins->type - 1 + slot * STACK_MAX;
1376
1377         switch (ins->type) {
1378         case STACK_I4:
1379         case STACK_I8:
1380         case STACK_R8:
1381         case STACK_PTR:
1382         case STACK_MP:
1383         case STACK_OBJ:
1384                 if ((vnum = cfg->intvars [pos]))
1385                         return cfg->varinfo [vnum];
1386                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1387                 cfg->intvars [pos] = res->inst_c0;
1388                 break;
1389         default:
1390                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1391         }
1392         return res;
1393 }
1394
1395 static void
1396 mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
1397 {
1398         /* 
1399          * Don't use this if a generic_context is set, since that means AOT can't
1400          * look up the method using just the image+token.
1401          * table == 0 means this is a reference made from a wrapper.
1402          */
1403         if (cfg->compile_aot && !cfg->generic_context && (mono_metadata_token_table (token) > 0)) {
1404                 MonoJumpInfoToken *jump_info_token = (MonoJumpInfoToken *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
1405                 jump_info_token->image = image;
1406                 jump_info_token->token = token;
1407                 g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
1408         }
1409 }
1410
1411 /*
1412  * This function is called to handle items that are left on the evaluation stack
1413  * at basic block boundaries. What happens is that we save the values to local variables
1414  * and we reload them later when first entering the target basic block (with the
1415  * handle_loaded_temps () function).
1416  * A single joint point will use the same variables (stored in the array bb->out_stack or
1417  * bb->in_stack, if the basic block is before or after the joint point).
1418  *
1419  * This function needs to be called _before_ emitting the last instruction of
1420  * the bb (i.e. before emitting a branch).
1421  * If the stack merge fails at a join point, cfg->unverifiable is set.
1422  */
1423 static void
1424 handle_stack_args (MonoCompile *cfg, MonoInst **sp, int count)
1425 {
1426         int i, bindex;
1427         MonoBasicBlock *bb = cfg->cbb;
1428         MonoBasicBlock *outb;
1429         MonoInst *inst, **locals;
1430         gboolean found;
1431
1432         if (!count)
1433                 return;
1434         if (cfg->verbose_level > 3)
1435                 printf ("%d item(s) on exit from B%d\n", count, bb->block_num);
1436         if (!bb->out_scount) {
1437                 bb->out_scount = count;
1438                 //printf ("bblock %d has out:", bb->block_num);
1439                 found = FALSE;
1440                 for (i = 0; i < bb->out_count; ++i) {
1441                         outb = bb->out_bb [i];
1442                         /* exception handlers are linked, but they should not be considered for stack args */
1443                         if (outb->flags & BB_EXCEPTION_HANDLER)
1444                                 continue;
1445                         //printf (" %d", outb->block_num);
1446                         if (outb->in_stack) {
1447                                 found = TRUE;
1448                                 bb->out_stack = outb->in_stack;
1449                                 break;
1450                         }
1451                 }
1452                 //printf ("\n");
1453                 if (!found) {
1454                         bb->out_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1455                         for (i = 0; i < count; ++i) {
1456                                 /* 
1457                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
1458                                  * stack slot and if they are of the same type.
1459                                  * This won't cause conflicts since if 'local' is used to 
1460                                  * store one of the values in the in_stack of a bblock, then
1461                                  * the same variable will be used for the same outgoing stack 
1462                                  * slot as well. 
1463                                  * This doesn't work when inlining methods, since the bblocks
1464                                  * in the inlined methods do not inherit their in_stack from
1465                                  * the bblock they are inlined to. See bug #58863 for an
1466                                  * example.
1467                                  */
1468                                 if (cfg->inlined_method)
1469                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1470                                 else
1471                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
1472                         }
1473                 }
1474         }
1475
1476         for (i = 0; i < bb->out_count; ++i) {
1477                 outb = bb->out_bb [i];
1478                 /* exception handlers are linked, but they should not be considered for stack args */
1479                 if (outb->flags & BB_EXCEPTION_HANDLER)
1480                         continue;
1481                 if (outb->in_scount) {
1482                         if (outb->in_scount != bb->out_scount) {
1483                                 cfg->unverifiable = TRUE;
1484                                 return;
1485                         }
1486                         continue; /* check they are the same locals */
1487                 }
1488                 outb->in_scount = count;
1489                 outb->in_stack = bb->out_stack;
1490         }
1491
1492         locals = bb->out_stack;
1493         cfg->cbb = bb;
1494         for (i = 0; i < count; ++i) {
1495                 EMIT_NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
1496                 inst->cil_code = sp [i]->cil_code;
1497                 sp [i] = locals [i];
1498                 if (cfg->verbose_level > 3)
1499                         printf ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
1500         }
1501
1502         /*
1503          * It is possible that the out bblocks already have in_stack assigned, and
1504          * the in_stacks differ. In this case, we will store to all the different 
1505          * in_stacks.
1506          */
1507
1508         found = TRUE;
1509         bindex = 0;
1510         while (found) {
1511                 /* Find a bblock which has a different in_stack */
1512                 found = FALSE;
1513                 while (bindex < bb->out_count) {
1514                         outb = bb->out_bb [bindex];
1515                         /* exception handlers are linked, but they should not be considered for stack args */
1516                         if (outb->flags & BB_EXCEPTION_HANDLER) {
1517                                 bindex++;
1518                                 continue;
1519                         }
1520                         if (outb->in_stack != locals) {
1521                                 for (i = 0; i < count; ++i) {
1522                                         EMIT_NEW_TEMPSTORE (cfg, inst, outb->in_stack [i]->inst_c0, sp [i]);
1523                                         inst->cil_code = sp [i]->cil_code;
1524                                         sp [i] = locals [i];
1525                                         if (cfg->verbose_level > 3)
1526                                                 printf ("storing %d to temp %d\n", i, (int)outb->in_stack [i]->inst_c0);
1527                                 }
1528                                 locals = outb->in_stack;
1529                                 found = TRUE;
1530                                 break;
1531                         }
1532                         bindex ++;
1533                 }
1534         }
1535 }
1536
1537 static MonoInst*
1538 emit_runtime_constant (MonoCompile *cfg, MonoJumpInfoType patch_type, gpointer data)
1539 {
1540         MonoInst *ins;
1541
1542         if (cfg->compile_aot) {
1543                 EMIT_NEW_AOTCONST (cfg, ins, patch_type, data);
1544         } else {
1545                 MonoJumpInfo ji;
1546                 gpointer target;
1547
1548                 ji.type = patch_type;
1549                 ji.data.target = data;
1550                 target = mono_resolve_patch_target (NULL, cfg->domain, NULL, &ji, FALSE);
1551
1552                 EMIT_NEW_PCONST (cfg, ins, target);
1553         }
1554         return ins;
1555 }
1556
1557 static void
1558 mini_emit_interface_bitmap_check (MonoCompile *cfg, int intf_bit_reg, int base_reg, int offset, MonoClass *klass)
1559 {
1560         int ibitmap_reg = alloc_preg (cfg);
1561 #ifdef COMPRESSED_INTERFACE_BITMAP
1562         MonoInst *args [2];
1563         MonoInst *res, *ins;
1564         NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, ibitmap_reg, base_reg, offset);
1565         MONO_ADD_INS (cfg->cbb, ins);
1566         args [0] = ins;
1567         args [1] = emit_runtime_constant (cfg, MONO_PATCH_INFO_IID, klass);
1568         res = mono_emit_jit_icall (cfg, mono_class_interface_match, args);
1569         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, intf_bit_reg, res->dreg);
1570 #else
1571         int ibitmap_byte_reg = alloc_preg (cfg);
1572
1573         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, base_reg, offset);
1574
1575         if (cfg->compile_aot) {
1576                 int iid_reg = alloc_preg (cfg);
1577                 int shifted_iid_reg = alloc_preg (cfg);
1578                 int ibitmap_byte_address_reg = alloc_preg (cfg);
1579                 int masked_iid_reg = alloc_preg (cfg);
1580                 int iid_one_bit_reg = alloc_preg (cfg);
1581                 int iid_bit_reg = alloc_preg (cfg);
1582                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1583                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, shifted_iid_reg, iid_reg, 3);
1584                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ibitmap_byte_address_reg, ibitmap_reg, shifted_iid_reg);
1585                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, ibitmap_byte_reg, ibitmap_byte_address_reg, 0);
1586                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, masked_iid_reg, iid_reg, 7);
1587                 MONO_EMIT_NEW_ICONST (cfg, iid_one_bit_reg, 1);
1588                 MONO_EMIT_NEW_BIALU (cfg, OP_ISHL, iid_bit_reg, iid_one_bit_reg, masked_iid_reg);
1589                 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, intf_bit_reg, ibitmap_byte_reg, iid_bit_reg);
1590         } else {
1591                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, klass->interface_id >> 3);
1592                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (klass->interface_id & 7));
1593         }
1594 #endif
1595 }
1596
1597 /* 
1598  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoClass
1599  * stored in "klass_reg" implements the interface "klass".
1600  */
1601 static void
1602 mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass_reg, MonoClass *klass)
1603 {
1604         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, interface_bitmap), klass);
1605 }
1606
1607 /* 
1608  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoVTable
1609  * stored in "vtable_reg" implements the interface "klass".
1610  */
1611 static void
1612 mini_emit_load_intf_bit_reg_vtable (MonoCompile *cfg, int intf_bit_reg, int vtable_reg, MonoClass *klass)
1613 {
1614         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, interface_bitmap), klass);
1615 }
1616
1617 /* 
1618  * Emit code which checks whenever the interface id of @klass is smaller than
1619  * than the value given by max_iid_reg.
1620 */
1621 static void
1622 mini_emit_max_iid_check (MonoCompile *cfg, int max_iid_reg, MonoClass *klass,
1623                                                  MonoBasicBlock *false_target)
1624 {
1625         if (cfg->compile_aot) {
1626                 int iid_reg = alloc_preg (cfg);
1627                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1628                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, max_iid_reg, iid_reg);
1629         }
1630         else
1631                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, max_iid_reg, klass->interface_id);
1632         if (false_target)
1633                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1634         else
1635                 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1636 }
1637
1638 /* Same as above, but obtains max_iid from a vtable */
1639 static void
1640 mini_emit_max_iid_check_vtable (MonoCompile *cfg, int vtable_reg, MonoClass *klass,
1641                                                                  MonoBasicBlock *false_target)
1642 {
1643         int max_iid_reg = alloc_preg (cfg);
1644                 
1645         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, max_interface_id));
1646         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1647 }
1648
1649 /* Same as above, but obtains max_iid from a klass */
1650 static void
1651 mini_emit_max_iid_check_class (MonoCompile *cfg, int klass_reg, MonoClass *klass,
1652                                                                  MonoBasicBlock *false_target)
1653 {
1654         int max_iid_reg = alloc_preg (cfg);
1655
1656         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, max_interface_id));
1657         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1658 }
1659
1660 static void
1661 mini_emit_isninst_cast_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_ins, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1662 {
1663         int idepth_reg = alloc_preg (cfg);
1664         int stypes_reg = alloc_preg (cfg);
1665         int stype = alloc_preg (cfg);
1666
1667         mono_class_setup_supertypes (klass);
1668
1669         if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1670                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1671                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1672                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1673         }
1674         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1675         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1676         if (klass_ins) {
1677                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, klass_ins->dreg);
1678         } else if (cfg->compile_aot) {
1679                 int const_reg = alloc_preg (cfg);
1680                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1681                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, const_reg);
1682         } else {
1683                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, stype, klass);
1684         }
1685         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, true_target);
1686 }
1687
1688 static void
1689 mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1690 {
1691         mini_emit_isninst_cast_inst (cfg, klass_reg, klass, NULL, false_target, true_target);
1692 }
1693
1694 static void
1695 mini_emit_iface_cast (MonoCompile *cfg, int vtable_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1696 {
1697         int intf_reg = alloc_preg (cfg);
1698
1699         mini_emit_max_iid_check_vtable (cfg, vtable_reg, klass, false_target);
1700         mini_emit_load_intf_bit_reg_vtable (cfg, intf_reg, vtable_reg, klass);
1701         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_reg, 0);
1702         if (true_target)
1703                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1704         else
1705                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");               
1706 }
1707
1708 /*
1709  * Variant of the above that takes a register to the class, not the vtable.
1710  */
1711 static void
1712 mini_emit_iface_class_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1713 {
1714         int intf_bit_reg = alloc_preg (cfg);
1715
1716         mini_emit_max_iid_check_class (cfg, klass_reg, klass, false_target);
1717         mini_emit_load_intf_bit_reg_class (cfg, intf_bit_reg, klass_reg, klass);
1718         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_bit_reg, 0);
1719         if (true_target)
1720                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1721         else
1722                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
1723 }
1724
1725 static inline void
1726 mini_emit_class_check_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_inst)
1727 {
1728         if (klass_inst) {
1729                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_inst->dreg);
1730         } else {
1731                 MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
1732                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, ins->dreg);
1733         }
1734         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1735 }
1736
1737 static inline void
1738 mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass)
1739 {
1740         mini_emit_class_check_inst (cfg, klass_reg, klass, NULL);
1741 }
1742
1743 static inline void
1744 mini_emit_class_check_branch (MonoCompile *cfg, int klass_reg, MonoClass *klass, int branch_op, MonoBasicBlock *target)
1745 {
1746         if (cfg->compile_aot) {
1747                 int const_reg = alloc_preg (cfg);
1748                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1749                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1750         } else {
1751                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1752         }
1753         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, branch_op, target);
1754 }
1755
1756 static void
1757 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null);
1758         
1759 static void
1760 mini_emit_castclass_inst (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoInst *klass_inst, MonoBasicBlock *object_is_null)
1761 {
1762         if (klass->rank) {
1763                 int rank_reg = alloc_preg (cfg);
1764                 int eclass_reg = alloc_preg (cfg);
1765
1766                 g_assert (!klass_inst);
1767                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, rank));
1768                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
1769                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1770                 //              MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
1771                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
1772                 if (klass->cast_class == mono_defaults.object_class) {
1773                         int parent_reg = alloc_preg (cfg);
1774                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
1775                         mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, object_is_null);
1776                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1777                 } else if (klass->cast_class == mono_defaults.enum_class->parent) {
1778                         mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, object_is_null);
1779                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1780                 } else if (klass->cast_class == mono_defaults.enum_class) {
1781                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1782                 } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1783                         mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, NULL, NULL);
1784                 } else {
1785                         // Pass -1 as obj_reg to skip the check below for arrays of arrays
1786                         mini_emit_castclass (cfg, -1, eclass_reg, klass->cast_class, object_is_null);
1787                 }
1788
1789                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY) && (obj_reg != -1)) {
1790                         /* Check that the object is a vector too */
1791                         int bounds_reg = alloc_preg (cfg);
1792                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
1793                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
1794                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1795                 }
1796         } else {
1797                 int idepth_reg = alloc_preg (cfg);
1798                 int stypes_reg = alloc_preg (cfg);
1799                 int stype = alloc_preg (cfg);
1800
1801                 mono_class_setup_supertypes (klass);
1802
1803                 if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1804                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1805                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1806                         MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1807                 }
1808                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1809                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1810                 mini_emit_class_check_inst (cfg, stype, klass, klass_inst);
1811         }
1812 }
1813
1814 static void
1815 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null)
1816 {
1817         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, NULL, object_is_null);
1818 }
1819
1820 static void 
1821 mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align)
1822 {
1823         int val_reg;
1824
1825         g_assert (val == 0);
1826
1827         if (align == 0)
1828                 align = 4;
1829
1830         if ((size <= SIZEOF_REGISTER) && (size <= align)) {
1831                 switch (size) {
1832                 case 1:
1833                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, destreg, offset, val);
1834                         return;
1835                 case 2:
1836                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI2_MEMBASE_IMM, destreg, offset, val);
1837                         return;
1838                 case 4:
1839                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI4_MEMBASE_IMM, destreg, offset, val);
1840                         return;
1841 #if SIZEOF_REGISTER == 8
1842                 case 8:
1843                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI8_MEMBASE_IMM, destreg, offset, val);
1844                         return;
1845 #endif
1846                 }
1847         }
1848
1849         val_reg = alloc_preg (cfg);
1850
1851         if (SIZEOF_REGISTER == 8)
1852                 MONO_EMIT_NEW_I8CONST (cfg, val_reg, val);
1853         else
1854                 MONO_EMIT_NEW_ICONST (cfg, val_reg, val);
1855
1856         if (align < 4) {
1857                 /* This could be optimized further if neccesary */
1858                 while (size >= 1) {
1859                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1860                         offset += 1;
1861                         size -= 1;
1862                 }
1863                 return;
1864         }       
1865
1866         if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
1867                 if (offset % 8) {
1868                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1869                         offset += 4;
1870                         size -= 4;
1871                 }
1872                 while (size >= 8) {
1873                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, offset, val_reg);
1874                         offset += 8;
1875                         size -= 8;
1876                 }
1877         }       
1878
1879         while (size >= 4) {
1880                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1881                 offset += 4;
1882                 size -= 4;
1883         }
1884         while (size >= 2) {
1885                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, val_reg);
1886                 offset += 2;
1887                 size -= 2;
1888         }
1889         while (size >= 1) {
1890                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1891                 offset += 1;
1892                 size -= 1;
1893         }
1894 }
1895
1896 void 
1897 mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align)
1898 {
1899         int cur_reg;
1900
1901         if (align == 0)
1902                 align = 4;
1903
1904         /*FIXME arbitrary hack to avoid unbound code expansion.*/
1905         g_assert (size < 10000);
1906
1907         if (align < 4) {
1908                 /* This could be optimized further if neccesary */
1909                 while (size >= 1) {
1910                         cur_reg = alloc_preg (cfg);
1911                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1912                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1913                         doffset += 1;
1914                         soffset += 1;
1915                         size -= 1;
1916                 }
1917         }
1918
1919         if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
1920                 while (size >= 8) {
1921                         cur_reg = alloc_preg (cfg);
1922                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI8_MEMBASE, cur_reg, srcreg, soffset);
1923                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, doffset, cur_reg);
1924                         doffset += 8;
1925                         soffset += 8;
1926                         size -= 8;
1927                 }
1928         }       
1929
1930         while (size >= 4) {
1931                 cur_reg = alloc_preg (cfg);
1932                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, cur_reg, srcreg, soffset);
1933                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, doffset, cur_reg);
1934                 doffset += 4;
1935                 soffset += 4;
1936                 size -= 4;
1937         }
1938         while (size >= 2) {
1939                 cur_reg = alloc_preg (cfg);
1940                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, cur_reg, srcreg, soffset);
1941                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, doffset, cur_reg);
1942                 doffset += 2;
1943                 soffset += 2;
1944                 size -= 2;
1945         }
1946         while (size >= 1) {
1947                 cur_reg = alloc_preg (cfg);
1948                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1949                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1950                 doffset += 1;
1951                 soffset += 1;
1952                 size -= 1;
1953         }
1954 }
1955
1956 static void
1957 emit_tls_set (MonoCompile *cfg, int sreg1, MonoTlsKey tls_key)
1958 {
1959         MonoInst *ins, *c;
1960
1961         if (cfg->compile_aot) {
1962                 EMIT_NEW_TLS_OFFSETCONST (cfg, c, tls_key);
1963                 MONO_INST_NEW (cfg, ins, OP_TLS_SET_REG);
1964                 ins->sreg1 = sreg1;
1965                 ins->sreg2 = c->dreg;
1966                 MONO_ADD_INS (cfg->cbb, ins);
1967         } else {
1968                 MONO_INST_NEW (cfg, ins, OP_TLS_SET);
1969                 ins->sreg1 = sreg1;
1970                 ins->inst_offset = mini_get_tls_offset (tls_key);
1971                 MONO_ADD_INS (cfg->cbb, ins);
1972         }
1973 }
1974
1975 /*
1976  * emit_push_lmf:
1977  *
1978  *   Emit IR to push the current LMF onto the LMF stack.
1979  */
1980 static void
1981 emit_push_lmf (MonoCompile *cfg)
1982 {
1983         /*
1984          * Emit IR to push the LMF:
1985          * lmf_addr = <lmf_addr from tls>
1986          * lmf->lmf_addr = lmf_addr
1987          * lmf->prev_lmf = *lmf_addr
1988          * *lmf_addr = lmf
1989          */
1990         int lmf_reg, prev_lmf_reg;
1991         MonoInst *ins, *lmf_ins;
1992
1993         if (!cfg->lmf_ir)
1994                 return;
1995
1996         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
1997                 /* Load current lmf */
1998                 lmf_ins = mono_get_lmf_intrinsic (cfg);
1999                 g_assert (lmf_ins);
2000                 MONO_ADD_INS (cfg->cbb, lmf_ins);
2001                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2002                 lmf_reg = ins->dreg;
2003                 /* Save previous_lmf */
2004                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), lmf_ins->dreg);
2005                 /* Set new LMF */
2006                 emit_tls_set (cfg, lmf_reg, TLS_KEY_LMF);
2007         } else {
2008                 /*
2009                  * Store lmf_addr in a variable, so it can be allocated to a global register.
2010                  */
2011                 if (!cfg->lmf_addr_var)
2012                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2013
2014 #ifdef HOST_WIN32
2015                 ins = mono_get_jit_tls_intrinsic (cfg);
2016                 if (ins) {
2017                         int jit_tls_dreg = ins->dreg;
2018
2019                         MONO_ADD_INS (cfg->cbb, ins);
2020                         lmf_reg = alloc_preg (cfg);
2021                         EMIT_NEW_BIALU_IMM (cfg, lmf_ins, OP_PADD_IMM, lmf_reg, jit_tls_dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2022                 } else {
2023                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2024                 }
2025 #else
2026                 lmf_ins = mono_get_lmf_addr_intrinsic (cfg);
2027                 if (lmf_ins) {
2028                         MONO_ADD_INS (cfg->cbb, lmf_ins);
2029                 } else {
2030 #ifdef TARGET_IOS
2031                         MonoInst *args [16], *jit_tls_ins, *ins;
2032
2033                         /* Inline mono_get_lmf_addr () */
2034                         /* jit_tls = pthread_getspecific (mono_jit_tls_id); lmf_addr = &jit_tls->lmf; */
2035
2036                         /* Load mono_jit_tls_id */
2037                         if (cfg->compile_aot)
2038                                 EMIT_NEW_AOTCONST (cfg, args [0], MONO_PATCH_INFO_JIT_TLS_ID, NULL);
2039                         else
2040                                 EMIT_NEW_ICONST (cfg, args [0], mono_jit_tls_id);
2041                         /* call pthread_getspecific () */
2042                         jit_tls_ins = mono_emit_jit_icall (cfg, pthread_getspecific, args);
2043                         /* lmf_addr = &jit_tls->lmf */
2044                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, cfg->lmf_addr_var->dreg, jit_tls_ins->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2045                         lmf_ins = ins;
2046 #else
2047                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2048 #endif
2049                 }
2050 #endif
2051                 lmf_ins->dreg = cfg->lmf_addr_var->dreg;
2052
2053                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2054                 lmf_reg = ins->dreg;
2055
2056                 prev_lmf_reg = alloc_preg (cfg);
2057                 /* Save previous_lmf */
2058                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, cfg->lmf_addr_var->dreg, 0);
2059                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), prev_lmf_reg);
2060                 /* Set new lmf */
2061                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, cfg->lmf_addr_var->dreg, 0, lmf_reg);
2062         }
2063 }
2064
2065 /*
2066  * emit_pop_lmf:
2067  *
2068  *   Emit IR to pop the current LMF from the LMF stack.
2069  */
2070 static void
2071 emit_pop_lmf (MonoCompile *cfg)
2072 {
2073         int lmf_reg, lmf_addr_reg, prev_lmf_reg;
2074         MonoInst *ins;
2075
2076         if (!cfg->lmf_ir)
2077                 return;
2078
2079         EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2080         lmf_reg = ins->dreg;
2081
2082         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
2083                 /* Load previous_lmf */
2084                 prev_lmf_reg = alloc_preg (cfg);
2085                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2086                 /* Set new LMF */
2087                 emit_tls_set (cfg, prev_lmf_reg, TLS_KEY_LMF);
2088         } else {
2089                 /*
2090                  * Emit IR to pop the LMF:
2091                  * *(lmf->lmf_addr) = lmf->prev_lmf
2092                  */
2093                 /* This could be called before emit_push_lmf () */
2094                 if (!cfg->lmf_addr_var)
2095                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2096                 lmf_addr_reg = cfg->lmf_addr_var->dreg;
2097
2098                 prev_lmf_reg = alloc_preg (cfg);
2099                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2100                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_addr_reg, 0, prev_lmf_reg);
2101         }
2102 }
2103
2104 static void
2105 emit_instrumentation_call (MonoCompile *cfg, void *func)
2106 {
2107         MonoInst *iargs [1];
2108
2109         /*
2110          * Avoid instrumenting inlined methods since it can
2111          * distort profiling results.
2112          */
2113         if (cfg->method != cfg->current_method)
2114                 return;
2115
2116         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
2117                 EMIT_NEW_METHODCONST (cfg, iargs [0], cfg->method);
2118                 mono_emit_jit_icall (cfg, func, iargs);
2119         }
2120 }
2121
2122 static int
2123 ret_type_to_call_opcode (MonoCompile *cfg, MonoType *type, int calli, int virt)
2124 {
2125 handle_enum:
2126         type = mini_get_underlying_type (type);
2127         switch (type->type) {
2128         case MONO_TYPE_VOID:
2129                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALL_MEMBASE: OP_VOIDCALL;
2130         case MONO_TYPE_I1:
2131         case MONO_TYPE_U1:
2132         case MONO_TYPE_I2:
2133         case MONO_TYPE_U2:
2134         case MONO_TYPE_I4:
2135         case MONO_TYPE_U4:
2136                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2137         case MONO_TYPE_I:
2138         case MONO_TYPE_U:
2139         case MONO_TYPE_PTR:
2140         case MONO_TYPE_FNPTR:
2141                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2142         case MONO_TYPE_CLASS:
2143         case MONO_TYPE_STRING:
2144         case MONO_TYPE_OBJECT:
2145         case MONO_TYPE_SZARRAY:
2146         case MONO_TYPE_ARRAY:    
2147                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2148         case MONO_TYPE_I8:
2149         case MONO_TYPE_U8:
2150                 return calli? OP_LCALL_REG: virt? OP_LCALL_MEMBASE: OP_LCALL;
2151         case MONO_TYPE_R4:
2152                 if (cfg->r4fp)
2153                         return calli? OP_RCALL_REG: virt? OP_RCALL_MEMBASE: OP_RCALL;
2154                 else
2155                         return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2156         case MONO_TYPE_R8:
2157                 return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2158         case MONO_TYPE_VALUETYPE:
2159                 if (type->data.klass->enumtype) {
2160                         type = mono_class_enum_basetype (type->data.klass);
2161                         goto handle_enum;
2162                 } else
2163                         return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2164         case MONO_TYPE_TYPEDBYREF:
2165                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2166         case MONO_TYPE_GENERICINST:
2167                 type = &type->data.generic_class->container_class->byval_arg;
2168                 goto handle_enum;
2169         case MONO_TYPE_VAR:
2170         case MONO_TYPE_MVAR:
2171                 /* gsharedvt */
2172                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2173         default:
2174                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
2175         }
2176         return -1;
2177 }
2178
2179 /*
2180  * target_type_is_incompatible:
2181  * @cfg: MonoCompile context
2182  *
2183  * Check that the item @arg on the evaluation stack can be stored
2184  * in the target type (can be a local, or field, etc).
2185  * The cfg arg can be used to check if we need verification or just
2186  * validity checks.
2187  *
2188  * Returns: non-0 value if arg can't be stored on a target.
2189  */
2190 static int
2191 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
2192 {
2193         MonoType *simple_type;
2194         MonoClass *klass;
2195
2196         if (target->byref) {
2197                 /* FIXME: check that the pointed to types match */
2198                 if (arg->type == STACK_MP) {
2199                         MonoClass *base_class = mono_class_from_mono_type (target);
2200                         /* This is needed to handle gshared types + ldaddr */
2201                         simple_type = mini_get_underlying_type (&base_class->byval_arg);
2202                         return target->type != MONO_TYPE_I && arg->klass != base_class && arg->klass != mono_class_from_mono_type (simple_type);
2203                 }
2204                 if (arg->type == STACK_PTR)
2205                         return 0;
2206                 return 1;
2207         }
2208
2209         simple_type = mini_get_underlying_type (target);
2210         switch (simple_type->type) {
2211         case MONO_TYPE_VOID:
2212                 return 1;
2213         case MONO_TYPE_I1:
2214         case MONO_TYPE_U1:
2215         case MONO_TYPE_I2:
2216         case MONO_TYPE_U2:
2217         case MONO_TYPE_I4:
2218         case MONO_TYPE_U4:
2219                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2220                         return 1;
2221                 return 0;
2222         case MONO_TYPE_PTR:
2223                 /* STACK_MP is needed when setting pinned locals */
2224                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2225                         return 1;
2226                 return 0;
2227         case MONO_TYPE_I:
2228         case MONO_TYPE_U:
2229         case MONO_TYPE_FNPTR:
2230                 /* 
2231                  * Some opcodes like ldloca returns 'transient pointers' which can be stored in
2232                  * in native int. (#688008).
2233                  */
2234                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2235                         return 1;
2236                 return 0;
2237         case MONO_TYPE_CLASS:
2238         case MONO_TYPE_STRING:
2239         case MONO_TYPE_OBJECT:
2240         case MONO_TYPE_SZARRAY:
2241         case MONO_TYPE_ARRAY:    
2242                 if (arg->type != STACK_OBJ)
2243                         return 1;
2244                 /* FIXME: check type compatibility */
2245                 return 0;
2246         case MONO_TYPE_I8:
2247         case MONO_TYPE_U8:
2248                 if (arg->type != STACK_I8)
2249                         return 1;
2250                 return 0;
2251         case MONO_TYPE_R4:
2252                 if (arg->type != cfg->r4_stack_type)
2253                         return 1;
2254                 return 0;
2255         case MONO_TYPE_R8:
2256                 if (arg->type != STACK_R8)
2257                         return 1;
2258                 return 0;
2259         case MONO_TYPE_VALUETYPE:
2260                 if (arg->type != STACK_VTYPE)
2261                         return 1;
2262                 klass = mono_class_from_mono_type (simple_type);
2263                 if (klass != arg->klass)
2264                         return 1;
2265                 return 0;
2266         case MONO_TYPE_TYPEDBYREF:
2267                 if (arg->type != STACK_VTYPE)
2268                         return 1;
2269                 klass = mono_class_from_mono_type (simple_type);
2270                 if (klass != arg->klass)
2271                         return 1;
2272                 return 0;
2273         case MONO_TYPE_GENERICINST:
2274                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
2275                         MonoClass *target_class;
2276                         if (arg->type != STACK_VTYPE)
2277                                 return 1;
2278                         klass = mono_class_from_mono_type (simple_type);
2279                         target_class = mono_class_from_mono_type (target);
2280                         /* The second cases is needed when doing partial sharing */
2281                         if (klass != arg->klass && target_class != arg->klass && target_class != mono_class_from_mono_type (mini_get_underlying_type (&arg->klass->byval_arg)))
2282                                 return 1;
2283                         return 0;
2284                 } else {
2285                         if (arg->type != STACK_OBJ)
2286                                 return 1;
2287                         /* FIXME: check type compatibility */
2288                         return 0;
2289                 }
2290         case MONO_TYPE_VAR:
2291         case MONO_TYPE_MVAR:
2292                 g_assert (cfg->gshared);
2293                 if (mini_type_var_is_vt (simple_type)) {
2294                         if (arg->type != STACK_VTYPE)
2295                                 return 1;
2296                 } else {
2297                         if (arg->type != STACK_OBJ)
2298                                 return 1;
2299                 }
2300                 return 0;
2301         default:
2302                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
2303         }
2304         return 1;
2305 }
2306
2307 /*
2308  * Prepare arguments for passing to a function call.
2309  * Return a non-zero value if the arguments can't be passed to the given
2310  * signature.
2311  * The type checks are not yet complete and some conversions may need
2312  * casts on 32 or 64 bit architectures.
2313  *
2314  * FIXME: implement this using target_type_is_incompatible ()
2315  */
2316 static int
2317 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2318 {
2319         MonoType *simple_type;
2320         int i;
2321
2322         if (sig->hasthis) {
2323                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2324                         return 1;
2325                 args++;
2326         }
2327         for (i = 0; i < sig->param_count; ++i) {
2328                 if (sig->params [i]->byref) {
2329                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2330                                 return 1;
2331                         continue;
2332                 }
2333                 simple_type = mini_get_underlying_type (sig->params [i]);
2334 handle_enum:
2335                 switch (simple_type->type) {
2336                 case MONO_TYPE_VOID:
2337                         return 1;
2338                         continue;
2339                 case MONO_TYPE_I1:
2340                 case MONO_TYPE_U1:
2341                 case MONO_TYPE_I2:
2342                 case MONO_TYPE_U2:
2343                 case MONO_TYPE_I4:
2344                 case MONO_TYPE_U4:
2345                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2346                                 return 1;
2347                         continue;
2348                 case MONO_TYPE_I:
2349                 case MONO_TYPE_U:
2350                 case MONO_TYPE_PTR:
2351                 case MONO_TYPE_FNPTR:
2352                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2353                                 return 1;
2354                         continue;
2355                 case MONO_TYPE_CLASS:
2356                 case MONO_TYPE_STRING:
2357                 case MONO_TYPE_OBJECT:
2358                 case MONO_TYPE_SZARRAY:
2359                 case MONO_TYPE_ARRAY:    
2360                         if (args [i]->type != STACK_OBJ)
2361                                 return 1;
2362                         continue;
2363                 case MONO_TYPE_I8:
2364                 case MONO_TYPE_U8:
2365                         if (args [i]->type != STACK_I8)
2366                                 return 1;
2367                         continue;
2368                 case MONO_TYPE_R4:
2369                         if (args [i]->type != cfg->r4_stack_type)
2370                                 return 1;
2371                         continue;
2372                 case MONO_TYPE_R8:
2373                         if (args [i]->type != STACK_R8)
2374                                 return 1;
2375                         continue;
2376                 case MONO_TYPE_VALUETYPE:
2377                         if (simple_type->data.klass->enumtype) {
2378                                 simple_type = mono_class_enum_basetype (simple_type->data.klass);
2379                                 goto handle_enum;
2380                         }
2381                         if (args [i]->type != STACK_VTYPE)
2382                                 return 1;
2383                         continue;
2384                 case MONO_TYPE_TYPEDBYREF:
2385                         if (args [i]->type != STACK_VTYPE)
2386                                 return 1;
2387                         continue;
2388                 case MONO_TYPE_GENERICINST:
2389                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2390                         goto handle_enum;
2391                 case MONO_TYPE_VAR:
2392                 case MONO_TYPE_MVAR:
2393                         /* gsharedvt */
2394                         if (args [i]->type != STACK_VTYPE)
2395                                 return 1;
2396                         continue;
2397                 default:
2398                         g_error ("unknown type 0x%02x in check_call_signature",
2399                                  simple_type->type);
2400                 }
2401         }
2402         return 0;
2403 }
2404
2405 static int
2406 callvirt_to_call (int opcode)
2407 {
2408         switch (opcode) {
2409         case OP_CALL_MEMBASE:
2410                 return OP_CALL;
2411         case OP_VOIDCALL_MEMBASE:
2412                 return OP_VOIDCALL;
2413         case OP_FCALL_MEMBASE:
2414                 return OP_FCALL;
2415         case OP_RCALL_MEMBASE:
2416                 return OP_RCALL;
2417         case OP_VCALL_MEMBASE:
2418                 return OP_VCALL;
2419         case OP_LCALL_MEMBASE:
2420                 return OP_LCALL;
2421         default:
2422                 g_assert_not_reached ();
2423         }
2424
2425         return -1;
2426 }
2427
2428 static int
2429 callvirt_to_call_reg (int opcode)
2430 {
2431         switch (opcode) {
2432         case OP_CALL_MEMBASE:
2433                 return OP_CALL_REG;
2434         case OP_VOIDCALL_MEMBASE:
2435                 return OP_VOIDCALL_REG;
2436         case OP_FCALL_MEMBASE:
2437                 return OP_FCALL_REG;
2438         case OP_RCALL_MEMBASE:
2439                 return OP_RCALL_REG;
2440         case OP_VCALL_MEMBASE:
2441                 return OP_VCALL_REG;
2442         case OP_LCALL_MEMBASE:
2443                 return OP_LCALL_REG;
2444         default:
2445                 g_assert_not_reached ();
2446         }
2447
2448         return -1;
2449 }
2450
2451 /* Either METHOD or IMT_ARG needs to be set */
2452 static void
2453 emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoMethod *method, MonoInst *imt_arg)
2454 {
2455         int method_reg;
2456
2457         if (COMPILE_LLVM (cfg)) {
2458                 if (imt_arg) {
2459                         method_reg = alloc_preg (cfg);
2460                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2461                 } else {
2462                         MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHODCONST, method);
2463                         method_reg = ins->dreg;
2464                 }
2465
2466 #ifdef ENABLE_LLVM
2467                 call->imt_arg_reg = method_reg;
2468 #endif
2469                 mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2470                 return;
2471         }
2472
2473         if (imt_arg) {
2474                 method_reg = alloc_preg (cfg);
2475                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2476         } else {
2477                 MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHODCONST, method);
2478                 method_reg = ins->dreg;
2479         }
2480
2481         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2482 }
2483
2484 static MonoJumpInfo *
2485 mono_patch_info_new (MonoMemPool *mp, int ip, MonoJumpInfoType type, gconstpointer target)
2486 {
2487         MonoJumpInfo *ji = (MonoJumpInfo *)mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
2488
2489         ji->ip.i = ip;
2490         ji->type = type;
2491         ji->data.target = target;
2492
2493         return ji;
2494 }
2495
2496 static int
2497 mini_class_check_context_used (MonoCompile *cfg, MonoClass *klass)
2498 {
2499         if (cfg->gshared)
2500                 return mono_class_check_context_used (klass);
2501         else
2502                 return 0;
2503 }
2504
2505 static int
2506 mini_method_check_context_used (MonoCompile *cfg, MonoMethod *method)
2507 {
2508         if (cfg->gshared)
2509                 return mono_method_check_context_used (method);
2510         else
2511                 return 0;
2512 }
2513
2514 /*
2515  * check_method_sharing:
2516  *
2517  *   Check whenever the vtable or an mrgctx needs to be passed when calling CMETHOD.
2518  */
2519 static void
2520 check_method_sharing (MonoCompile *cfg, MonoMethod *cmethod, gboolean *out_pass_vtable, gboolean *out_pass_mrgctx)
2521 {
2522         gboolean pass_vtable = FALSE;
2523         gboolean pass_mrgctx = FALSE;
2524
2525         if (((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
2526                 (cmethod->klass->generic_class || cmethod->klass->generic_container)) {
2527                 gboolean sharable = FALSE;
2528
2529                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE))
2530                         sharable = TRUE;
2531
2532                 /*
2533                  * Pass vtable iff target method might
2534                  * be shared, which means that sharing
2535                  * is enabled for its class and its
2536                  * context is sharable (and it's not a
2537                  * generic method).
2538                  */
2539                 if (sharable && !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
2540                         pass_vtable = TRUE;
2541         }
2542
2543         if (mini_method_get_context (cmethod) &&
2544                 mini_method_get_context (cmethod)->method_inst) {
2545                 g_assert (!pass_vtable);
2546
2547                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE)) {
2548                         pass_mrgctx = TRUE;
2549                 } else {
2550                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (mono_method_signature (cmethod)))
2551                                 pass_mrgctx = TRUE;
2552                 }
2553         }
2554
2555         if (out_pass_vtable)
2556                 *out_pass_vtable = pass_vtable;
2557         if (out_pass_mrgctx)
2558                 *out_pass_mrgctx = pass_mrgctx;
2559 }
2560
2561 inline static MonoCallInst *
2562 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
2563                                          MonoInst **args, int calli, int virtual_, int tail, int rgctx, int unbox_trampoline)
2564 {
2565         MonoType *sig_ret;
2566         MonoCallInst *call;
2567 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2568         int i;
2569 #endif
2570
2571         if (cfg->llvm_only)
2572                 tail = FALSE;
2573
2574         if (tail) {
2575                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
2576
2577                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
2578         } else
2579                 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (cfg, sig->ret, calli, virtual_));
2580
2581         call->args = args;
2582         call->signature = sig;
2583         call->rgctx_reg = rgctx;
2584         sig_ret = mini_get_underlying_type (sig->ret);
2585
2586         type_to_eval_stack_type ((cfg), sig_ret, &call->inst);
2587
2588         if (tail) {
2589                 if (mini_type_is_vtype (sig_ret)) {
2590                         call->vret_var = cfg->vret_addr;
2591                         //g_assert_not_reached ();
2592                 }
2593         } else if (mini_type_is_vtype (sig_ret)) {
2594                 MonoInst *temp = mono_compile_create_var (cfg, sig_ret, OP_LOCAL);
2595                 MonoInst *loada;
2596
2597                 temp->backend.is_pinvoke = sig->pinvoke;
2598
2599                 /*
2600                  * We use a new opcode OP_OUTARG_VTRETADDR instead of LDADDR for emitting the
2601                  * address of return value to increase optimization opportunities.
2602                  * Before vtype decomposition, the dreg of the call ins itself represents the
2603                  * fact the call modifies the return value. After decomposition, the call will
2604                  * be transformed into one of the OP_VOIDCALL opcodes, and the VTRETADDR opcode
2605                  * will be transformed into an LDADDR.
2606                  */
2607                 MONO_INST_NEW (cfg, loada, OP_OUTARG_VTRETADDR);
2608                 loada->dreg = alloc_preg (cfg);
2609                 loada->inst_p0 = temp;
2610                 /* We reference the call too since call->dreg could change during optimization */
2611                 loada->inst_p1 = call;
2612                 MONO_ADD_INS (cfg->cbb, loada);
2613
2614                 call->inst.dreg = temp->dreg;
2615
2616                 call->vret_var = loada;
2617         } else if (!MONO_TYPE_IS_VOID (sig_ret))
2618                 call->inst.dreg = alloc_dreg (cfg, (MonoStackType)call->inst.type);
2619
2620 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2621         if (COMPILE_SOFT_FLOAT (cfg)) {
2622                 /* 
2623                  * If the call has a float argument, we would need to do an r8->r4 conversion using 
2624                  * an icall, but that cannot be done during the call sequence since it would clobber
2625                  * the call registers + the stack. So we do it before emitting the call.
2626                  */
2627                 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2628                         MonoType *t;
2629                         MonoInst *in = call->args [i];
2630
2631                         if (i >= sig->hasthis)
2632                                 t = sig->params [i - sig->hasthis];
2633                         else
2634                                 t = &mono_defaults.int_class->byval_arg;
2635                         t = mono_type_get_underlying_type (t);
2636
2637                         if (!t->byref && t->type == MONO_TYPE_R4) {
2638                                 MonoInst *iargs [1];
2639                                 MonoInst *conv;
2640
2641                                 iargs [0] = in;
2642                                 conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
2643
2644                                 /* The result will be in an int vreg */
2645                                 call->args [i] = conv;
2646                         }
2647                 }
2648         }
2649 #endif
2650
2651         call->need_unbox_trampoline = unbox_trampoline;
2652
2653 #ifdef ENABLE_LLVM
2654         if (COMPILE_LLVM (cfg))
2655                 mono_llvm_emit_call (cfg, call);
2656         else
2657                 mono_arch_emit_call (cfg, call);
2658 #else
2659         mono_arch_emit_call (cfg, call);
2660 #endif
2661
2662         cfg->param_area = MAX (cfg->param_area, call->stack_usage);
2663         cfg->flags |= MONO_CFG_HAS_CALLS;
2664         
2665         return call;
2666 }
2667
2668 static void
2669 set_rgctx_arg (MonoCompile *cfg, MonoCallInst *call, int rgctx_reg, MonoInst *rgctx_arg)
2670 {
2671         mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
2672         cfg->uses_rgctx_reg = TRUE;
2673         call->rgctx_reg = TRUE;
2674 #ifdef ENABLE_LLVM
2675         call->rgctx_arg_reg = rgctx_reg;
2676 #endif
2677 }       
2678
2679 inline static MonoInst*
2680 mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg)
2681 {
2682         MonoCallInst *call;
2683         MonoInst *ins;
2684         int rgctx_reg = -1;
2685         gboolean check_sp = FALSE;
2686
2687         if (cfg->check_pinvoke_callconv && cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
2688                 WrapperInfo *info = mono_marshal_get_wrapper_info (cfg->method);
2689
2690                 if (info && info->subtype == WRAPPER_SUBTYPE_PINVOKE)
2691                         check_sp = TRUE;
2692         }
2693
2694         if (rgctx_arg) {
2695                 rgctx_reg = mono_alloc_preg (cfg);
2696                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2697         }
2698
2699         if (check_sp) {
2700                 if (!cfg->stack_inbalance_var)
2701                         cfg->stack_inbalance_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2702
2703                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2704                 ins->dreg = cfg->stack_inbalance_var->dreg;
2705                 MONO_ADD_INS (cfg->cbb, ins);
2706         }
2707
2708         call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE, FALSE);
2709
2710         call->inst.sreg1 = addr->dreg;
2711
2712         if (imt_arg)
2713                 emit_imt_argument (cfg, call, NULL, imt_arg);
2714
2715         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2716
2717         if (check_sp) {
2718                 int sp_reg;
2719
2720                 sp_reg = mono_alloc_preg (cfg);
2721
2722                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2723                 ins->dreg = sp_reg;
2724                 MONO_ADD_INS (cfg->cbb, ins);
2725
2726                 /* Restore the stack so we don't crash when throwing the exception */
2727                 MONO_INST_NEW (cfg, ins, OP_SET_SP);
2728                 ins->sreg1 = cfg->stack_inbalance_var->dreg;
2729                 MONO_ADD_INS (cfg->cbb, ins);
2730
2731                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, cfg->stack_inbalance_var->dreg, sp_reg);
2732                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ExecutionEngineException");
2733         }
2734
2735         if (rgctx_arg)
2736                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2737
2738         return (MonoInst*)call;
2739 }
2740
2741 static MonoInst*
2742 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2743
2744 static MonoInst*
2745 emit_get_rgctx_method (MonoCompile *cfg, int context_used, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type);
2746 static MonoInst*
2747 emit_get_rgctx_klass (MonoCompile *cfg, int context_used, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2748
2749 static MonoInst*
2750 mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig, gboolean tail,
2751                                                         MonoInst **args, MonoInst *this_ins, MonoInst *imt_arg, MonoInst *rgctx_arg)
2752 {
2753 #ifndef DISABLE_REMOTING
2754         gboolean might_be_remote = FALSE;
2755 #endif
2756         gboolean virtual_ = this_ins != NULL;
2757         gboolean enable_for_aot = TRUE;
2758         int context_used;
2759         MonoCallInst *call;
2760         MonoInst *call_target = NULL;
2761         int rgctx_reg = 0;
2762         gboolean need_unbox_trampoline;
2763
2764         if (!sig)
2765                 sig = mono_method_signature (method);
2766
2767         if (cfg->llvm_only && (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE))
2768                 g_assert_not_reached ();
2769
2770         if (rgctx_arg) {
2771                 rgctx_reg = mono_alloc_preg (cfg);
2772                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2773         }
2774
2775         if (method->string_ctor) {
2776                 /* Create the real signature */
2777                 /* FIXME: Cache these */
2778                 MonoMethodSignature *ctor_sig = mono_metadata_signature_dup_mempool (cfg->mempool, sig);
2779                 ctor_sig->ret = &mono_defaults.string_class->byval_arg;
2780
2781                 sig = ctor_sig;
2782         }
2783
2784         context_used = mini_method_check_context_used (cfg, method);
2785
2786 #ifndef DISABLE_REMOTING
2787         might_be_remote = this_ins && sig->hasthis &&
2788                 (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) &&
2789                 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && (!MONO_CHECK_THIS (this_ins) || context_used);
2790
2791         if (might_be_remote && context_used) {
2792                 MonoInst *addr;
2793
2794                 g_assert (cfg->gshared);
2795
2796                 addr = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK);
2797
2798                 return mono_emit_calli (cfg, sig, args, addr, NULL, NULL);
2799         }
2800 #endif
2801
2802         if (cfg->llvm_only && !call_target && virtual_ && (method->flags & METHOD_ATTRIBUTE_VIRTUAL))
2803                 return emit_llvmonly_virtual_call (cfg, method, sig, 0, args);
2804
2805         need_unbox_trampoline = method->klass == mono_defaults.object_class || (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
2806
2807         call = mono_emit_call_args (cfg, sig, args, FALSE, virtual_, tail, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline);
2808
2809 #ifndef DISABLE_REMOTING
2810         if (might_be_remote)
2811                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2812         else
2813 #endif
2814                 call->method = method;
2815         call->inst.flags |= MONO_INST_HAS_METHOD;
2816         call->inst.inst_left = this_ins;
2817         call->tail_call = tail;
2818
2819         if (virtual_) {
2820                 int vtable_reg, slot_reg, this_reg;
2821                 int offset;
2822
2823                 this_reg = this_ins->dreg;
2824
2825                 if (!cfg->llvm_only && (method->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (method->name, "Invoke")) {
2826                         MonoInst *dummy_use;
2827
2828                         MONO_EMIT_NULL_CHECK (cfg, this_reg);
2829
2830                         /* Make a call to delegate->invoke_impl */
2831                         call->inst.inst_basereg = this_reg;
2832                         call->inst.inst_offset = MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl);
2833                         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2834
2835                         /* We must emit a dummy use here because the delegate trampoline will
2836                         replace the 'this' argument with the delegate target making this activation
2837                         no longer a root for the delegate.
2838                         This is an issue for delegates that target collectible code such as dynamic
2839                         methods of GC'able assemblies.
2840
2841                         For a test case look into #667921.
2842
2843                         FIXME: a dummy use is not the best way to do it as the local register allocator
2844                         will put it on a caller save register and spil it around the call. 
2845                         Ideally, we would either put it on a callee save register or only do the store part.  
2846                          */
2847                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, args [0]);
2848
2849                         return (MonoInst*)call;
2850                 }
2851
2852                 if ((!cfg->compile_aot || enable_for_aot) && 
2853                         (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || 
2854                          (MONO_METHOD_IS_FINAL (method) &&
2855                           method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)) &&
2856                         !(mono_class_is_marshalbyref (method->klass) && context_used)) {
2857                         /* 
2858                          * the method is not virtual, we just need to ensure this is not null
2859                          * and then we can call the method directly.
2860                          */
2861 #ifndef DISABLE_REMOTING
2862                         if (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) {
2863                                 /* 
2864                                  * The check above ensures method is not gshared, this is needed since
2865                                  * gshared methods can't have wrappers.
2866                                  */
2867                                 method = call->method = mono_marshal_get_remoting_invoke_with_check (method);
2868                         }
2869 #endif
2870
2871                         if (!method->string_ctor)
2872                                 MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2873
2874                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2875                 } else if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && MONO_METHOD_IS_FINAL (method)) {
2876                         /*
2877                          * the method is virtual, but we can statically dispatch since either
2878                          * it's class or the method itself are sealed.
2879                          * But first we need to ensure it's not a null reference.
2880                          */
2881                         MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2882
2883                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2884                 } else if (call_target) {
2885                         vtable_reg = alloc_preg (cfg);
2886                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2887
2888                         call->inst.opcode = callvirt_to_call_reg (call->inst.opcode);
2889                         call->inst.sreg1 = call_target->dreg;
2890                         call->inst.flags &= !MONO_INST_HAS_METHOD;
2891                 } else {
2892                         vtable_reg = alloc_preg (cfg);
2893                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2894                         if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2895                                 guint32 imt_slot = mono_method_get_imt_slot (method);
2896                                 emit_imt_argument (cfg, call, call->method, imt_arg);
2897                                 slot_reg = vtable_reg;
2898                                 offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
2899                         } else {
2900                                 slot_reg = vtable_reg;
2901                                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) +
2902                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
2903                                 if (imt_arg) {
2904                                         g_assert (mono_method_signature (method)->generic_param_count);
2905                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2906                                 }
2907                         }
2908
2909                         call->inst.sreg1 = slot_reg;
2910                         call->inst.inst_offset = offset;
2911                         call->is_virtual = TRUE;
2912                 }
2913         }
2914
2915         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2916
2917         if (rgctx_arg)
2918                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2919
2920         return (MonoInst*)call;
2921 }
2922
2923 MonoInst*
2924 mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoInst **args, MonoInst *this_ins)
2925 {
2926         return mono_emit_method_call_full (cfg, method, mono_method_signature (method), FALSE, args, this_ins, NULL, NULL);
2927 }
2928
2929 MonoInst*
2930 mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig,
2931                                            MonoInst **args)
2932 {
2933         MonoCallInst *call;
2934
2935         g_assert (sig);
2936
2937         call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE, FALSE, FALSE);
2938         call->fptr = func;
2939
2940         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2941
2942         return (MonoInst*)call;
2943 }
2944
2945 MonoInst*
2946 mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args)
2947 {
2948         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2949
2950         g_assert (info);
2951
2952         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2953 }
2954
2955 /*
2956  * mono_emit_abs_call:
2957  *
2958  *   Emit a call to the runtime function described by PATCH_TYPE and DATA.
2959  */
2960 inline static MonoInst*
2961 mono_emit_abs_call (MonoCompile *cfg, MonoJumpInfoType patch_type, gconstpointer data, 
2962                                         MonoMethodSignature *sig, MonoInst **args)
2963 {
2964         MonoJumpInfo *ji = mono_patch_info_new (cfg->mempool, 0, patch_type, data);
2965         MonoInst *ins;
2966
2967         /* 
2968          * We pass ji as the call address, the PATCH_INFO_ABS resolving code will
2969          * handle it.
2970          */
2971         if (cfg->abs_patches == NULL)
2972                 cfg->abs_patches = g_hash_table_new (NULL, NULL);
2973         g_hash_table_insert (cfg->abs_patches, ji, ji);
2974         ins = mono_emit_native_call (cfg, ji, sig, args);
2975         ((MonoCallInst*)ins)->fptr_is_patch = TRUE;
2976         return ins;
2977 }
2978
2979 static MonoMethodSignature*
2980 sig_to_rgctx_sig (MonoMethodSignature *sig)
2981 {
2982         // FIXME: memory allocation
2983         MonoMethodSignature *res;
2984         int i;
2985
2986         res = (MonoMethodSignature *)g_malloc (MONO_SIZEOF_METHOD_SIGNATURE + (sig->param_count + 1) * sizeof (MonoType*));
2987         memcpy (res, sig, MONO_SIZEOF_METHOD_SIGNATURE);
2988         res->param_count = sig->param_count + 1;
2989         for (i = 0; i < sig->param_count; ++i)
2990                 res->params [i] = sig->params [i];
2991         res->params [sig->param_count] = &mono_defaults.int_class->this_arg;
2992         return res;
2993 }
2994
2995 /* Make an indirect call to FSIG passing an additional argument */
2996 static MonoInst*
2997 emit_extra_arg_calli (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **orig_args, int arg_reg, MonoInst *call_target)
2998 {
2999         MonoMethodSignature *csig;
3000         MonoInst *args_buf [16];
3001         MonoInst **args;
3002         int i, pindex, tmp_reg;
3003
3004         /* Make a call with an rgctx/extra arg */
3005         if (fsig->param_count + 2 < 16)
3006                 args = args_buf;
3007         else
3008                 args = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (fsig->param_count + 2));
3009         pindex = 0;
3010         if (fsig->hasthis)
3011                 args [pindex ++] = orig_args [0];
3012         for (i = 0; i < fsig->param_count; ++i)
3013                 args [pindex ++] = orig_args [fsig->hasthis + i];
3014         tmp_reg = alloc_preg (cfg);
3015         EMIT_NEW_UNALU (cfg, args [pindex], OP_MOVE, tmp_reg, arg_reg);
3016         csig = sig_to_rgctx_sig (fsig);
3017         return mono_emit_calli (cfg, csig, args, call_target, NULL, NULL);
3018 }
3019
3020 /* Emit an indirect call to the function descriptor ADDR */
3021 static MonoInst*
3022 emit_llvmonly_calli (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, MonoInst *addr)
3023 {
3024         int addr_reg, arg_reg;
3025         MonoInst *call_target;
3026
3027         g_assert (cfg->llvm_only);
3028
3029         /*
3030          * addr points to a <addr, arg> pair, load both of them, and
3031          * make a call to addr, passing arg as an extra arg.
3032          */
3033         addr_reg = alloc_preg (cfg);
3034         EMIT_NEW_LOAD_MEMBASE (cfg, call_target, OP_LOAD_MEMBASE, addr_reg, addr->dreg, 0);
3035         arg_reg = alloc_preg (cfg);
3036         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, arg_reg, addr->dreg, sizeof (gpointer));
3037
3038         return emit_extra_arg_calli (cfg, fsig, args, arg_reg, call_target);
3039 }
3040
3041 static gboolean
3042 direct_icalls_enabled (MonoCompile *cfg)
3043 {
3044         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
3045 #ifdef TARGET_AMD64
3046         if (cfg->compile_llvm)
3047                 return FALSE;
3048 #endif
3049         if (cfg->gen_sdb_seq_points || cfg->disable_direct_icalls)
3050                 return FALSE;
3051         return TRUE;
3052 }
3053
3054 MonoInst*
3055 mono_emit_jit_icall_by_info (MonoCompile *cfg, MonoJitICallInfo *info, MonoInst **args)
3056 {
3057         /*
3058          * Call the jit icall without a wrapper if possible.
3059          * The wrapper is needed for the following reasons:
3060          * - to handle exceptions thrown using mono_raise_exceptions () from the
3061          *   icall function. The EH code needs the lmf frame pushed by the
3062          *   wrapper to be able to unwind back to managed code.
3063          * - to be able to do stack walks for asynchronously suspended
3064          *   threads when debugging.
3065          */
3066         if (info->no_raise && direct_icalls_enabled (cfg)) {
3067                 char *name;
3068                 int costs;
3069
3070                 if (!info->wrapper_method) {
3071                         name = g_strdup_printf ("__icall_wrapper_%s", info->name);
3072                         info->wrapper_method = mono_marshal_get_icall_wrapper (info->sig, name, info->func, TRUE);
3073                         g_free (name);
3074                         mono_memory_barrier ();
3075                 }
3076
3077                 /*
3078                  * Inline the wrapper method, which is basically a call to the C icall, and
3079                  * an exception check.
3080                  */
3081                 costs = inline_method (cfg, info->wrapper_method, NULL,
3082                                                            args, NULL, cfg->real_offset, TRUE);
3083                 g_assert (costs > 0);
3084                 g_assert (!MONO_TYPE_IS_VOID (info->sig->ret));
3085
3086                 return args [0];
3087         } else {
3088                 return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
3089         }
3090 }
3091  
3092 static MonoInst*
3093 mono_emit_widen_call_res (MonoCompile *cfg, MonoInst *ins, MonoMethodSignature *fsig)
3094 {
3095         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
3096                 if ((fsig->pinvoke || LLVM_ENABLED) && !fsig->ret->byref) {
3097                         int widen_op = -1;
3098
3099                         /* 
3100                          * Native code might return non register sized integers 
3101                          * without initializing the upper bits.
3102                          */
3103                         switch (mono_type_to_load_membase (cfg, fsig->ret)) {
3104                         case OP_LOADI1_MEMBASE:
3105                                 widen_op = OP_ICONV_TO_I1;
3106                                 break;
3107                         case OP_LOADU1_MEMBASE:
3108                                 widen_op = OP_ICONV_TO_U1;
3109                                 break;
3110                         case OP_LOADI2_MEMBASE:
3111                                 widen_op = OP_ICONV_TO_I2;
3112                                 break;
3113                         case OP_LOADU2_MEMBASE:
3114                                 widen_op = OP_ICONV_TO_U2;
3115                                 break;
3116                         default:
3117                                 break;
3118                         }
3119
3120                         if (widen_op != -1) {
3121                                 int dreg = alloc_preg (cfg);
3122                                 MonoInst *widen;
3123
3124                                 EMIT_NEW_UNALU (cfg, widen, widen_op, dreg, ins->dreg);
3125                                 widen->type = ins->type;
3126                                 ins = widen;
3127                         }
3128                 }
3129         }
3130
3131         return ins;
3132 }
3133
3134 static MonoMethod*
3135 get_memcpy_method (void)
3136 {
3137         static MonoMethod *memcpy_method = NULL;
3138         if (!memcpy_method) {
3139                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
3140                 if (!memcpy_method)
3141                         g_error ("Old corlib found. Install a new one");
3142         }
3143         return memcpy_method;
3144 }
3145
3146 static void
3147 create_write_barrier_bitmap (MonoCompile *cfg, MonoClass *klass, unsigned *wb_bitmap, int offset)
3148 {
3149         MonoClassField *field;
3150         gpointer iter = NULL;
3151
3152         while ((field = mono_class_get_fields (klass, &iter))) {
3153                 int foffset;
3154
3155                 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3156                         continue;
3157                 foffset = klass->valuetype ? field->offset - sizeof (MonoObject): field->offset;
3158                 if (mini_type_is_reference (mono_field_get_type (field))) {
3159                         g_assert ((foffset % SIZEOF_VOID_P) == 0);
3160                         *wb_bitmap |= 1 << ((offset + foffset) / SIZEOF_VOID_P);
3161                 } else {
3162                         MonoClass *field_class = mono_class_from_mono_type (field->type);
3163                         if (field_class->has_references)
3164                                 create_write_barrier_bitmap (cfg, field_class, wb_bitmap, offset + foffset);
3165                 }
3166         }
3167 }
3168
3169 static void
3170 emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value)
3171 {
3172         int card_table_shift_bits;
3173         gpointer card_table_mask;
3174         guint8 *card_table;
3175         MonoInst *dummy_use;
3176         int nursery_shift_bits;
3177         size_t nursery_size;
3178
3179         if (!cfg->gen_write_barriers)
3180                 return;
3181
3182         card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
3183
3184         mono_gc_get_nursery (&nursery_shift_bits, &nursery_size);
3185
3186         if (cfg->backend->have_card_table_wb && !cfg->compile_aot && card_table && nursery_shift_bits > 0 && !COMPILE_LLVM (cfg)) {
3187                 MonoInst *wbarrier;
3188
3189                 MONO_INST_NEW (cfg, wbarrier, OP_CARD_TABLE_WBARRIER);
3190                 wbarrier->sreg1 = ptr->dreg;
3191                 wbarrier->sreg2 = value->dreg;
3192                 MONO_ADD_INS (cfg->cbb, wbarrier);
3193         } else if (card_table && !cfg->compile_aot && !mono_gc_card_table_nursery_check ()) {
3194                 int offset_reg = alloc_preg (cfg);
3195                 int card_reg;
3196                 MonoInst *ins;
3197
3198                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, offset_reg, ptr->dreg, card_table_shift_bits);
3199                 if (card_table_mask)
3200                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, offset_reg, offset_reg, card_table_mask);
3201
3202                 /*We can't use PADD_IMM since the cardtable might end up in high addresses and amd64 doesn't support
3203                  * IMM's larger than 32bits.
3204                  */
3205                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
3206                 card_reg = ins->dreg;
3207
3208                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, offset_reg, offset_reg, card_reg);
3209                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, offset_reg, 0, 1);
3210         } else {
3211                 MonoMethod *write_barrier = mono_gc_get_write_barrier ();
3212                 mono_emit_method_call (cfg, write_barrier, &ptr, NULL);
3213         }
3214
3215         EMIT_NEW_DUMMY_USE (cfg, dummy_use, value);
3216 }
3217
3218 static gboolean
3219 mono_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align)
3220 {
3221         int dest_ptr_reg, tmp_reg, destreg, srcreg, offset;
3222         unsigned need_wb = 0;
3223
3224         if (align == 0)
3225                 align = 4;
3226
3227         /*types with references can't have alignment smaller than sizeof(void*) */
3228         if (align < SIZEOF_VOID_P)
3229                 return FALSE;
3230
3231         /*This value cannot be bigger than 32 due to the way we calculate the required wb bitmap.*/
3232         if (size > 32 * SIZEOF_VOID_P)
3233                 return FALSE;
3234
3235         create_write_barrier_bitmap (cfg, klass, &need_wb, 0);
3236
3237         /* We don't unroll more than 5 stores to avoid code bloat. */
3238         if (size > 5 * SIZEOF_VOID_P) {
3239                 /*This is harmless and simplify mono_gc_wbarrier_value_copy_bitmap */
3240                 size += (SIZEOF_VOID_P - 1);
3241                 size &= ~(SIZEOF_VOID_P - 1);
3242
3243                 EMIT_NEW_ICONST (cfg, iargs [2], size);
3244                 EMIT_NEW_ICONST (cfg, iargs [3], need_wb);
3245                 mono_emit_jit_icall (cfg, mono_gc_wbarrier_value_copy_bitmap, iargs);
3246                 return TRUE;
3247         }
3248
3249         destreg = iargs [0]->dreg;
3250         srcreg = iargs [1]->dreg;
3251         offset = 0;
3252
3253         dest_ptr_reg = alloc_preg (cfg);
3254         tmp_reg = alloc_preg (cfg);
3255
3256         /*tmp = dreg*/
3257         EMIT_NEW_UNALU (cfg, iargs [0], OP_MOVE, dest_ptr_reg, destreg);
3258
3259         while (size >= SIZEOF_VOID_P) {
3260                 MonoInst *load_inst;
3261                 MONO_INST_NEW (cfg, load_inst, OP_LOAD_MEMBASE);
3262                 load_inst->dreg = tmp_reg;
3263                 load_inst->inst_basereg = srcreg;
3264                 load_inst->inst_offset = offset;
3265                 MONO_ADD_INS (cfg->cbb, load_inst);
3266
3267                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, dest_ptr_reg, 0, tmp_reg);
3268
3269                 if (need_wb & 0x1)
3270                         emit_write_barrier (cfg, iargs [0], load_inst);
3271
3272                 offset += SIZEOF_VOID_P;
3273                 size -= SIZEOF_VOID_P;
3274                 need_wb >>= 1;
3275
3276                 /*tmp += sizeof (void*)*/
3277                 if (size >= SIZEOF_VOID_P) {
3278                         NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dest_ptr_reg, dest_ptr_reg, SIZEOF_VOID_P);
3279                         MONO_ADD_INS (cfg->cbb, iargs [0]);
3280                 }
3281         }
3282
3283         /* Those cannot be references since size < sizeof (void*) */
3284         while (size >= 4) {
3285                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tmp_reg, srcreg, offset);
3286                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, tmp_reg);
3287                 offset += 4;
3288                 size -= 4;
3289         }
3290
3291         while (size >= 2) {
3292                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmp_reg, srcreg, offset);
3293                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, tmp_reg);
3294                 offset += 2;
3295                 size -= 2;
3296         }
3297
3298         while (size >= 1) {
3299                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmp_reg, srcreg, offset);
3300                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, tmp_reg);
3301                 offset += 1;
3302                 size -= 1;
3303         }
3304
3305         return TRUE;
3306 }
3307
3308 /*
3309  * Emit code to copy a valuetype of type @klass whose address is stored in
3310  * @src->dreg to memory whose address is stored at @dest->dreg.
3311  */
3312 void
3313 mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native)
3314 {
3315         MonoInst *iargs [4];
3316         int n;
3317         guint32 align = 0;
3318         MonoMethod *memcpy_method;
3319         MonoInst *size_ins = NULL;
3320         MonoInst *memcpy_ins = NULL;
3321
3322         g_assert (klass);
3323         if (cfg->gshared)
3324                 klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg));
3325
3326         /*
3327          * This check breaks with spilled vars... need to handle it during verification anyway.
3328          * g_assert (klass && klass == src->klass && klass == dest->klass);
3329          */
3330
3331         if (mini_is_gsharedvt_klass (klass)) {
3332                 g_assert (!native);
3333                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3334                 memcpy_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_MEMCPY);
3335         }
3336
3337         if (native)
3338                 n = mono_class_native_size (klass, &align);
3339         else
3340                 n = mono_class_value_size (klass, &align);
3341
3342         /* if native is true there should be no references in the struct */
3343         if (cfg->gen_write_barriers && (klass->has_references || size_ins) && !native) {
3344                 /* Avoid barriers when storing to the stack */
3345                 if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) ||
3346                           (dest->opcode == OP_LDADDR))) {
3347                         int context_used;
3348
3349                         iargs [0] = dest;
3350                         iargs [1] = src;
3351
3352                         context_used = mini_class_check_context_used (cfg, klass);
3353
3354                         /* It's ok to intrinsify under gsharing since shared code types are layout stable. */
3355                         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && mono_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
3356                                 return;
3357                         } else if (context_used) {
3358                                 iargs [2] = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3359                         }  else {
3360                                 iargs [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
3361                                 if (!cfg->compile_aot)
3362                                         mono_class_compute_gc_descriptor (klass);
3363                         }
3364
3365                         if (size_ins)
3366                                 mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs);
3367                         else
3368                                 mono_emit_jit_icall (cfg, mono_value_copy, iargs);
3369                         return;
3370                 }
3371         }
3372
3373         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 8) {
3374                 /* FIXME: Optimize the case when src/dest is OP_LDADDR */
3375                 mini_emit_memcpy (cfg, dest->dreg, 0, src->dreg, 0, n, align);
3376         } else {
3377                 iargs [0] = dest;
3378                 iargs [1] = src;
3379                 if (size_ins)
3380                         iargs [2] = size_ins;
3381                 else
3382                         EMIT_NEW_ICONST (cfg, iargs [2], n);
3383                 
3384                 memcpy_method = get_memcpy_method ();
3385                 if (memcpy_ins)
3386                         mono_emit_calli (cfg, mono_method_signature (memcpy_method), iargs, memcpy_ins, NULL, NULL);
3387                 else
3388                         mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
3389         }
3390 }
3391
3392 static MonoMethod*
3393 get_memset_method (void)
3394 {
3395         static MonoMethod *memset_method = NULL;
3396         if (!memset_method) {
3397                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
3398                 if (!memset_method)
3399                         g_error ("Old corlib found. Install a new one");
3400         }
3401         return memset_method;
3402 }
3403
3404 void
3405 mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass)
3406 {
3407         MonoInst *iargs [3];
3408         int n;
3409         guint32 align;
3410         MonoMethod *memset_method;
3411         MonoInst *size_ins = NULL;
3412         MonoInst *bzero_ins = NULL;
3413         static MonoMethod *bzero_method;
3414
3415         /* FIXME: Optimize this for the case when dest is an LDADDR */
3416         mono_class_init (klass);
3417         if (mini_is_gsharedvt_klass (klass)) {
3418                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3419                 bzero_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_BZERO);
3420                 if (!bzero_method)
3421                         bzero_method = mono_class_get_method_from_name (mono_defaults.string_class, "bzero_aligned_1", 2);
3422                 g_assert (bzero_method);
3423                 iargs [0] = dest;
3424                 iargs [1] = size_ins;
3425                 mono_emit_calli (cfg, mono_method_signature (bzero_method), iargs, bzero_ins, NULL, NULL);
3426                 return;
3427         }
3428
3429         klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg));
3430
3431         n = mono_class_value_size (klass, &align);
3432
3433         if (n <= sizeof (gpointer) * 8) {
3434                 mini_emit_memset (cfg, dest->dreg, 0, n, 0, align);
3435         }
3436         else {
3437                 memset_method = get_memset_method ();
3438                 iargs [0] = dest;
3439                 EMIT_NEW_ICONST (cfg, iargs [1], 0);
3440                 EMIT_NEW_ICONST (cfg, iargs [2], n);
3441                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
3442         }
3443 }
3444
3445 /*
3446  * emit_get_rgctx:
3447  *
3448  *   Emit IR to return either the this pointer for instance method,
3449  * or the mrgctx for static methods.
3450  */
3451 static MonoInst*
3452 emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used)
3453 {
3454         MonoInst *this_ins = NULL;
3455
3456         g_assert (cfg->gshared);
3457
3458         if (!(method->flags & METHOD_ATTRIBUTE_STATIC) &&
3459                         !(context_used & MONO_GENERIC_CONTEXT_USED_METHOD) &&
3460                         !method->klass->valuetype)
3461                 EMIT_NEW_ARGLOAD (cfg, this_ins, 0);
3462
3463         if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
3464                 MonoInst *mrgctx_loc, *mrgctx_var;
3465
3466                 g_assert (!this_ins);
3467                 g_assert (method->is_inflated && mono_method_get_context (method)->method_inst);
3468
3469                 mrgctx_loc = mono_get_vtable_var (cfg);
3470                 EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
3471
3472                 return mrgctx_var;
3473         } else if (method->flags & METHOD_ATTRIBUTE_STATIC || method->klass->valuetype) {
3474                 MonoInst *vtable_loc, *vtable_var;
3475
3476                 g_assert (!this_ins);
3477
3478                 vtable_loc = mono_get_vtable_var (cfg);
3479                 EMIT_NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
3480
3481                 if (method->is_inflated && mono_method_get_context (method)->method_inst) {
3482                         MonoInst *mrgctx_var = vtable_var;
3483                         int vtable_reg;
3484
3485                         vtable_reg = alloc_preg (cfg);
3486                         EMIT_NEW_LOAD_MEMBASE (cfg, vtable_var, OP_LOAD_MEMBASE, vtable_reg, mrgctx_var->dreg, MONO_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, class_vtable));
3487                         vtable_var->type = STACK_PTR;
3488                 }
3489
3490                 return vtable_var;
3491         } else {
3492                 MonoInst *ins;
3493                 int vtable_reg;
3494         
3495                 vtable_reg = alloc_preg (cfg);
3496                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, vtable_reg, this_ins->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3497                 return ins;
3498         }
3499 }
3500
3501 static MonoJumpInfoRgctxEntry *
3502 mono_patch_info_rgctx_entry_new (MonoMemPool *mp, MonoMethod *method, gboolean in_mrgctx, MonoJumpInfoType patch_type, gconstpointer patch_data, MonoRgctxInfoType info_type)
3503 {
3504         MonoJumpInfoRgctxEntry *res = (MonoJumpInfoRgctxEntry *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoRgctxEntry));
3505         res->method = method;
3506         res->in_mrgctx = in_mrgctx;
3507         res->data = (MonoJumpInfo *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
3508         res->data->type = patch_type;
3509         res->data->data.target = patch_data;
3510         res->info_type = info_type;
3511
3512         return res;
3513 }
3514
3515 static inline MonoInst*
3516 emit_rgctx_fetch_inline (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3517 {
3518         MonoInst *args [16];
3519         MonoInst *call;
3520
3521         // FIXME: No fastpath since the slot is not a compile time constant
3522         args [0] = rgctx;
3523         EMIT_NEW_AOTCONST (cfg, args [1], MONO_PATCH_INFO_RGCTX_SLOT_INDEX, entry);
3524         if (entry->in_mrgctx)
3525                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3526         else
3527                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3528         return call;
3529 #if 0
3530         /*
3531          * FIXME: This can be called during decompose, which is a problem since it creates
3532          * new bblocks.
3533          * Also, the fastpath doesn't work since the slot number is dynamically allocated.
3534          */
3535         int i, slot, depth, index, rgctx_reg, val_reg, res_reg;
3536         gboolean mrgctx;
3537         MonoBasicBlock *is_null_bb, *end_bb;
3538         MonoInst *res, *ins, *call;
3539         MonoInst *args[16];
3540
3541         slot = mini_get_rgctx_entry_slot (entry);
3542
3543         mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot);
3544         index = MONO_RGCTX_SLOT_INDEX (slot);
3545         if (mrgctx)
3546                 index += MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
3547         for (depth = 0; ; ++depth) {
3548                 int size = mono_class_rgctx_get_array_size (depth, mrgctx);
3549
3550                 if (index < size - 1)
3551                         break;
3552                 index -= size - 1;
3553         }
3554
3555         NEW_BBLOCK (cfg, end_bb);
3556         NEW_BBLOCK (cfg, is_null_bb);
3557
3558         if (mrgctx) {
3559                 rgctx_reg = rgctx->dreg;
3560         } else {
3561                 rgctx_reg = alloc_preg (cfg);
3562
3563                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, rgctx_reg, rgctx->dreg, MONO_STRUCT_OFFSET (MonoVTable, runtime_generic_context));
3564                 // FIXME: Avoid this check by allocating the table when the vtable is created etc.
3565                 NEW_BBLOCK (cfg, is_null_bb);
3566
3567                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3568                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3569         }
3570
3571         for (i = 0; i < depth; ++i) {
3572                 int array_reg = alloc_preg (cfg);
3573
3574                 /* load ptr to next array */
3575                 if (mrgctx && i == 0)
3576                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT);
3577                 else
3578                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, 0);
3579                 rgctx_reg = array_reg;
3580                 /* is the ptr null? */
3581                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3582                 /* if yes, jump to actual trampoline */
3583                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3584         }
3585
3586         /* fetch slot */
3587         val_reg = alloc_preg (cfg);
3588         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, val_reg, rgctx_reg, (index + 1) * sizeof (gpointer));
3589         /* is the slot null? */
3590         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, val_reg, 0);
3591         /* if yes, jump to actual trampoline */
3592         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3593
3594         /* Fastpath */
3595         res_reg = alloc_preg (cfg);
3596         MONO_INST_NEW (cfg, ins, OP_MOVE);
3597         ins->dreg = res_reg;
3598         ins->sreg1 = val_reg;
3599         MONO_ADD_INS (cfg->cbb, ins);
3600         res = ins;
3601         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3602
3603         /* Slowpath */
3604         MONO_START_BB (cfg, is_null_bb);
3605         args [0] = rgctx;
3606         EMIT_NEW_ICONST (cfg, args [1], index);
3607         if (mrgctx)
3608                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3609         else
3610                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3611         MONO_INST_NEW (cfg, ins, OP_MOVE);
3612         ins->dreg = res_reg;
3613         ins->sreg1 = call->dreg;
3614         MONO_ADD_INS (cfg->cbb, ins);
3615         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3616
3617         MONO_START_BB (cfg, end_bb);
3618
3619         return res;
3620 #endif
3621 }
3622
3623 /*
3624  * emit_rgctx_fetch:
3625  *
3626  *   Emit IR to load the value of the rgctx entry ENTRY from the rgctx
3627  * given by RGCTX.
3628  */
3629 static inline MonoInst*
3630 emit_rgctx_fetch (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3631 {
3632         if (cfg->llvm_only)
3633                 return emit_rgctx_fetch_inline (cfg, rgctx, entry);
3634         else
3635                 return mono_emit_abs_call (cfg, MONO_PATCH_INFO_RGCTX_FETCH, entry, helper_sig_rgctx_lazy_fetch_trampoline, &rgctx);
3636 }
3637
3638 static MonoInst*
3639 emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
3640                                           MonoClass *klass, MonoRgctxInfoType rgctx_type)
3641 {
3642         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);
3643         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3644
3645         return emit_rgctx_fetch (cfg, rgctx, entry);
3646 }
3647
3648 static MonoInst*
3649 emit_get_rgctx_sig (MonoCompile *cfg, int context_used,
3650                                         MonoMethodSignature *sig, MonoRgctxInfoType rgctx_type)
3651 {
3652         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);
3653         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3654
3655         return emit_rgctx_fetch (cfg, rgctx, entry);
3656 }
3657
3658 static MonoInst*
3659 emit_get_rgctx_gsharedvt_call (MonoCompile *cfg, int context_used,
3660                                                            MonoMethodSignature *sig, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3661 {
3662         MonoJumpInfoGSharedVtCall *call_info;
3663         MonoJumpInfoRgctxEntry *entry;
3664         MonoInst *rgctx;
3665
3666         call_info = (MonoJumpInfoGSharedVtCall *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoGSharedVtCall));
3667         call_info->sig = sig;
3668         call_info->method = cmethod;
3669
3670         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);
3671         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3672
3673         return emit_rgctx_fetch (cfg, rgctx, entry);
3674 }
3675
3676 /*
3677  * emit_get_rgctx_virt_method:
3678  *
3679  *   Return data for method VIRT_METHOD for a receiver of type KLASS.
3680  */
3681 static MonoInst*
3682 emit_get_rgctx_virt_method (MonoCompile *cfg, int context_used,
3683                                                         MonoClass *klass, MonoMethod *virt_method, MonoRgctxInfoType rgctx_type)
3684 {
3685         MonoJumpInfoVirtMethod *info;
3686         MonoJumpInfoRgctxEntry *entry;
3687         MonoInst *rgctx;
3688
3689         info = (MonoJumpInfoVirtMethod *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoVirtMethod));
3690         info->klass = klass;
3691         info->method = virt_method;
3692
3693         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);
3694         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3695
3696         return emit_rgctx_fetch (cfg, rgctx, entry);
3697 }
3698
3699 static MonoInst*
3700 emit_get_rgctx_gsharedvt_method (MonoCompile *cfg, int context_used,
3701                                                                  MonoMethod *cmethod, MonoGSharedVtMethodInfo *info)
3702 {
3703         MonoJumpInfoRgctxEntry *entry;
3704         MonoInst *rgctx;
3705
3706         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);
3707         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3708
3709         return emit_rgctx_fetch (cfg, rgctx, entry);
3710 }
3711
3712 /*
3713  * emit_get_rgctx_method:
3714  *
3715  *   Emit IR to load the property RGCTX_TYPE of CMETHOD. If context_used is 0, emit
3716  * normal constants, else emit a load from the rgctx.
3717  */
3718 static MonoInst*
3719 emit_get_rgctx_method (MonoCompile *cfg, int context_used,
3720                                            MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3721 {
3722         if (!context_used) {
3723                 MonoInst *ins;
3724
3725                 switch (rgctx_type) {
3726                 case MONO_RGCTX_INFO_METHOD:
3727                         EMIT_NEW_METHODCONST (cfg, ins, cmethod);
3728                         return ins;
3729                 case MONO_RGCTX_INFO_METHOD_RGCTX:
3730                         EMIT_NEW_METHOD_RGCTX_CONST (cfg, ins, cmethod);
3731                         return ins;
3732                 default:
3733                         g_assert_not_reached ();
3734                 }
3735         } else {
3736                 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);
3737                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3738
3739                 return emit_rgctx_fetch (cfg, rgctx, entry);
3740         }
3741 }
3742
3743 static MonoInst*
3744 emit_get_rgctx_field (MonoCompile *cfg, int context_used,
3745                                           MonoClassField *field, MonoRgctxInfoType rgctx_type)
3746 {
3747         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);
3748         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3749
3750         return emit_rgctx_fetch (cfg, rgctx, entry);
3751 }
3752
3753 static int
3754 get_gsharedvt_info_slot (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3755 {
3756         MonoGSharedVtMethodInfo *info = cfg->gsharedvt_info;
3757         MonoRuntimeGenericContextInfoTemplate *template_;
3758         int i, idx;
3759
3760         g_assert (info);
3761
3762         for (i = 0; i < info->num_entries; ++i) {
3763                 MonoRuntimeGenericContextInfoTemplate *otemplate = &info->entries [i];
3764
3765                 if (otemplate->info_type == rgctx_type && otemplate->data == data && rgctx_type != MONO_RGCTX_INFO_LOCAL_OFFSET)
3766                         return i;
3767         }
3768
3769         if (info->num_entries == info->count_entries) {
3770                 MonoRuntimeGenericContextInfoTemplate *new_entries;
3771                 int new_count_entries = info->count_entries ? info->count_entries * 2 : 16;
3772
3773                 new_entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * new_count_entries);
3774
3775                 memcpy (new_entries, info->entries, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
3776                 info->entries = new_entries;
3777                 info->count_entries = new_count_entries;
3778         }
3779
3780         idx = info->num_entries;
3781         template_ = &info->entries [idx];
3782         template_->info_type = rgctx_type;
3783         template_->data = data;
3784
3785         info->num_entries ++;
3786
3787         return idx;
3788 }
3789
3790 /*
3791  * emit_get_gsharedvt_info:
3792  *
3793  *   This is similar to emit_get_rgctx_.., but loads the data from the gsharedvt info var instead of calling an rgctx fetch trampoline.
3794  */
3795 static MonoInst*
3796 emit_get_gsharedvt_info (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3797 {
3798         MonoInst *ins;
3799         int idx, dreg;
3800
3801         idx = get_gsharedvt_info_slot (cfg, data, rgctx_type);
3802         /* Load info->entries [idx] */
3803         dreg = alloc_preg (cfg);
3804         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, cfg->gsharedvt_info_var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
3805
3806         return ins;
3807 }
3808
3809 static MonoInst*
3810 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type)
3811 {
3812         return emit_get_gsharedvt_info (cfg, &klass->byval_arg, rgctx_type);
3813 }
3814
3815 /*
3816  * On return the caller must check @klass for load errors.
3817  */
3818 static void
3819 emit_class_init (MonoCompile *cfg, MonoClass *klass)
3820 {
3821         MonoInst *vtable_arg;
3822         int context_used;
3823
3824         context_used = mini_class_check_context_used (cfg, klass);
3825
3826         if (context_used) {
3827                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
3828                                                                                    klass, MONO_RGCTX_INFO_VTABLE);
3829         } else {
3830                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3831
3832                 if (!vtable)
3833                         return;
3834                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
3835         }
3836
3837         if (!COMPILE_LLVM (cfg) && cfg->backend->have_op_generic_class_init) {
3838                 MonoInst *ins;
3839
3840                 /*
3841                  * Using an opcode instead of emitting IR here allows the hiding of the call inside the opcode,
3842                  * so this doesn't have to clobber any regs and it doesn't break basic blocks.
3843                  */
3844                 MONO_INST_NEW (cfg, ins, OP_GENERIC_CLASS_INIT);
3845                 ins->sreg1 = vtable_arg->dreg;
3846                 MONO_ADD_INS (cfg->cbb, ins);
3847         } else {
3848                 static int byte_offset = -1;
3849                 static guint8 bitmask;
3850                 int bits_reg, inited_reg;
3851                 MonoBasicBlock *inited_bb;
3852                 MonoInst *args [16];
3853
3854                 if (byte_offset < 0)
3855                         mono_marshal_find_bitfield_offset (MonoVTable, initialized, &byte_offset, &bitmask);
3856
3857                 bits_reg = alloc_ireg (cfg);
3858                 inited_reg = alloc_ireg (cfg);
3859
3860                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, bits_reg, vtable_arg->dreg, byte_offset);
3861                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, inited_reg, bits_reg, bitmask);
3862
3863                 NEW_BBLOCK (cfg, inited_bb);
3864
3865                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, inited_reg, 0);
3866                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, inited_bb);
3867
3868                 args [0] = vtable_arg;
3869                 mono_emit_jit_icall (cfg, mono_generic_class_init, args);
3870
3871                 MONO_START_BB (cfg, inited_bb);
3872         }
3873 }
3874
3875 static void
3876 emit_seq_point (MonoCompile *cfg, MonoMethod *method, guint8* ip, gboolean intr_loc, gboolean nonempty_stack)
3877 {
3878         MonoInst *ins;
3879
3880         if (cfg->gen_seq_points && cfg->method == method) {
3881                 NEW_SEQ_POINT (cfg, ins, ip - cfg->header->code, intr_loc);
3882                 if (nonempty_stack)
3883                         ins->flags |= MONO_INST_NONEMPTY_STACK;
3884                 MONO_ADD_INS (cfg->cbb, ins);
3885         }
3886 }
3887
3888 static void
3889 save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean null_check)
3890 {
3891         if (mini_get_debug_options ()->better_cast_details) {
3892                 int vtable_reg = alloc_preg (cfg);
3893                 int klass_reg = alloc_preg (cfg);
3894                 MonoBasicBlock *is_null_bb = NULL;
3895                 MonoInst *tls_get;
3896                 int to_klass_reg, context_used;
3897
3898                 if (null_check) {
3899                         NEW_BBLOCK (cfg, is_null_bb);
3900
3901                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3902                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3903                 }
3904
3905                 tls_get = mono_get_jit_tls_intrinsic (cfg);
3906                 if (!tls_get) {
3907                         fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
3908                         exit (1);
3909                 }
3910
3911                 MONO_ADD_INS (cfg->cbb, tls_get);
3912                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3913                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3914
3915                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg);
3916
3917                 context_used = mini_class_check_context_used (cfg, klass);
3918                 if (context_used) {
3919                         MonoInst *class_ins;
3920
3921                         class_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3922                         to_klass_reg = class_ins->dreg;
3923                 } else {
3924                         to_klass_reg = alloc_preg (cfg);
3925                         MONO_EMIT_NEW_CLASSCONST (cfg, to_klass_reg, klass);
3926                 }
3927                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg);
3928
3929                 if (null_check)
3930                         MONO_START_BB (cfg, is_null_bb);
3931         }
3932 }
3933
3934 static void
3935 reset_cast_details (MonoCompile *cfg)
3936 {
3937         /* Reset the variables holding the cast details */
3938         if (mini_get_debug_options ()->better_cast_details) {
3939                 MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
3940
3941                 MONO_ADD_INS (cfg->cbb, tls_get);
3942                 /* It is enough to reset the from field */
3943                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0);
3944         }
3945 }
3946
3947 /*
3948  * On return the caller must check @array_class for load errors
3949  */
3950 static void
3951 mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_class)
3952 {
3953         int vtable_reg = alloc_preg (cfg);
3954         int context_used;
3955
3956         context_used = mini_class_check_context_used (cfg, array_class);
3957
3958         save_cast_details (cfg, array_class, obj->dreg, FALSE);
3959
3960         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3961
3962         if (cfg->opt & MONO_OPT_SHARED) {
3963                 int class_reg = alloc_preg (cfg);
3964                 MonoInst *ins;
3965
3966                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, class_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3967                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, array_class);
3968                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, class_reg, ins->dreg);
3969         } else if (context_used) {
3970                 MonoInst *vtable_ins;
3971
3972                 vtable_ins = emit_get_rgctx_klass (cfg, context_used, array_class, MONO_RGCTX_INFO_VTABLE);
3973                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vtable_ins->dreg);
3974         } else {
3975                 if (cfg->compile_aot) {
3976                         int vt_reg;
3977                         MonoVTable *vtable;
3978
3979                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3980                                 return;
3981                         vt_reg = alloc_preg (cfg);
3982                         MONO_EMIT_NEW_VTABLECONST (cfg, vt_reg, vtable);
3983                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vt_reg);
3984                 } else {
3985                         MonoVTable *vtable;
3986                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3987                                 return;
3988                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vtable);
3989                 }
3990         }
3991         
3992         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException");
3993
3994         reset_cast_details (cfg);
3995 }
3996
3997 /**
3998  * Handles unbox of a Nullable<T>. If context_used is non zero, then shared 
3999  * generic code is generated.
4000  */
4001 static MonoInst*
4002 handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int context_used)
4003 {
4004         MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
4005
4006         if (context_used) {
4007                 MonoInst *rgctx, *addr;
4008
4009                 /* FIXME: What if the class is shared?  We might not
4010                    have to get the address of the method from the
4011                    RGCTX. */
4012                 addr = emit_get_rgctx_method (cfg, context_used, method,
4013                                                                           MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4014                 if (cfg->llvm_only && cfg->gsharedvt) {
4015                         return emit_llvmonly_calli (cfg, mono_method_signature (method), &val, addr);
4016                 } else {
4017                         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
4018
4019                         return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
4020                 }
4021         } else {
4022                 gboolean pass_vtable, pass_mrgctx;
4023                 MonoInst *rgctx_arg = NULL;
4024
4025                 check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
4026                 g_assert (!pass_mrgctx);
4027
4028                 if (pass_vtable) {
4029                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4030
4031                         g_assert (vtable);
4032                         EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
4033                 }
4034
4035                 return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4036         }
4037 }
4038
4039 static MonoInst*
4040 handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_used)
4041 {
4042         MonoInst *add;
4043         int obj_reg;
4044         int vtable_reg = alloc_dreg (cfg ,STACK_PTR);
4045         int klass_reg = alloc_dreg (cfg ,STACK_PTR);
4046         int eclass_reg = alloc_dreg (cfg ,STACK_PTR);
4047         int rank_reg = alloc_dreg (cfg ,STACK_I4);
4048
4049         obj_reg = sp [0]->dreg;
4050         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4051         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
4052
4053         /* FIXME: generics */
4054         g_assert (klass->rank == 0);
4055                         
4056         // Check rank == 0
4057         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, 0);
4058         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4059
4060         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4061         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, element_class));
4062
4063         if (context_used) {
4064                 MonoInst *element_class;
4065
4066                 /* This assertion is from the unboxcast insn */
4067                 g_assert (klass->rank == 0);
4068
4069                 element_class = emit_get_rgctx_klass (cfg, context_used,
4070                                 klass, MONO_RGCTX_INFO_ELEMENT_KLASS);
4071
4072                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, eclass_reg, element_class->dreg);
4073                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4074         } else {
4075                 save_cast_details (cfg, klass->element_class, obj_reg, FALSE);
4076                 mini_emit_class_check (cfg, eclass_reg, klass->element_class);
4077                 reset_cast_details (cfg);
4078         }
4079
4080         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), obj_reg, sizeof (MonoObject));
4081         MONO_ADD_INS (cfg->cbb, add);
4082         add->type = STACK_MP;
4083         add->klass = klass;
4084
4085         return add;
4086 }
4087
4088 static MonoInst*
4089 handle_unbox_gsharedvt (MonoCompile *cfg, MonoClass *klass, MonoInst *obj)
4090 {
4091         MonoInst *addr, *klass_inst, *is_ref, *args[16];
4092         MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4093         MonoInst *ins;
4094         int dreg, addr_reg;
4095
4096         klass_inst = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_KLASS);
4097
4098         /* obj */
4099         args [0] = obj;
4100
4101         /* klass */
4102         args [1] = klass_inst;
4103
4104         /* CASTCLASS */
4105         obj = mono_emit_jit_icall (cfg, mono_object_castclass_unbox, args);
4106
4107         NEW_BBLOCK (cfg, is_ref_bb);
4108         NEW_BBLOCK (cfg, is_nullable_bb);
4109         NEW_BBLOCK (cfg, end_bb);
4110         is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4111         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
4112         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4113
4114         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
4115         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4116
4117         /* This will contain either the address of the unboxed vtype, or an address of the temporary where the ref is stored */
4118         addr_reg = alloc_dreg (cfg, STACK_MP);
4119
4120         /* Non-ref case */
4121         /* UNBOX */
4122         NEW_BIALU_IMM (cfg, addr, OP_ADD_IMM, addr_reg, obj->dreg, sizeof (MonoObject));
4123         MONO_ADD_INS (cfg->cbb, addr);
4124
4125         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4126
4127         /* Ref case */
4128         MONO_START_BB (cfg, is_ref_bb);
4129
4130         /* Save the ref to a temporary */
4131         dreg = alloc_ireg (cfg);
4132         EMIT_NEW_VARLOADA_VREG (cfg, addr, dreg, &klass->byval_arg);
4133         addr->dreg = addr_reg;
4134         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, obj->dreg);
4135         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4136
4137         /* Nullable case */
4138         MONO_START_BB (cfg, is_nullable_bb);
4139
4140         {
4141                 MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX);
4142                 MonoInst *unbox_call;
4143                 MonoMethodSignature *unbox_sig;
4144
4145                 unbox_sig = (MonoMethodSignature *)mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4146                 unbox_sig->ret = &klass->byval_arg;
4147                 unbox_sig->param_count = 1;
4148                 unbox_sig->params [0] = &mono_defaults.object_class->byval_arg;
4149
4150                 if (cfg->llvm_only)
4151                         unbox_call = emit_llvmonly_calli (cfg, unbox_sig, &obj, addr);
4152                 else
4153                         unbox_call = mono_emit_calli (cfg, unbox_sig, &obj, addr, NULL, NULL);
4154
4155                 EMIT_NEW_VARLOADA_VREG (cfg, addr, unbox_call->dreg, &klass->byval_arg);
4156                 addr->dreg = addr_reg;
4157         }
4158
4159         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4160
4161         /* End */
4162         MONO_START_BB (cfg, end_bb);
4163
4164         /* LDOBJ */
4165         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr_reg, 0);
4166
4167         return ins;
4168 }
4169
4170 /*
4171  * Returns NULL and set the cfg exception on error.
4172  */
4173 static MonoInst*
4174 handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_used)
4175 {
4176         MonoInst *iargs [2];
4177         void *alloc_ftn;
4178
4179         if (context_used) {
4180                 MonoInst *data;
4181                 MonoRgctxInfoType rgctx_info;
4182                 MonoInst *iargs [2];
4183                 gboolean known_instance_size = !mini_is_gsharedvt_klass (klass);
4184
4185                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (klass, for_box, known_instance_size);
4186
4187                 if (cfg->opt & MONO_OPT_SHARED)
4188                         rgctx_info = MONO_RGCTX_INFO_KLASS;
4189                 else
4190                         rgctx_info = MONO_RGCTX_INFO_VTABLE;
4191                 data = emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
4192
4193                 if (cfg->opt & MONO_OPT_SHARED) {
4194                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4195                         iargs [1] = data;
4196                         alloc_ftn = mono_object_new;
4197                 } else {
4198                         iargs [0] = data;
4199                         alloc_ftn = ves_icall_object_new_specific;
4200                 }
4201
4202                 if (managed_alloc && !(cfg->opt & MONO_OPT_SHARED)) {
4203                         if (known_instance_size) {
4204                                 int size = mono_class_instance_size (klass);
4205                                 if (size < sizeof (MonoObject))
4206                                         g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4207
4208                                 EMIT_NEW_ICONST (cfg, iargs [1], mono_gc_get_aligned_size_for_allocator (size));
4209                         }
4210                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4211                 }
4212
4213                 return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4214         }
4215
4216         if (cfg->opt & MONO_OPT_SHARED) {
4217                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4218                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
4219
4220                 alloc_ftn = mono_object_new;
4221         } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !klass->generic_class) {
4222                 /* This happens often in argument checking code, eg. throw new FooException... */
4223                 /* Avoid relocations and save some space by calling a helper function specialized to mscorlib */
4224                 EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
4225                 return mono_emit_jit_icall (cfg, mono_helper_newobj_mscorlib, iargs);
4226         } else {
4227                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
4228                 MonoMethod *managed_alloc = NULL;
4229                 gboolean pass_lw;
4230
4231                 if (!vtable) {
4232                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4233                         cfg->exception_ptr = klass;
4234                         return NULL;
4235                 }
4236
4237                 managed_alloc = mono_gc_get_managed_allocator (klass, for_box, TRUE);
4238
4239                 if (managed_alloc) {
4240                         int size = mono_class_instance_size (klass);
4241                         if (size < sizeof (MonoObject))
4242                                 g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4243
4244                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4245                         EMIT_NEW_ICONST (cfg, iargs [1], mono_gc_get_aligned_size_for_allocator (size));
4246                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4247                 }
4248                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
4249                 if (pass_lw) {
4250                         guint32 lw = vtable->klass->instance_size;
4251                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
4252                         EMIT_NEW_ICONST (cfg, iargs [0], lw);
4253                         EMIT_NEW_VTABLECONST (cfg, iargs [1], vtable);
4254                 }
4255                 else {
4256                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4257                 }
4258         }
4259
4260         return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4261 }
4262         
4263 /*
4264  * Returns NULL and set the cfg exception on error.
4265  */     
4266 static MonoInst*
4267 handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used)
4268 {
4269         MonoInst *alloc, *ins;
4270
4271         if (mono_class_is_nullable (klass)) {
4272                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
4273
4274                 if (context_used) {
4275                         if (cfg->llvm_only && cfg->gsharedvt) {
4276                                 MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4277                                                                                                                 MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4278                                 return emit_llvmonly_calli (cfg, mono_method_signature (method), &val, addr);
4279                         } else {
4280                                 /* FIXME: What if the class is shared?  We might not
4281                                    have to get the method address from the RGCTX. */
4282                                 MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4283                                                                                                                 MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4284                                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
4285
4286                                 return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
4287                         }
4288                 } else {
4289                         gboolean pass_vtable, pass_mrgctx;
4290                         MonoInst *rgctx_arg = NULL;
4291
4292                         check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
4293                         g_assert (!pass_mrgctx);
4294
4295                         if (pass_vtable) {
4296                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4297
4298                                 g_assert (vtable);
4299                                 EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
4300                         }
4301
4302                         return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4303                 }
4304         }
4305
4306         if (mini_is_gsharedvt_klass (klass)) {
4307                 MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4308                 MonoInst *res, *is_ref, *src_var, *addr;
4309                 int dreg;
4310
4311                 dreg = alloc_ireg (cfg);
4312
4313                 NEW_BBLOCK (cfg, is_ref_bb);
4314                 NEW_BBLOCK (cfg, is_nullable_bb);
4315                 NEW_BBLOCK (cfg, end_bb);
4316                 is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4317                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
4318                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4319
4320                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
4321                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4322
4323                 /* Non-ref case */
4324                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4325                 if (!alloc)
4326                         return NULL;
4327                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4328                 ins->opcode = OP_STOREV_MEMBASE;
4329
4330                 EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, alloc->dreg);
4331                 res->type = STACK_OBJ;
4332                 res->klass = klass;
4333                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4334                 
4335                 /* Ref case */
4336                 MONO_START_BB (cfg, is_ref_bb);
4337
4338                 /* val is a vtype, so has to load the value manually */
4339                 src_var = get_vreg_to_inst (cfg, val->dreg);
4340                 if (!src_var)
4341                         src_var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, val->dreg);
4342                 EMIT_NEW_VARLOADA (cfg, addr, src_var, src_var->inst_vtype);
4343                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, addr->dreg, 0);
4344                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4345
4346                 /* Nullable case */
4347                 MONO_START_BB (cfg, is_nullable_bb);
4348
4349                 {
4350                         MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass,
4351                                                                                                         MONO_RGCTX_INFO_NULLABLE_CLASS_BOX);
4352                         MonoInst *box_call;
4353                         MonoMethodSignature *box_sig;
4354
4355                         /*
4356                          * klass is Nullable<T>, need to call Nullable<T>.Box () using a gsharedvt signature, but we cannot
4357                          * construct that method at JIT time, so have to do things by hand.
4358                          */
4359                         box_sig = (MonoMethodSignature *)mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4360                         box_sig->ret = &mono_defaults.object_class->byval_arg;
4361                         box_sig->param_count = 1;
4362                         box_sig->params [0] = &klass->byval_arg;
4363
4364                         if (cfg->llvm_only)
4365                                 box_call = emit_llvmonly_calli (cfg, box_sig, &val, addr);
4366                         else
4367                                 box_call = mono_emit_calli (cfg, box_sig, &val, addr, NULL, NULL);
4368                         EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, box_call->dreg);
4369                         res->type = STACK_OBJ;
4370                         res->klass = klass;
4371                 }
4372
4373                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4374
4375                 MONO_START_BB (cfg, end_bb);
4376
4377                 return res;
4378         } else {
4379                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4380                 if (!alloc)
4381                         return NULL;
4382
4383                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4384                 return alloc;
4385         }
4386 }
4387
4388 static gboolean
4389 mini_class_has_reference_variant_generic_argument (MonoCompile *cfg, MonoClass *klass, int context_used)
4390 {
4391         int i;
4392         MonoGenericContainer *container;
4393         MonoGenericInst *ginst;
4394
4395         if (klass->generic_class) {
4396                 container = klass->generic_class->container_class->generic_container;
4397                 ginst = klass->generic_class->context.class_inst;
4398         } else if (klass->generic_container && context_used) {
4399                 container = klass->generic_container;
4400                 ginst = container->context.class_inst;
4401         } else {
4402                 return FALSE;
4403         }
4404
4405         for (i = 0; i < container->type_argc; ++i) {
4406                 MonoType *type;
4407                 if (!(mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT)))
4408                         continue;
4409                 type = ginst->type_argv [i];
4410                 if (mini_type_is_reference (type))
4411                         return TRUE;
4412         }
4413         return FALSE;
4414 }
4415
4416 static GHashTable* direct_icall_type_hash;
4417
4418 static gboolean
4419 icall_is_direct_callable (MonoCompile *cfg, MonoMethod *cmethod)
4420 {
4421         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
4422         if (!direct_icalls_enabled (cfg))
4423                 return FALSE;
4424
4425         /*
4426          * An icall is directly callable if it doesn't directly or indirectly call mono_raise_exception ().
4427          * Whitelist a few icalls for now.
4428          */
4429         if (!direct_icall_type_hash) {
4430                 GHashTable *h = g_hash_table_new (g_str_hash, g_str_equal);
4431
4432                 g_hash_table_insert (h, (char*)"Decimal", GUINT_TO_POINTER (1));
4433                 g_hash_table_insert (h, (char*)"Number", GUINT_TO_POINTER (1));
4434                 g_hash_table_insert (h, (char*)"Buffer", GUINT_TO_POINTER (1));
4435                 g_hash_table_insert (h, (char*)"Monitor", GUINT_TO_POINTER (1));
4436                 mono_memory_barrier ();
4437                 direct_icall_type_hash = h;
4438         }
4439
4440         if (cmethod->klass == mono_defaults.math_class)
4441                 return TRUE;
4442         /* No locking needed */
4443         if (cmethod->klass->image == mono_defaults.corlib && g_hash_table_lookup (direct_icall_type_hash, cmethod->klass->name))
4444                 return TRUE;
4445         return FALSE;
4446 }
4447
4448 /* Return whenever METHOD calls Assembly.GetCallingAssembly () */
4449 // FIXME: It would be better to generalize this using some kind of method attribute
4450 // or automatic detection
4451 static gboolean
4452 method_needs_calling_assembly (MonoMethod *method)
4453 {
4454         MonoClass *klass = method->klass;
4455
4456         if (klass->image != mono_defaults.corlib)
4457                 return FALSE;
4458         if (!strcmp (klass->name_space, "System") && !strcmp (klass->name, "Activator") &&
4459                 !strcmp (method->name, "CreateInstance"))
4460                 return TRUE;
4461         return FALSE;
4462 }
4463
4464 #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)
4465
4466 static MonoInst*
4467 emit_castclass_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args)
4468 {
4469         MonoMethod *mono_castclass;
4470         MonoInst *res;
4471
4472         mono_castclass = mono_marshal_get_castclass_with_cache ();
4473
4474         save_cast_details (cfg, klass, args [0]->dreg, TRUE);
4475         res = mono_emit_method_call (cfg, mono_castclass, args, NULL);
4476         reset_cast_details (cfg);
4477
4478         return res;
4479 }
4480
4481 static int
4482 get_castclass_cache_idx (MonoCompile *cfg)
4483 {
4484         /* Each CASTCLASS_CACHE patch needs a unique index which identifies the call site */
4485         cfg->castclass_cache_index ++;
4486         return (cfg->method_index << 16) | cfg->castclass_cache_index;
4487 }
4488
4489 static MonoInst*
4490 emit_castclass_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass *klass)
4491 {
4492         MonoInst *args [3];
4493         int idx;
4494
4495         /* obj */
4496         args [0] = obj;
4497
4498         /* klass */
4499         EMIT_NEW_CLASSCONST (cfg, args [1], klass);
4500
4501         /* inline cache*/
4502         idx = get_castclass_cache_idx (cfg);
4503         args [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
4504
4505         /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
4506         return emit_castclass_with_cache (cfg, klass, args);
4507 }
4508
4509 /*
4510  * Returns NULL and set the cfg exception on error.
4511  */
4512 static MonoInst*
4513 handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, guint8 *ip, int *inline_costs)
4514 {
4515         MonoBasicBlock *is_null_bb;
4516         int obj_reg = src->dreg;
4517         int vtable_reg = alloc_preg (cfg);
4518         int context_used;
4519         MonoInst *klass_inst = NULL, *res;
4520
4521         context_used = mini_class_check_context_used (cfg, klass);
4522
4523         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
4524                 res = emit_castclass_with_cache_nonshared (cfg, src, klass);
4525                 (*inline_costs) += 2;
4526                 return res;
4527         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
4528                 MonoMethod *mono_castclass;
4529                 MonoInst *iargs [1];
4530                 int costs;
4531
4532                 mono_castclass = mono_marshal_get_castclass (klass); 
4533                 iargs [0] = src;
4534                                 
4535                 save_cast_details (cfg, klass, src->dreg, TRUE);
4536                 costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
4537                                                            iargs, ip, cfg->real_offset, TRUE);
4538                 reset_cast_details (cfg);
4539                 CHECK_CFG_EXCEPTION;
4540                 g_assert (costs > 0);
4541                                 
4542                 cfg->real_offset += 5;
4543
4544                 (*inline_costs) += costs;
4545
4546                 return src;
4547         }
4548
4549         if (context_used) {
4550                 MonoInst *args [3];
4551
4552                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4553                         MonoInst *cache_ins;
4554
4555                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4556
4557                         /* obj */
4558                         args [0] = src;
4559
4560                         /* klass - it's the second element of the cache entry*/
4561                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4562
4563                         /* cache */
4564                         args [2] = cache_ins;
4565
4566                         return emit_castclass_with_cache (cfg, klass, args);
4567                 }
4568
4569                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4570         }
4571
4572         NEW_BBLOCK (cfg, is_null_bb);
4573
4574         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4575         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
4576
4577         save_cast_details (cfg, klass, obj_reg, FALSE);
4578
4579         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4580                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4581                 mini_emit_iface_cast (cfg, vtable_reg, klass, NULL, NULL);
4582         } else {
4583                 int klass_reg = alloc_preg (cfg);
4584
4585                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4586
4587                 if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4588                         /* the remoting code is broken, access the class for now */
4589                         if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4590                                 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4591                                 if (!vt) {
4592                                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4593                                         cfg->exception_ptr = klass;
4594                                         return NULL;
4595                                 }
4596                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4597                         } else {
4598                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4599                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4600                         }
4601                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4602                 } else {
4603                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4604                         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, klass_inst, is_null_bb);
4605                 }
4606         }
4607
4608         MONO_START_BB (cfg, is_null_bb);
4609
4610         reset_cast_details (cfg);
4611
4612         return src;
4613
4614 exception_exit:
4615         return NULL;
4616 }
4617
4618 /*
4619  * Returns NULL and set the cfg exception on error.
4620  */
4621 static MonoInst*
4622 handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
4623 {
4624         MonoInst *ins;
4625         MonoBasicBlock *is_null_bb, *false_bb, *end_bb;
4626         int obj_reg = src->dreg;
4627         int vtable_reg = alloc_preg (cfg);
4628         int res_reg = alloc_ireg_ref (cfg);
4629         MonoInst *klass_inst = NULL;
4630
4631         if (context_used) {
4632                 MonoInst *args [3];
4633
4634                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4635                         MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
4636                         MonoInst *cache_ins;
4637
4638                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4639
4640                         /* obj */
4641                         args [0] = src;
4642
4643                         /* klass - it's the second element of the cache entry*/
4644                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4645
4646                         /* cache */
4647                         args [2] = cache_ins;
4648
4649                         return mono_emit_method_call (cfg, mono_isinst, args, NULL);
4650                 }
4651
4652                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4653         }
4654
4655         NEW_BBLOCK (cfg, is_null_bb);
4656         NEW_BBLOCK (cfg, false_bb);
4657         NEW_BBLOCK (cfg, end_bb);
4658
4659         /* Do the assignment at the beginning, so the other assignment can be if converted */
4660         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, res_reg, obj_reg);
4661         ins->type = STACK_OBJ;
4662         ins->klass = klass;
4663
4664         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4665         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_null_bb);
4666
4667         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4668
4669         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4670                 g_assert (!context_used);
4671                 /* the is_null_bb target simply copies the input register to the output */
4672                 mini_emit_iface_cast (cfg, vtable_reg, klass, false_bb, is_null_bb);
4673         } else {
4674                 int klass_reg = alloc_preg (cfg);
4675
4676                 if (klass->rank) {
4677                         int rank_reg = alloc_preg (cfg);
4678                         int eclass_reg = alloc_preg (cfg);
4679
4680                         g_assert (!context_used);
4681                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
4682                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
4683                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4684                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4685                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
4686                         if (klass->cast_class == mono_defaults.object_class) {
4687                                 int parent_reg = alloc_preg (cfg);
4688                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
4689                                 mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, is_null_bb);
4690                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4691                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4692                         } else if (klass->cast_class == mono_defaults.enum_class->parent) {
4693                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, is_null_bb);
4694                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);                          
4695                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4696                         } else if (klass->cast_class == mono_defaults.enum_class) {
4697                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4698                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4699                         } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
4700                                 mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4701                         } else {
4702                                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY)) {
4703                                         /* Check that the object is a vector too */
4704                                         int bounds_reg = alloc_preg (cfg);
4705                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
4706                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
4707                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4708                                 }
4709
4710                                 /* the is_null_bb target simply copies the input register to the output */
4711                                 mini_emit_isninst_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4712                         }
4713                 } else if (mono_class_is_nullable (klass)) {
4714                         g_assert (!context_used);
4715                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4716                         /* the is_null_bb target simply copies the input register to the output */
4717                         mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb);
4718                 } else {
4719                         if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4720                                 g_assert (!context_used);
4721                                 /* the remoting code is broken, access the class for now */
4722                                 if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4723                                         MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4724                                         if (!vt) {
4725                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4726                                                 cfg->exception_ptr = klass;
4727                                                 return NULL;
4728                                         }
4729                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4730                                 } else {
4731                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4732                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4733                                 }
4734                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4735                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
4736                         } else {
4737                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4738                                 /* the is_null_bb target simply copies the input register to the output */
4739                                 mini_emit_isninst_cast_inst (cfg, klass_reg, klass, klass_inst, false_bb, is_null_bb);
4740                         }
4741                 }
4742         }
4743
4744         MONO_START_BB (cfg, false_bb);
4745
4746         MONO_EMIT_NEW_PCONST (cfg, res_reg, 0);
4747         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4748
4749         MONO_START_BB (cfg, is_null_bb);
4750
4751         MONO_START_BB (cfg, end_bb);
4752
4753         return ins;
4754 }
4755
4756 static MonoInst*
4757 handle_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4758 {
4759         /* This opcode takes as input an object reference and a class, and returns:
4760         0) if the object is an instance of the class,
4761         1) if the object is not instance of the class,
4762         2) if the object is a proxy whose type cannot be determined */
4763
4764         MonoInst *ins;
4765 #ifndef DISABLE_REMOTING
4766         MonoBasicBlock *true_bb, *false_bb, *false2_bb, *end_bb, *no_proxy_bb, *interface_fail_bb;
4767 #else
4768         MonoBasicBlock *true_bb, *false_bb, *end_bb;
4769 #endif
4770         int obj_reg = src->dreg;
4771         int dreg = alloc_ireg (cfg);
4772         int tmp_reg;
4773 #ifndef DISABLE_REMOTING
4774         int klass_reg = alloc_preg (cfg);
4775 #endif
4776
4777         NEW_BBLOCK (cfg, true_bb);
4778         NEW_BBLOCK (cfg, false_bb);
4779         NEW_BBLOCK (cfg, end_bb);
4780 #ifndef DISABLE_REMOTING
4781         NEW_BBLOCK (cfg, false2_bb);
4782         NEW_BBLOCK (cfg, no_proxy_bb);
4783 #endif
4784
4785         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4786         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
4787
4788         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4789 #ifndef DISABLE_REMOTING
4790                 NEW_BBLOCK (cfg, interface_fail_bb);
4791 #endif
4792
4793                 tmp_reg = alloc_preg (cfg);
4794                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4795 #ifndef DISABLE_REMOTING
4796                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, true_bb);
4797                 MONO_START_BB (cfg, interface_fail_bb);
4798                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4799                 
4800                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, false_bb);
4801
4802                 tmp_reg = alloc_preg (cfg);
4803                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4804                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4805                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false2_bb);                
4806 #else
4807                 mini_emit_iface_cast (cfg, tmp_reg, klass, false_bb, true_bb);
4808 #endif
4809         } else {
4810 #ifndef DISABLE_REMOTING
4811                 tmp_reg = alloc_preg (cfg);
4812                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4813                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4814
4815                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4816                 tmp_reg = alloc_preg (cfg);
4817                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4818                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4819
4820                 tmp_reg = alloc_preg (cfg);             
4821                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4822                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4823                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4824                 
4825                 mini_emit_isninst_cast (cfg, klass_reg, klass, false2_bb, true_bb);
4826                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false2_bb);
4827
4828                 MONO_START_BB (cfg, no_proxy_bb);
4829
4830                 mini_emit_isninst_cast (cfg, klass_reg, klass, false_bb, true_bb);
4831 #else
4832                 g_error ("transparent proxy support is disabled while trying to JIT code that uses it");
4833 #endif
4834         }
4835
4836         MONO_START_BB (cfg, false_bb);
4837
4838         MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4839         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4840
4841 #ifndef DISABLE_REMOTING
4842         MONO_START_BB (cfg, false2_bb);
4843
4844         MONO_EMIT_NEW_ICONST (cfg, dreg, 2);
4845         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4846 #endif
4847
4848         MONO_START_BB (cfg, true_bb);
4849
4850         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4851
4852         MONO_START_BB (cfg, end_bb);
4853
4854         /* FIXME: */
4855         MONO_INST_NEW (cfg, ins, OP_ICONST);
4856         ins->dreg = dreg;
4857         ins->type = STACK_I4;
4858
4859         return ins;
4860 }
4861
4862 static MonoInst*
4863 handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4864 {
4865         /* This opcode takes as input an object reference and a class, and returns:
4866         0) if the object is an instance of the class,
4867         1) if the object is a proxy whose type cannot be determined
4868         an InvalidCastException exception is thrown otherwhise*/
4869         
4870         MonoInst *ins;
4871 #ifndef DISABLE_REMOTING
4872         MonoBasicBlock *end_bb, *ok_result_bb, *no_proxy_bb, *interface_fail_bb, *fail_1_bb;
4873 #else
4874         MonoBasicBlock *ok_result_bb;
4875 #endif
4876         int obj_reg = src->dreg;
4877         int dreg = alloc_ireg (cfg);
4878         int tmp_reg = alloc_preg (cfg);
4879
4880 #ifndef DISABLE_REMOTING
4881         int klass_reg = alloc_preg (cfg);
4882         NEW_BBLOCK (cfg, end_bb);
4883 #endif
4884
4885         NEW_BBLOCK (cfg, ok_result_bb);
4886
4887         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4888         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, ok_result_bb);
4889
4890         save_cast_details (cfg, klass, obj_reg, FALSE);
4891
4892         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4893 #ifndef DISABLE_REMOTING
4894                 NEW_BBLOCK (cfg, interface_fail_bb);
4895         
4896                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4897                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, ok_result_bb);
4898                 MONO_START_BB (cfg, interface_fail_bb);
4899                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4900
4901                 mini_emit_class_check (cfg, klass_reg, mono_defaults.transparent_proxy_class);
4902
4903                 tmp_reg = alloc_preg (cfg);             
4904                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4905                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4906                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
4907                 
4908                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4909                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4910 #else
4911                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4912                 mini_emit_iface_cast (cfg, tmp_reg, klass, NULL, NULL);
4913                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, ok_result_bb);
4914 #endif
4915         } else {
4916 #ifndef DISABLE_REMOTING
4917                 NEW_BBLOCK (cfg, no_proxy_bb);
4918
4919                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4920                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4921                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4922
4923                 tmp_reg = alloc_preg (cfg);
4924                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4925                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4926
4927                 tmp_reg = alloc_preg (cfg);
4928                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4929                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4930                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4931
4932                 NEW_BBLOCK (cfg, fail_1_bb);
4933                 
4934                 mini_emit_isninst_cast (cfg, klass_reg, klass, fail_1_bb, ok_result_bb);
4935
4936                 MONO_START_BB (cfg, fail_1_bb);
4937
4938                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4939                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4940
4941                 MONO_START_BB (cfg, no_proxy_bb);
4942
4943                 mini_emit_castclass (cfg, obj_reg, klass_reg, klass, ok_result_bb);
4944 #else
4945                 g_error ("Transparent proxy support is disabled while trying to JIT code that uses it");
4946 #endif
4947         }
4948
4949         MONO_START_BB (cfg, ok_result_bb);
4950
4951         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4952
4953 #ifndef DISABLE_REMOTING
4954         MONO_START_BB (cfg, end_bb);
4955 #endif
4956
4957         /* FIXME: */
4958         MONO_INST_NEW (cfg, ins, OP_ICONST);
4959         ins->dreg = dreg;
4960         ins->type = STACK_I4;
4961
4962         return ins;
4963 }
4964
4965 static G_GNUC_UNUSED MonoInst*
4966 handle_enum_has_flag (MonoCompile *cfg, MonoClass *klass, MonoInst *enum_this, MonoInst *enum_flag)
4967 {
4968         MonoType *enum_type = mono_type_get_underlying_type (&klass->byval_arg);
4969         guint32 load_opc = mono_type_to_load_membase (cfg, enum_type);
4970         gboolean is_i4;
4971
4972         switch (enum_type->type) {
4973         case MONO_TYPE_I8:
4974         case MONO_TYPE_U8:
4975 #if SIZEOF_REGISTER == 8
4976         case MONO_TYPE_I:
4977         case MONO_TYPE_U:
4978 #endif
4979                 is_i4 = FALSE;
4980                 break;
4981         default:
4982                 is_i4 = TRUE;
4983                 break;
4984         }
4985
4986         {
4987                 MonoInst *load, *and_, *cmp, *ceq;
4988                 int enum_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4989                 int and_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4990                 int dest_reg = alloc_ireg (cfg);
4991
4992                 EMIT_NEW_LOAD_MEMBASE (cfg, load, load_opc, enum_reg, enum_this->dreg, 0);
4993                 EMIT_NEW_BIALU (cfg, and_, is_i4 ? OP_IAND : OP_LAND, and_reg, enum_reg, enum_flag->dreg);
4994                 EMIT_NEW_BIALU (cfg, cmp, is_i4 ? OP_ICOMPARE : OP_LCOMPARE, -1, and_reg, enum_flag->dreg);
4995                 EMIT_NEW_UNALU (cfg, ceq, is_i4 ? OP_ICEQ : OP_LCEQ, dest_reg, -1);
4996
4997                 ceq->type = STACK_I4;
4998
4999                 if (!is_i4) {
5000                         load = mono_decompose_opcode (cfg, load);
5001                         and_ = mono_decompose_opcode (cfg, and_);
5002                         cmp = mono_decompose_opcode (cfg, cmp);
5003                         ceq = mono_decompose_opcode (cfg, ceq);
5004                 }
5005
5006                 return ceq;
5007         }
5008 }
5009
5010 /*
5011  * Returns NULL and set the cfg exception on error.
5012  */
5013 static G_GNUC_UNUSED MonoInst*
5014 handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method, int context_used, gboolean virtual_)
5015 {
5016         MonoInst *ptr;
5017         int dreg;
5018         gpointer trampoline;
5019         MonoInst *obj, *method_ins, *tramp_ins;
5020         MonoDomain *domain;
5021         guint8 **code_slot;
5022
5023         if (virtual_ && !cfg->llvm_only) {
5024                 MonoMethod *invoke = mono_get_delegate_invoke (klass);
5025                 g_assert (invoke);
5026
5027                 if (!mono_get_delegate_virtual_invoke_impl (mono_method_signature (invoke), context_used ? NULL : method))
5028                         return NULL;
5029         }
5030
5031         obj = handle_alloc (cfg, klass, FALSE, mono_class_check_context_used (klass));
5032         if (!obj)
5033                 return NULL;
5034
5035         if (cfg->llvm_only) {
5036                 MonoInst *args [16];
5037
5038                 /*
5039                  * If the method to be called needs an rgctx, we can't fall back to mono_delegate_ctor (), since it might receive
5040                  * the address of a gshared method. So use a JIT icall.
5041                  * FIXME: Optimize this.
5042                  */
5043                 args [0] = obj;
5044                 args [1] = target;
5045                 args [2] = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
5046                 mono_emit_jit_icall (cfg, virtual_ ? mono_llvmonly_init_delegate_virtual : mono_llvmonly_init_delegate, args);
5047
5048                 return obj;
5049         }
5050
5051         /* Inline the contents of mono_delegate_ctor */
5052
5053         /* Set target field */
5054         /* Optimize away setting of NULL target */
5055         if (!(target->opcode == OP_PCONST && target->inst_p0 == 0)) {
5056                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
5057                 if (cfg->gen_write_barriers) {
5058                         dreg = alloc_preg (cfg);
5059                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target));
5060                         emit_write_barrier (cfg, ptr, target);
5061                 }
5062         }
5063
5064         /* Set method field */
5065         method_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
5066         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg);
5067
5068         /* 
5069          * To avoid looking up the compiled code belonging to the target method
5070          * in mono_delegate_trampoline (), we allocate a per-domain memory slot to
5071          * store it, and we fill it after the method has been compiled.
5072          */
5073         if (!method->dynamic && !(cfg->opt & MONO_OPT_SHARED)) {
5074                 MonoInst *code_slot_ins;
5075
5076                 if (context_used) {
5077                         code_slot_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD_DELEGATE_CODE);
5078                 } else {
5079                         domain = mono_domain_get ();
5080                         mono_domain_lock (domain);
5081                         if (!domain_jit_info (domain)->method_code_hash)
5082                                 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
5083                         code_slot = (guint8 **)g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, method);
5084                         if (!code_slot) {
5085                                 code_slot = (guint8 **)mono_domain_alloc0 (domain, sizeof (gpointer));
5086                                 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, method, code_slot);
5087                         }
5088                         mono_domain_unlock (domain);
5089
5090                         code_slot_ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHOD_CODE_SLOT, method);
5091                 }
5092                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);                
5093         }
5094
5095         if (cfg->compile_aot) {
5096                 MonoDelegateClassMethodPair *del_tramp;
5097
5098                 del_tramp = (MonoDelegateClassMethodPair *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoDelegateClassMethodPair));
5099                 del_tramp->klass = klass;
5100                 del_tramp->method = context_used ? NULL : method;
5101                 del_tramp->is_virtual = virtual_;
5102                 EMIT_NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_DELEGATE_TRAMPOLINE, del_tramp);
5103         } else {
5104                 if (virtual_)
5105                         trampoline = mono_create_delegate_virtual_trampoline (cfg->domain, klass, context_used ? NULL : method);
5106                 else
5107                         trampoline = mono_create_delegate_trampoline_info (cfg->domain, klass, context_used ? NULL : method);
5108                 EMIT_NEW_PCONST (cfg, tramp_ins, trampoline);
5109         }
5110
5111         /* Set invoke_impl field */
5112         if (virtual_) {
5113                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), tramp_ins->dreg);
5114         } else {
5115                 dreg = alloc_preg (cfg);
5116                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, invoke_impl));
5117                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), dreg);
5118
5119                 dreg = alloc_preg (cfg);
5120                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, method_ptr));
5121                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr), dreg);
5122         }
5123
5124         dreg = alloc_preg (cfg);
5125         MONO_EMIT_NEW_ICONST (cfg, dreg, virtual_ ? 1 : 0);
5126         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_is_virtual), dreg);
5127
5128         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
5129
5130         return obj;
5131 }
5132
5133 static MonoInst*
5134 handle_array_new (MonoCompile *cfg, int rank, MonoInst **sp, unsigned char *ip)
5135 {
5136         MonoJitICallInfo *info;
5137
5138         /* Need to register the icall so it gets an icall wrapper */
5139         info = mono_get_array_new_va_icall (rank);
5140
5141         cfg->flags |= MONO_CFG_HAS_VARARGS;
5142
5143         /* mono_array_new_va () needs a vararg calling convention */
5144         cfg->exception_message = g_strdup ("array-new");
5145         cfg->disable_llvm = TRUE;
5146
5147         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
5148         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, sp);
5149 }
5150
5151 /*
5152  * handle_constrained_gsharedvt_call:
5153  *
5154  *   Handle constrained calls where the receiver is a gsharedvt type.
5155  * Return the instruction representing the call. Set the cfg exception on failure.
5156  */
5157 static MonoInst*
5158 handle_constrained_gsharedvt_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp, MonoClass *constrained_class,
5159                                                                    gboolean *ref_emit_widen)
5160 {
5161         MonoInst *ins = NULL;
5162         gboolean emit_widen = *ref_emit_widen;
5163
5164         /*
5165          * Constrained calls need to behave differently at runtime dependending on whenever the receiver is instantiated as ref type or as a vtype.
5166          * 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
5167          * pack the arguments into an array, and do the rest of the work in in an icall.
5168          */
5169         if (((cmethod->klass == mono_defaults.object_class) || (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) &&
5170                 (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)) &&
5171                 (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]))))) {
5172                 MonoInst *args [16];
5173
5174                 /*
5175                  * This case handles calls to
5176                  * - object:ToString()/Equals()/GetHashCode(),
5177                  * - System.IComparable<T>:CompareTo()
5178                  * - System.IEquatable<T>:Equals ()
5179                  * plus some simple interface calls enough to support AsyncTaskMethodBuilder.
5180                  */
5181
5182                 args [0] = sp [0];
5183                 if (mono_method_check_context_used (cmethod))
5184                         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cmethod), cmethod, MONO_RGCTX_INFO_METHOD);
5185                 else
5186                         EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
5187                 args [2] = emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_class), constrained_class, MONO_RGCTX_INFO_KLASS);
5188
5189                 /* !fsig->hasthis is for the wrapper for the Object.GetType () icall */
5190                 if (fsig->hasthis && fsig->param_count) {
5191                         /* Pass the arguments using a localloc-ed array using the format expected by runtime_invoke () */
5192                         MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
5193                         ins->dreg = alloc_preg (cfg);
5194                         ins->inst_imm = fsig->param_count * sizeof (mgreg_t);
5195                         MONO_ADD_INS (cfg->cbb, ins);
5196                         args [4] = ins;
5197
5198                         if (mini_is_gsharedvt_type (fsig->params [0])) {
5199                                 int addr_reg, deref_arg_reg;
5200
5201                                 ins = emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type (fsig->params [0]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
5202                                 deref_arg_reg = alloc_preg (cfg);
5203                                 /* deref_arg = BOX_TYPE != MONO_GSHAREDVT_BOX_TYPE_VTYPE */
5204                                 EMIT_NEW_BIALU_IMM (cfg, args [3], OP_ISUB_IMM, deref_arg_reg, ins->dreg, 1);
5205
5206                                 EMIT_NEW_VARLOADA_VREG (cfg, ins, sp [1]->dreg, fsig->params [0]);
5207                                 addr_reg = ins->dreg;
5208                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, addr_reg);
5209                         } else {
5210                                 EMIT_NEW_ICONST (cfg, args [3], 0);
5211                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, sp [1]->dreg);
5212                         }
5213                 } else {
5214                         EMIT_NEW_ICONST (cfg, args [3], 0);
5215                         EMIT_NEW_ICONST (cfg, args [4], 0);
5216                 }
5217                 ins = mono_emit_jit_icall (cfg, mono_gsharedvt_constrained_call, args);
5218                 emit_widen = FALSE;
5219
5220                 if (mini_is_gsharedvt_type (fsig->ret)) {
5221                         ins = handle_unbox_gsharedvt (cfg, mono_class_from_mono_type (fsig->ret), ins);
5222                 } else if (MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret)) {
5223                         MonoInst *add;
5224
5225                         /* Unbox */
5226                         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), ins->dreg, sizeof (MonoObject));
5227                         MONO_ADD_INS (cfg->cbb, add);
5228                         /* Load value */
5229                         NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, add->dreg, 0);
5230                         MONO_ADD_INS (cfg->cbb, ins);
5231                         /* ins represents the call result */
5232                 }
5233         } else {
5234                 GSHAREDVT_FAILURE (CEE_CALLVIRT);
5235         }
5236
5237         *ref_emit_widen = emit_widen;
5238
5239         return ins;
5240
5241  exception_exit:
5242         return NULL;
5243 }
5244
5245 static void
5246 mono_emit_load_got_addr (MonoCompile *cfg)
5247 {
5248         MonoInst *getaddr, *dummy_use;
5249
5250         if (!cfg->got_var || cfg->got_var_allocated)
5251                 return;
5252
5253         MONO_INST_NEW (cfg, getaddr, OP_LOAD_GOTADDR);
5254         getaddr->cil_code = cfg->header->code;
5255         getaddr->dreg = cfg->got_var->dreg;
5256
5257         /* Add it to the start of the first bblock */
5258         if (cfg->bb_entry->code) {
5259                 getaddr->next = cfg->bb_entry->code;
5260                 cfg->bb_entry->code = getaddr;
5261         }
5262         else
5263                 MONO_ADD_INS (cfg->bb_entry, getaddr);
5264
5265         cfg->got_var_allocated = TRUE;
5266
5267         /* 
5268          * Add a dummy use to keep the got_var alive, since real uses might
5269          * only be generated by the back ends.
5270          * Add it to end_bblock, so the variable's lifetime covers the whole
5271          * method.
5272          * It would be better to make the usage of the got var explicit in all
5273          * cases when the backend needs it (i.e. calls, throw etc.), so this
5274          * wouldn't be needed.
5275          */
5276         NEW_DUMMY_USE (cfg, dummy_use, cfg->got_var);
5277         MONO_ADD_INS (cfg->bb_exit, dummy_use);
5278 }
5279
5280 static int inline_limit;
5281 static gboolean inline_limit_inited;
5282
5283 static gboolean
5284 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
5285 {
5286         MonoMethodHeaderSummary header;
5287         MonoVTable *vtable;
5288 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5289         MonoMethodSignature *sig = mono_method_signature (method);
5290         int i;
5291 #endif
5292
5293         if (cfg->disable_inline)
5294                 return FALSE;
5295         if (cfg->gshared)
5296                 return FALSE;
5297
5298         if (cfg->inline_depth > 10)
5299                 return FALSE;
5300
5301         if (!mono_method_get_header_summary (method, &header))
5302                 return FALSE;
5303
5304         /*runtime, icall and pinvoke are checked by summary call*/
5305         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
5306             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
5307             (mono_class_is_marshalbyref (method->klass)) ||
5308             header.has_clauses)
5309                 return FALSE;
5310
5311         /* also consider num_locals? */
5312         /* Do the size check early to avoid creating vtables */
5313         if (!inline_limit_inited) {
5314                 if (g_getenv ("MONO_INLINELIMIT"))
5315                         inline_limit = atoi (g_getenv ("MONO_INLINELIMIT"));
5316                 else
5317                         inline_limit = INLINE_LENGTH_LIMIT;
5318                 inline_limit_inited = TRUE;
5319         }
5320         if (header.code_size >= inline_limit && !(method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
5321                 return FALSE;
5322
5323         /*
5324          * if we can initialize the class of the method right away, we do,
5325          * otherwise we don't allow inlining if the class needs initialization,
5326          * since it would mean inserting a call to mono_runtime_class_init()
5327          * inside the inlined code
5328          */
5329         if (!(cfg->opt & MONO_OPT_SHARED)) {
5330                 /* The AggressiveInlining hint is a good excuse to force that cctor to run. */
5331                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING) {
5332                         vtable = mono_class_vtable (cfg->domain, method->klass);
5333                         if (!vtable)
5334                                 return FALSE;
5335                         if (!cfg->compile_aot)
5336                                 mono_runtime_class_init (vtable);
5337                 } else if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5338                         if (cfg->run_cctors && method->klass->has_cctor) {
5339                                 /*FIXME it would easier and lazier to just use mono_class_try_get_vtable */
5340                                 if (!method->klass->runtime_info)
5341                                         /* No vtable created yet */
5342                                         return FALSE;
5343                                 vtable = mono_class_vtable (cfg->domain, method->klass);
5344                                 if (!vtable)
5345                                         return FALSE;
5346                                 /* This makes so that inline cannot trigger */
5347                                 /* .cctors: too many apps depend on them */
5348                                 /* running with a specific order... */
5349                                 if (! vtable->initialized)
5350                                         return FALSE;
5351                                 mono_runtime_class_init (vtable);
5352                         }
5353                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
5354                         if (!method->klass->runtime_info)
5355                                 /* No vtable created yet */
5356                                 return FALSE;
5357                         vtable = mono_class_vtable (cfg->domain, method->klass);
5358                         if (!vtable)
5359                                 return FALSE;
5360                         if (!vtable->initialized)
5361                                 return FALSE;
5362                 }
5363         } else {
5364                 /* 
5365                  * If we're compiling for shared code
5366                  * the cctor will need to be run at aot method load time, for example,
5367                  * or at the end of the compilation of the inlining method.
5368                  */
5369                 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
5370                         return FALSE;
5371         }
5372
5373 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5374         if (mono_arch_is_soft_float ()) {
5375                 /* FIXME: */
5376                 if (sig->ret && sig->ret->type == MONO_TYPE_R4)
5377                         return FALSE;
5378                 for (i = 0; i < sig->param_count; ++i)
5379                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4)
5380                                 return FALSE;
5381         }
5382 #endif
5383
5384         if (g_list_find (cfg->dont_inline, method))
5385                 return FALSE;
5386
5387         return TRUE;
5388 }
5389
5390 static gboolean
5391 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoClass *klass, MonoVTable *vtable)
5392 {
5393         if (!cfg->compile_aot) {
5394                 g_assert (vtable);
5395                 if (vtable->initialized)
5396                         return FALSE;
5397         }
5398
5399         if (klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5400                 if (cfg->method == method)
5401                         return FALSE;
5402         }
5403
5404         if (!mono_class_needs_cctor_run (klass, method))
5405                 return FALSE;
5406
5407         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (klass == method->klass))
5408                 /* The initialization is already done before the method is called */
5409                 return FALSE;
5410
5411         return TRUE;
5412 }
5413
5414 static MonoInst*
5415 mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck)
5416 {
5417         MonoInst *ins;
5418         guint32 size;
5419         int mult_reg, add_reg, array_reg, index_reg, index2_reg;
5420         int context_used;
5421
5422         if (mini_is_gsharedvt_variable_klass (klass)) {
5423                 size = -1;
5424         } else {
5425                 mono_class_init (klass);
5426                 size = mono_class_array_element_size (klass);
5427         }
5428
5429         mult_reg = alloc_preg (cfg);
5430         array_reg = arr->dreg;
5431         index_reg = index->dreg;
5432
5433 #if SIZEOF_REGISTER == 8
5434         /* The array reg is 64 bits but the index reg is only 32 */
5435         if (COMPILE_LLVM (cfg)) {
5436                 /* Not needed */
5437                 index2_reg = index_reg;
5438         } else {
5439                 index2_reg = alloc_preg (cfg);
5440                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
5441         }
5442 #else
5443         if (index->type == STACK_I8) {
5444                 index2_reg = alloc_preg (cfg);
5445                 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I4, index2_reg, index_reg);
5446         } else {
5447                 index2_reg = index_reg;
5448         }
5449 #endif
5450
5451         if (bcheck)
5452                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
5453
5454 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5455         if (size == 1 || size == 2 || size == 4 || size == 8) {
5456                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
5457
5458                 EMIT_NEW_X86_LEA (cfg, ins, array_reg, index2_reg, fast_log2 [size], MONO_STRUCT_OFFSET (MonoArray, vector));
5459                 ins->klass = mono_class_get_element_class (klass);
5460                 ins->type = STACK_MP;
5461
5462                 return ins;
5463         }
5464 #endif          
5465
5466         add_reg = alloc_ireg_mp (cfg);
5467
5468         if (size == -1) {
5469                 MonoInst *rgctx_ins;
5470
5471                 /* gsharedvt */
5472                 g_assert (cfg->gshared);
5473                 context_used = mini_class_check_context_used (cfg, klass);
5474                 g_assert (context_used);
5475                 rgctx_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE);
5476                 MONO_EMIT_NEW_BIALU (cfg, OP_IMUL, mult_reg, index2_reg, rgctx_ins->dreg);
5477         } else {
5478                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
5479         }
5480         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg);
5481         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5482         ins->klass = mono_class_get_element_class (klass);
5483         ins->type = STACK_MP;
5484         MONO_ADD_INS (cfg->cbb, ins);
5485
5486         return ins;
5487 }
5488
5489 static MonoInst*
5490 mini_emit_ldelema_2_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index_ins1, MonoInst *index_ins2)
5491 {
5492         int bounds_reg = alloc_preg (cfg);
5493         int add_reg = alloc_ireg_mp (cfg);
5494         int mult_reg = alloc_preg (cfg);
5495         int mult2_reg = alloc_preg (cfg);
5496         int low1_reg = alloc_preg (cfg);
5497         int low2_reg = alloc_preg (cfg);
5498         int high1_reg = alloc_preg (cfg);
5499         int high2_reg = alloc_preg (cfg);
5500         int realidx1_reg = alloc_preg (cfg);
5501         int realidx2_reg = alloc_preg (cfg);
5502         int sum_reg = alloc_preg (cfg);
5503         int index1, index2, tmpreg;
5504         MonoInst *ins;
5505         guint32 size;
5506
5507         mono_class_init (klass);
5508         size = mono_class_array_element_size (klass);
5509
5510         index1 = index_ins1->dreg;
5511         index2 = index_ins2->dreg;
5512
5513 #if SIZEOF_REGISTER == 8
5514         /* The array reg is 64 bits but the index reg is only 32 */
5515         if (COMPILE_LLVM (cfg)) {
5516                 /* Not needed */
5517         } else {
5518                 tmpreg = alloc_preg (cfg);
5519                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index1);
5520                 index1 = tmpreg;
5521                 tmpreg = alloc_preg (cfg);
5522                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index2);
5523                 index2 = tmpreg;
5524         }
5525 #else
5526         // FIXME: Do we need to do something here for i8 indexes, like in ldelema_1_ins ?
5527         tmpreg = -1;
5528 #endif
5529
5530         /* range checking */
5531         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, 
5532                                        arr->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5533
5534         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low1_reg, 
5535                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5536         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx1_reg, index1, low1_reg);
5537         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high1_reg, 
5538                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5539         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high1_reg, realidx1_reg);
5540         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5541
5542         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low2_reg, 
5543                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5544         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx2_reg, index2, low2_reg);
5545         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high2_reg, 
5546                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5547         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high2_reg, realidx2_reg);
5548         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5549
5550         MONO_EMIT_NEW_BIALU (cfg, OP_PMUL, mult_reg, high2_reg, realidx1_reg);
5551         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, mult_reg, realidx2_reg);
5552         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PMUL_IMM, mult2_reg, sum_reg, size);
5553         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult2_reg, arr->dreg);
5554         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5555
5556         ins->type = STACK_MP;
5557         ins->klass = klass;
5558         MONO_ADD_INS (cfg->cbb, ins);
5559
5560         return ins;
5561 }
5562
5563 static MonoInst*
5564 mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
5565 {
5566         int rank;
5567         MonoInst *addr;
5568         MonoMethod *addr_method;
5569         int element_size;
5570         MonoClass *eclass = cmethod->klass->element_class;
5571
5572         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
5573
5574         if (rank == 1)
5575                 return mini_emit_ldelema_1_ins (cfg, eclass, sp [0], sp [1], TRUE);
5576
5577         /* emit_ldelema_2 depends on OP_LMUL */
5578         if (!cfg->backend->emulate_mul_div && rank == 2 && (cfg->opt & MONO_OPT_INTRINS) && !mini_is_gsharedvt_variable_klass (eclass)) {
5579                 return mini_emit_ldelema_2_ins (cfg, eclass, sp [0], sp [1], sp [2]);
5580         }
5581
5582         if (mini_is_gsharedvt_variable_klass (eclass))
5583                 element_size = 0;
5584         else
5585                 element_size = mono_class_array_element_size (eclass);
5586         addr_method = mono_marshal_get_array_address (rank, element_size);
5587         addr = mono_emit_method_call (cfg, addr_method, sp, NULL);
5588
5589         return addr;
5590 }
5591
5592 static MonoBreakPolicy
5593 always_insert_breakpoint (MonoMethod *method)
5594 {
5595         return MONO_BREAK_POLICY_ALWAYS;
5596 }
5597
5598 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
5599
5600 /**
5601  * mono_set_break_policy:
5602  * policy_callback: the new callback function
5603  *
5604  * Allow embedders to decide wherther to actually obey breakpoint instructions
5605  * (both break IL instructions and Debugger.Break () method calls), for example
5606  * to not allow an app to be aborted by a perfectly valid IL opcode when executing
5607  * untrusted or semi-trusted code.
5608  *
5609  * @policy_callback will be called every time a break point instruction needs to
5610  * be inserted with the method argument being the method that calls Debugger.Break()
5611  * or has the IL break instruction. The callback should return #MONO_BREAK_POLICY_NEVER
5612  * if it wants the breakpoint to not be effective in the given method.
5613  * #MONO_BREAK_POLICY_ALWAYS is the default.
5614  */
5615 void
5616 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
5617 {
5618         if (policy_callback)
5619                 break_policy_func = policy_callback;
5620         else
5621                 break_policy_func = always_insert_breakpoint;
5622 }
5623
5624 static gboolean
5625 should_insert_brekpoint (MonoMethod *method) {
5626         switch (break_policy_func (method)) {
5627         case MONO_BREAK_POLICY_ALWAYS:
5628                 return TRUE;
5629         case MONO_BREAK_POLICY_NEVER:
5630                 return FALSE;
5631         case MONO_BREAK_POLICY_ON_DBG:
5632                 g_warning ("mdb no longer supported");
5633                 return FALSE;
5634         default:
5635                 g_warning ("Incorrect value returned from break policy callback");
5636                 return FALSE;
5637         }
5638 }
5639
5640 /* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */
5641 static MonoInst*
5642 emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5643 {
5644         MonoInst *addr, *store, *load;
5645         MonoClass *eklass = mono_class_from_mono_type (fsig->params [2]);
5646
5647         /* the bounds check is already done by the callers */
5648         addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5649         if (is_set) {
5650                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
5651                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
5652                 if (mini_type_is_reference (fsig->params [2]))
5653                         emit_write_barrier (cfg, addr, load);
5654         } else {
5655                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
5656                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
5657         }
5658         return store;
5659 }
5660
5661
5662 static gboolean
5663 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
5664 {
5665         return mini_type_is_reference (&klass->byval_arg);
5666 }
5667
5668 static MonoInst*
5669 emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboolean safety_checks)
5670 {
5671         if (safety_checks && generic_class_is_reference_type (cfg, klass) &&
5672                 !(sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL)) {
5673                 MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
5674                 MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
5675                 MonoInst *iargs [3];
5676
5677                 if (!helper->slot)
5678                         mono_class_setup_vtable (obj_array);
5679                 g_assert (helper->slot);
5680
5681                 if (sp [0]->type != STACK_OBJ)
5682                         return NULL;
5683                 if (sp [2]->type != STACK_OBJ)
5684                         return NULL;
5685
5686                 iargs [2] = sp [2];
5687                 iargs [1] = sp [1];
5688                 iargs [0] = sp [0];
5689
5690                 return mono_emit_method_call (cfg, helper, iargs, sp [0]);
5691         } else {
5692                 MonoInst *ins;
5693
5694                 if (mini_is_gsharedvt_variable_klass (klass)) {
5695                         MonoInst *addr;
5696
5697                         // FIXME-VT: OP_ICONST optimization
5698                         addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
5699                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5700                         ins->opcode = OP_STOREV_MEMBASE;
5701                 } else if (sp [1]->opcode == OP_ICONST) {
5702                         int array_reg = sp [0]->dreg;
5703                         int index_reg = sp [1]->dreg;
5704                         int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
5705
5706                         if (SIZEOF_REGISTER == 8 && COMPILE_LLVM (cfg))
5707                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, index_reg);
5708
5709                         if (safety_checks)
5710                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
5711                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
5712                 } else {
5713                         MonoInst *addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], safety_checks);
5714                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5715                         if (generic_class_is_reference_type (cfg, klass))
5716                                 emit_write_barrier (cfg, addr, sp [2]);
5717                 }
5718                 return ins;
5719         }
5720 }
5721
5722 static MonoInst*
5723 emit_array_unsafe_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5724 {
5725         MonoClass *eklass;
5726         
5727         if (is_set)
5728                 eklass = mono_class_from_mono_type (fsig->params [2]);
5729         else
5730                 eklass = mono_class_from_mono_type (fsig->ret);
5731
5732         if (is_set) {
5733                 return emit_array_store (cfg, eklass, args, FALSE);
5734         } else {
5735                 MonoInst *ins, *addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5736                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &eklass->byval_arg, addr->dreg, 0);
5737                 return ins;
5738         }
5739 }
5740
5741 static gboolean
5742 is_unsafe_mov_compatible (MonoCompile *cfg, MonoClass *param_klass, MonoClass *return_klass)
5743 {
5744         uint32_t align;
5745         int param_size, return_size;
5746
5747         param_klass = mono_class_from_mono_type (mini_get_underlying_type (&param_klass->byval_arg));
5748         return_klass = mono_class_from_mono_type (mini_get_underlying_type (&return_klass->byval_arg));
5749
5750         if (cfg->verbose_level > 3)
5751                 printf ("[UNSAFE-MOV-INTRISIC] %s <- %s\n", return_klass->name, param_klass->name);
5752
5753         //Don't allow mixing reference types with value types
5754         if (param_klass->valuetype != return_klass->valuetype) {
5755                 if (cfg->verbose_level > 3)
5756                         printf ("[UNSAFE-MOV-INTRISIC]\tone of the args is a valuetype and the other is not\n");
5757                 return FALSE;
5758         }
5759
5760         if (!param_klass->valuetype) {
5761                 if (cfg->verbose_level > 3)
5762                         printf ("[UNSAFE-MOV-INTRISIC]\targs are reference types\n");
5763                 return TRUE;
5764         }
5765
5766         //That are blitable
5767         if (param_klass->has_references || return_klass->has_references)
5768                 return FALSE;
5769
5770         /* Avoid mixing structs and primitive types/enums, they need to be handled differently in the JIT */
5771         if ((MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && !MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)) ||
5772                 (!MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && MONO_TYPE_ISSTRUCT (&return_klass->byval_arg))) {
5773                         if (cfg->verbose_level > 3)
5774                                 printf ("[UNSAFE-MOV-INTRISIC]\tmixing structs and scalars\n");
5775                 return FALSE;
5776         }
5777
5778         if (param_klass->byval_arg.type == MONO_TYPE_R4 || param_klass->byval_arg.type == MONO_TYPE_R8 ||
5779                 return_klass->byval_arg.type == MONO_TYPE_R4 || return_klass->byval_arg.type == MONO_TYPE_R8) {
5780                 if (cfg->verbose_level > 3)
5781                         printf ("[UNSAFE-MOV-INTRISIC]\tfloat or double are not supported\n");
5782                 return FALSE;
5783         }
5784
5785         param_size = mono_class_value_size (param_klass, &align);
5786         return_size = mono_class_value_size (return_klass, &align);
5787
5788         //We can do it if sizes match
5789         if (param_size == return_size) {
5790                 if (cfg->verbose_level > 3)
5791                         printf ("[UNSAFE-MOV-INTRISIC]\tsame size\n");
5792                 return TRUE;
5793         }
5794
5795         //No simple way to handle struct if sizes don't match
5796         if (MONO_TYPE_ISSTRUCT (&param_klass->byval_arg)) {
5797                 if (cfg->verbose_level > 3)
5798                         printf ("[UNSAFE-MOV-INTRISIC]\tsize mismatch and type is a struct\n");
5799                 return FALSE;
5800         }
5801
5802         /*
5803          * Same reg size category.
5804          * A quick note on why we don't require widening here.
5805          * The intrinsic is "R Array.UnsafeMov<S,R> (S s)".
5806          *
5807          * Since the source value comes from a function argument, the JIT will already have
5808          * the value in a VREG and performed any widening needed before (say, when loading from a field).
5809          */
5810         if (param_size <= 4 && return_size <= 4) {
5811                 if (cfg->verbose_level > 3)
5812                         printf ("[UNSAFE-MOV-INTRISIC]\tsize mismatch but both are of the same reg class\n");
5813                 return TRUE;
5814         }
5815
5816         return FALSE;
5817 }
5818
5819 static MonoInst*
5820 emit_array_unsafe_mov (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args)
5821 {
5822         MonoClass *param_klass = mono_class_from_mono_type (fsig->params [0]);
5823         MonoClass *return_klass = mono_class_from_mono_type (fsig->ret);
5824
5825         if (mini_is_gsharedvt_variable_type (fsig->ret))
5826                 return NULL;
5827
5828         //Valuetypes that are semantically equivalent or numbers than can be widened to
5829         if (is_unsafe_mov_compatible (cfg, param_klass, return_klass))
5830                 return args [0];
5831
5832         //Arrays of valuetypes that are semantically equivalent
5833         if (param_klass->rank == 1 && return_klass->rank == 1 && is_unsafe_mov_compatible (cfg, param_klass->element_class, return_klass->element_class))
5834                 return args [0];
5835
5836         return NULL;
5837 }
5838
5839 static MonoInst*
5840 mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5841 {
5842 #ifdef MONO_ARCH_SIMD_INTRINSICS
5843         MonoInst *ins = NULL;
5844
5845         if (cfg->opt & MONO_OPT_SIMD) {
5846                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5847                 if (ins)
5848                         return ins;
5849         }
5850 #endif
5851
5852         return mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
5853 }
5854
5855 static MonoInst*
5856 emit_memory_barrier (MonoCompile *cfg, int kind)
5857 {
5858         MonoInst *ins = NULL;
5859         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
5860         MONO_ADD_INS (cfg->cbb, ins);
5861         ins->backend.memory_barrier_kind = kind;
5862
5863         return ins;
5864 }
5865
5866 static MonoInst*
5867 llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5868 {
5869         MonoInst *ins = NULL;
5870         int opcode = 0;
5871
5872         /* The LLVM backend supports these intrinsics */
5873         if (cmethod->klass == mono_defaults.math_class) {
5874                 if (strcmp (cmethod->name, "Sin") == 0) {
5875                         opcode = OP_SIN;
5876                 } else if (strcmp (cmethod->name, "Cos") == 0) {
5877                         opcode = OP_COS;
5878                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
5879                         opcode = OP_SQRT;
5880                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
5881                         opcode = OP_ABS;
5882                 }
5883
5884                 if (opcode && fsig->param_count == 1) {
5885                         MONO_INST_NEW (cfg, ins, opcode);
5886                         ins->type = STACK_R8;
5887                         ins->dreg = mono_alloc_freg (cfg);
5888                         ins->sreg1 = args [0]->dreg;
5889                         MONO_ADD_INS (cfg->cbb, ins);
5890                 }
5891
5892                 opcode = 0;
5893                 if (cfg->opt & MONO_OPT_CMOV) {
5894                         if (strcmp (cmethod->name, "Min") == 0) {
5895                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5896                                         opcode = OP_IMIN;
5897                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5898                                         opcode = OP_IMIN_UN;
5899                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5900                                         opcode = OP_LMIN;
5901                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5902                                         opcode = OP_LMIN_UN;
5903                         } else if (strcmp (cmethod->name, "Max") == 0) {
5904                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5905                                         opcode = OP_IMAX;
5906                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5907                                         opcode = OP_IMAX_UN;
5908                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5909                                         opcode = OP_LMAX;
5910                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5911                                         opcode = OP_LMAX_UN;
5912                         }
5913                 }
5914
5915                 if (opcode && fsig->param_count == 2) {
5916                         MONO_INST_NEW (cfg, ins, opcode);
5917                         ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
5918                         ins->dreg = mono_alloc_ireg (cfg);
5919                         ins->sreg1 = args [0]->dreg;
5920                         ins->sreg2 = args [1]->dreg;
5921                         MONO_ADD_INS (cfg->cbb, ins);
5922                 }
5923         }
5924
5925         return ins;
5926 }
5927
5928 static MonoInst*
5929 mini_emit_inst_for_sharable_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5930 {
5931         if (cmethod->klass == mono_defaults.array_class) {
5932                 if (strcmp (cmethod->name, "UnsafeStore") == 0)
5933                         return emit_array_unsafe_access (cfg, fsig, args, TRUE);
5934                 else if (strcmp (cmethod->name, "UnsafeLoad") == 0)
5935                         return emit_array_unsafe_access (cfg, fsig, args, FALSE);
5936                 else if (strcmp (cmethod->name, "UnsafeMov") == 0)
5937                         return emit_array_unsafe_mov (cfg, fsig, args);
5938         }
5939
5940         return NULL;
5941 }
5942
5943 static MonoInst*
5944 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5945 {
5946         MonoInst *ins = NULL;
5947
5948         static MonoClass *runtime_helpers_class = NULL;
5949         if (! runtime_helpers_class)
5950                 runtime_helpers_class = mono_class_from_name (mono_defaults.corlib,
5951                         "System.Runtime.CompilerServices", "RuntimeHelpers");
5952
5953         if (cmethod->klass == mono_defaults.string_class) {
5954                 if (strcmp (cmethod->name, "get_Chars") == 0 && fsig->param_count + fsig->hasthis == 2) {
5955                         int dreg = alloc_ireg (cfg);
5956                         int index_reg = alloc_preg (cfg);
5957                         int add_reg = alloc_preg (cfg);
5958
5959 #if SIZEOF_REGISTER == 8
5960                         if (COMPILE_LLVM (cfg)) {
5961                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, args [1]->dreg);
5962                         } else {
5963                                 /* The array reg is 64 bits but the index reg is only 32 */
5964                                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index_reg, args [1]->dreg);
5965                         }
5966 #else
5967                         index_reg = args [1]->dreg;
5968 #endif  
5969                         MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
5970
5971 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5972                         EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, MONO_STRUCT_OFFSET (MonoString, chars));
5973                         add_reg = ins->dreg;
5974                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5975                                                                    add_reg, 0);
5976 #else
5977                         int mult_reg = alloc_preg (cfg);
5978                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1);
5979                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5980                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5981                                                                    add_reg, MONO_STRUCT_OFFSET (MonoString, chars));
5982 #endif
5983                         type_from_op (cfg, ins, NULL, NULL);
5984                         return ins;
5985                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
5986                         int dreg = alloc_ireg (cfg);
5987                         /* Decompose later to allow more optimizations */
5988                         EMIT_NEW_UNALU (cfg, ins, OP_STRLEN, dreg, args [0]->dreg);
5989                         ins->type = STACK_I4;
5990                         ins->flags |= MONO_INST_FAULT;
5991                         cfg->cbb->has_array_access = TRUE;
5992                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
5993
5994                         return ins;
5995                 } else 
5996                         return NULL;
5997         } else if (cmethod->klass == mono_defaults.object_class) {
5998
5999                 if (strcmp (cmethod->name, "GetType") == 0 && fsig->param_count + fsig->hasthis == 1) {
6000                         int dreg = alloc_ireg_ref (cfg);
6001                         int vt_reg = alloc_preg (cfg);
6002                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
6003                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, MONO_STRUCT_OFFSET (MonoVTable, type));
6004                         type_from_op (cfg, ins, NULL, NULL);
6005
6006                         return ins;
6007                 } else if (!cfg->backend->emulate_mul_div && strcmp (cmethod->name, "InternalGetHashCode") == 0 && fsig->param_count == 1 && !mono_gc_is_moving ()) {
6008                         int dreg = alloc_ireg (cfg);
6009                         int t1 = alloc_ireg (cfg);
6010         
6011                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, t1, args [0]->dreg, 3);
6012                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_MUL_IMM, dreg, t1, 2654435761u);
6013                         ins->type = STACK_I4;
6014
6015                         return ins;
6016                 } else if (strcmp (cmethod->name, ".ctor") == 0 && fsig->param_count == 0) {
6017                         MONO_INST_NEW (cfg, ins, OP_NOP);
6018                         MONO_ADD_INS (cfg->cbb, ins);
6019                         return ins;
6020                 } else
6021                         return NULL;
6022         } else if (cmethod->klass == mono_defaults.array_class) {
6023                 if (strcmp (cmethod->name, "GetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
6024                         return emit_array_generic_access (cfg, fsig, args, FALSE);
6025                 else if (strcmp (cmethod->name, "SetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
6026                         return emit_array_generic_access (cfg, fsig, args, TRUE);
6027
6028 #ifndef MONO_BIG_ARRAYS
6029                 /*
6030                  * This is an inline version of GetLength/GetLowerBound(0) used frequently in
6031                  * Array methods.
6032                  */
6033                 else if (((strcmp (cmethod->name, "GetLength") == 0 && fsig->param_count + fsig->hasthis == 2) ||
6034                          (strcmp (cmethod->name, "GetLowerBound") == 0 && fsig->param_count + fsig->hasthis == 2)) &&
6035                          args [1]->opcode == OP_ICONST && args [1]->inst_c0 == 0) {
6036                         int dreg = alloc_ireg (cfg);
6037                         int bounds_reg = alloc_ireg_mp (cfg);
6038                         MonoBasicBlock *end_bb, *szarray_bb;
6039                         gboolean get_length = strcmp (cmethod->name, "GetLength") == 0;
6040
6041                         NEW_BBLOCK (cfg, end_bb);
6042                         NEW_BBLOCK (cfg, szarray_bb);
6043
6044                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOAD_MEMBASE, bounds_reg,
6045                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
6046                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
6047                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, szarray_bb);
6048                         /* Non-szarray case */
6049                         if (get_length)
6050                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
6051                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
6052                         else
6053                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
6054                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
6055                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
6056                         MONO_START_BB (cfg, szarray_bb);
6057                         /* Szarray case */
6058                         if (get_length)
6059                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
6060                                                                            args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
6061                         else
6062                                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
6063                         MONO_START_BB (cfg, end_bb);
6064
6065                         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, dreg, dreg);
6066                         ins->type = STACK_I4;
6067                         
6068                         return ins;
6069                 }
6070 #endif
6071
6072                 if (cmethod->name [0] != 'g')
6073                         return NULL;
6074
6075                 if (strcmp (cmethod->name, "get_Rank") == 0 && fsig->param_count + fsig->hasthis == 1) {
6076                         int dreg = alloc_ireg (cfg);
6077                         int vtable_reg = alloc_preg (cfg);
6078                         MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, 
6079                                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
6080                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
6081                                                                    vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
6082                         type_from_op (cfg, ins, NULL, NULL);
6083
6084                         return ins;
6085                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
6086                         int dreg = alloc_ireg (cfg);
6087
6088                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
6089                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
6090                         type_from_op (cfg, ins, NULL, NULL);
6091
6092                         return ins;
6093                 } else
6094                         return NULL;
6095         } else if (cmethod->klass == runtime_helpers_class) {
6096
6097                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0 && fsig->param_count == 0) {
6098                         EMIT_NEW_ICONST (cfg, ins, MONO_STRUCT_OFFSET (MonoString, chars));
6099                         return ins;
6100                 } else
6101                         return NULL;
6102         } else if (cmethod->klass == mono_defaults.thread_class) {
6103                 if (strcmp (cmethod->name, "SpinWait_nop") == 0 && fsig->param_count == 0) {
6104                         MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
6105                         MONO_ADD_INS (cfg->cbb, ins);
6106                         return ins;
6107                 } else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0) {
6108                         return emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6109                 } else if (!strcmp (cmethod->name, "VolatileRead") && fsig->param_count == 1) {
6110                         guint32 opcode = 0;
6111                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6112
6113                         if (fsig->params [0]->type == MONO_TYPE_I1)
6114                                 opcode = OP_LOADI1_MEMBASE;
6115                         else if (fsig->params [0]->type == MONO_TYPE_U1)
6116                                 opcode = OP_LOADU1_MEMBASE;
6117                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6118                                 opcode = OP_LOADI2_MEMBASE;
6119                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6120                                 opcode = OP_LOADU2_MEMBASE;
6121                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6122                                 opcode = OP_LOADI4_MEMBASE;
6123                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6124                                 opcode = OP_LOADU4_MEMBASE;
6125                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
6126                                 opcode = OP_LOADI8_MEMBASE;
6127                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6128                                 opcode = OP_LOADR4_MEMBASE;
6129                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6130                                 opcode = OP_LOADR8_MEMBASE;
6131                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
6132                                 opcode = OP_LOAD_MEMBASE;
6133
6134                         if (opcode) {
6135                                 MONO_INST_NEW (cfg, ins, opcode);
6136                                 ins->inst_basereg = args [0]->dreg;
6137                                 ins->inst_offset = 0;
6138                                 MONO_ADD_INS (cfg->cbb, ins);
6139
6140                                 switch (fsig->params [0]->type) {
6141                                 case MONO_TYPE_I1:
6142                                 case MONO_TYPE_U1:
6143                                 case MONO_TYPE_I2:
6144                                 case MONO_TYPE_U2:
6145                                 case MONO_TYPE_I4:
6146                                 case MONO_TYPE_U4:
6147                                         ins->dreg = mono_alloc_ireg (cfg);
6148                                         ins->type = STACK_I4;
6149                                         break;
6150                                 case MONO_TYPE_I8:
6151                                 case MONO_TYPE_U8:
6152                                         ins->dreg = mono_alloc_lreg (cfg);
6153                                         ins->type = STACK_I8;
6154                                         break;
6155                                 case MONO_TYPE_I:
6156                                 case MONO_TYPE_U:
6157                                         ins->dreg = mono_alloc_ireg (cfg);
6158 #if SIZEOF_REGISTER == 8
6159                                         ins->type = STACK_I8;
6160 #else
6161                                         ins->type = STACK_I4;
6162 #endif
6163                                         break;
6164                                 case MONO_TYPE_R4:
6165                                 case MONO_TYPE_R8:
6166                                         ins->dreg = mono_alloc_freg (cfg);
6167                                         ins->type = STACK_R8;
6168                                         break;
6169                                 default:
6170                                         g_assert (mini_type_is_reference (fsig->params [0]));
6171                                         ins->dreg = mono_alloc_ireg_ref (cfg);
6172                                         ins->type = STACK_OBJ;
6173                                         break;
6174                                 }
6175
6176                                 if (opcode == OP_LOADI8_MEMBASE)
6177                                         ins = mono_decompose_opcode (cfg, ins);
6178
6179                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6180
6181                                 return ins;
6182                         }
6183                 } else if (!strcmp (cmethod->name, "VolatileWrite") && fsig->param_count == 2) {
6184                         guint32 opcode = 0;
6185                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6186
6187                         if (fsig->params [0]->type == MONO_TYPE_I1 || fsig->params [0]->type == MONO_TYPE_U1)
6188                                 opcode = OP_STOREI1_MEMBASE_REG;
6189                         else if (fsig->params [0]->type == MONO_TYPE_I2 || fsig->params [0]->type == MONO_TYPE_U2)
6190                                 opcode = OP_STOREI2_MEMBASE_REG;
6191                         else if (fsig->params [0]->type == MONO_TYPE_I4 || fsig->params [0]->type == MONO_TYPE_U4)
6192                                 opcode = OP_STOREI4_MEMBASE_REG;
6193                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
6194                                 opcode = OP_STOREI8_MEMBASE_REG;
6195                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6196                                 opcode = OP_STORER4_MEMBASE_REG;
6197                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6198                                 opcode = OP_STORER8_MEMBASE_REG;
6199                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
6200                                 opcode = OP_STORE_MEMBASE_REG;
6201
6202                         if (opcode) {
6203                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6204
6205                                 MONO_INST_NEW (cfg, ins, opcode);
6206                                 ins->sreg1 = args [1]->dreg;
6207                                 ins->inst_destbasereg = args [0]->dreg;
6208                                 ins->inst_offset = 0;
6209                                 MONO_ADD_INS (cfg->cbb, ins);
6210
6211                                 if (opcode == OP_STOREI8_MEMBASE_REG)
6212                                         ins = mono_decompose_opcode (cfg, ins);
6213
6214                                 return ins;
6215                         }
6216                 }
6217         } else if (cmethod->klass->image == mono_defaults.corlib &&
6218                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6219                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
6220                 ins = NULL;
6221
6222 #if SIZEOF_REGISTER == 8
6223                 if (!cfg->llvm_only && strcmp (cmethod->name, "Read") == 0 && fsig->param_count == 1 && (fsig->params [0]->type == MONO_TYPE_I8)) {
6224                         if (!cfg->llvm_only && mono_arch_opcode_supported (OP_ATOMIC_LOAD_I8)) {
6225                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_LOAD_I8);
6226                                 ins->dreg = mono_alloc_preg (cfg);
6227                                 ins->sreg1 = args [0]->dreg;
6228                                 ins->type = STACK_I8;
6229                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_SEQ;
6230                                 MONO_ADD_INS (cfg->cbb, ins);
6231                         } else {
6232                                 MonoInst *load_ins;
6233
6234                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6235
6236                                 /* 64 bit reads are already atomic */
6237                                 MONO_INST_NEW (cfg, load_ins, OP_LOADI8_MEMBASE);
6238                                 load_ins->dreg = mono_alloc_preg (cfg);
6239                                 load_ins->inst_basereg = args [0]->dreg;
6240                                 load_ins->inst_offset = 0;
6241                                 load_ins->type = STACK_I8;
6242                                 MONO_ADD_INS (cfg->cbb, load_ins);
6243
6244                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6245
6246                                 ins = load_ins;
6247                         }
6248                 }
6249 #endif
6250
6251                 if (strcmp (cmethod->name, "Increment") == 0 && fsig->param_count == 1) {
6252                         MonoInst *ins_iconst;
6253                         guint32 opcode = 0;
6254
6255                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6256                                 opcode = OP_ATOMIC_ADD_I4;
6257                                 cfg->has_atomic_add_i4 = TRUE;
6258                         }
6259 #if SIZEOF_REGISTER == 8
6260                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6261                                 opcode = OP_ATOMIC_ADD_I8;
6262 #endif
6263                         if (opcode) {
6264                                 if (!mono_arch_opcode_supported (opcode))
6265                                         return NULL;
6266                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6267                                 ins_iconst->inst_c0 = 1;
6268                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6269                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6270
6271                                 MONO_INST_NEW (cfg, ins, opcode);
6272                                 ins->dreg = mono_alloc_ireg (cfg);
6273                                 ins->inst_basereg = args [0]->dreg;
6274                                 ins->inst_offset = 0;
6275                                 ins->sreg2 = ins_iconst->dreg;
6276                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6277                                 MONO_ADD_INS (cfg->cbb, ins);
6278                         }
6279                 } else if (strcmp (cmethod->name, "Decrement") == 0 && fsig->param_count == 1) {
6280                         MonoInst *ins_iconst;
6281                         guint32 opcode = 0;
6282
6283                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6284                                 opcode = OP_ATOMIC_ADD_I4;
6285                                 cfg->has_atomic_add_i4 = TRUE;
6286                         }
6287 #if SIZEOF_REGISTER == 8
6288                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6289                                 opcode = OP_ATOMIC_ADD_I8;
6290 #endif
6291                         if (opcode) {
6292                                 if (!mono_arch_opcode_supported (opcode))
6293                                         return NULL;
6294                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6295                                 ins_iconst->inst_c0 = -1;
6296                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6297                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6298
6299                                 MONO_INST_NEW (cfg, ins, opcode);
6300                                 ins->dreg = mono_alloc_ireg (cfg);
6301                                 ins->inst_basereg = args [0]->dreg;
6302                                 ins->inst_offset = 0;
6303                                 ins->sreg2 = ins_iconst->dreg;
6304                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6305                                 MONO_ADD_INS (cfg->cbb, ins);
6306                         }
6307                 } else if (strcmp (cmethod->name, "Add") == 0 && fsig->param_count == 2) {
6308                         guint32 opcode = 0;
6309
6310                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6311                                 opcode = OP_ATOMIC_ADD_I4;
6312                                 cfg->has_atomic_add_i4 = TRUE;
6313                         }
6314 #if SIZEOF_REGISTER == 8
6315                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6316                                 opcode = OP_ATOMIC_ADD_I8;
6317 #endif
6318                         if (opcode) {
6319                                 if (!mono_arch_opcode_supported (opcode))
6320                                         return NULL;
6321                                 MONO_INST_NEW (cfg, ins, opcode);
6322                                 ins->dreg = mono_alloc_ireg (cfg);
6323                                 ins->inst_basereg = args [0]->dreg;
6324                                 ins->inst_offset = 0;
6325                                 ins->sreg2 = args [1]->dreg;
6326                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6327                                 MONO_ADD_INS (cfg->cbb, ins);
6328                         }
6329                 }
6330                 else if (strcmp (cmethod->name, "Exchange") == 0 && fsig->param_count == 2) {
6331                         MonoInst *f2i = NULL, *i2f;
6332                         guint32 opcode, f2i_opcode, i2f_opcode;
6333                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6334                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
6335
6336                         if (fsig->params [0]->type == MONO_TYPE_I4 ||
6337                             fsig->params [0]->type == MONO_TYPE_R4) {
6338                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6339                                 f2i_opcode = OP_MOVE_F_TO_I4;
6340                                 i2f_opcode = OP_MOVE_I4_TO_F;
6341                                 cfg->has_atomic_exchange_i4 = TRUE;
6342                         }
6343 #if SIZEOF_REGISTER == 8
6344                         else if (is_ref ||
6345                                  fsig->params [0]->type == MONO_TYPE_I8 ||
6346                                  fsig->params [0]->type == MONO_TYPE_R8 ||
6347                                  fsig->params [0]->type == MONO_TYPE_I) {
6348                                 opcode = OP_ATOMIC_EXCHANGE_I8;
6349                                 f2i_opcode = OP_MOVE_F_TO_I8;
6350                                 i2f_opcode = OP_MOVE_I8_TO_F;
6351                         }
6352 #else
6353                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I) {
6354                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6355                                 cfg->has_atomic_exchange_i4 = TRUE;
6356                         }
6357 #endif
6358                         else
6359                                 return NULL;
6360
6361                         if (!mono_arch_opcode_supported (opcode))
6362                                 return NULL;
6363
6364                         if (is_float) {
6365                                 /* TODO: Decompose these opcodes instead of bailing here. */
6366                                 if (COMPILE_SOFT_FLOAT (cfg))
6367                                         return NULL;
6368
6369                                 MONO_INST_NEW (cfg, f2i, f2i_opcode);
6370                                 f2i->dreg = mono_alloc_ireg (cfg);
6371                                 f2i->sreg1 = args [1]->dreg;
6372                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6373                                         f2i->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6374                                 MONO_ADD_INS (cfg->cbb, f2i);
6375                         }
6376
6377                         MONO_INST_NEW (cfg, ins, opcode);
6378                         ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : mono_alloc_ireg (cfg);
6379                         ins->inst_basereg = args [0]->dreg;
6380                         ins->inst_offset = 0;
6381                         ins->sreg2 = is_float ? f2i->dreg : args [1]->dreg;
6382                         MONO_ADD_INS (cfg->cbb, ins);
6383
6384                         switch (fsig->params [0]->type) {
6385                         case MONO_TYPE_I4:
6386                                 ins->type = STACK_I4;
6387                                 break;
6388                         case MONO_TYPE_I8:
6389                                 ins->type = STACK_I8;
6390                                 break;
6391                         case MONO_TYPE_I:
6392 #if SIZEOF_REGISTER == 8
6393                                 ins->type = STACK_I8;
6394 #else
6395                                 ins->type = STACK_I4;
6396 #endif
6397                                 break;
6398                         case MONO_TYPE_R4:
6399                         case MONO_TYPE_R8:
6400                                 ins->type = STACK_R8;
6401                                 break;
6402                         default:
6403                                 g_assert (mini_type_is_reference (fsig->params [0]));
6404                                 ins->type = STACK_OBJ;
6405                                 break;
6406                         }
6407
6408                         if (is_float) {
6409                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6410                                 i2f->dreg = mono_alloc_freg (cfg);
6411                                 i2f->sreg1 = ins->dreg;
6412                                 i2f->type = STACK_R8;
6413                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6414                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6415                                 MONO_ADD_INS (cfg->cbb, i2f);
6416
6417                                 ins = i2f;
6418                         }
6419
6420                         if (cfg->gen_write_barriers && is_ref)
6421                                 emit_write_barrier (cfg, args [0], args [1]);
6422                 }
6423                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 3) {
6424                         MonoInst *f2i_new = NULL, *f2i_cmp = NULL, *i2f;
6425                         guint32 opcode, f2i_opcode, i2f_opcode;
6426                         gboolean is_ref = mini_type_is_reference (fsig->params [1]);
6427                         gboolean is_float = fsig->params [1]->type == MONO_TYPE_R4 || fsig->params [1]->type == MONO_TYPE_R8;
6428
6429                         if (fsig->params [1]->type == MONO_TYPE_I4 ||
6430                             fsig->params [1]->type == MONO_TYPE_R4) {
6431                                 opcode = OP_ATOMIC_CAS_I4;
6432                                 f2i_opcode = OP_MOVE_F_TO_I4;
6433                                 i2f_opcode = OP_MOVE_I4_TO_F;
6434                                 cfg->has_atomic_cas_i4 = TRUE;
6435                         }
6436 #if SIZEOF_REGISTER == 8
6437                         else if (is_ref ||
6438                                  fsig->params [1]->type == MONO_TYPE_I8 ||
6439                                  fsig->params [1]->type == MONO_TYPE_R8 ||
6440                                  fsig->params [1]->type == MONO_TYPE_I) {
6441                                 opcode = OP_ATOMIC_CAS_I8;
6442                                 f2i_opcode = OP_MOVE_F_TO_I8;
6443                                 i2f_opcode = OP_MOVE_I8_TO_F;
6444                         }
6445 #else
6446                         else if (is_ref || fsig->params [1]->type == MONO_TYPE_I) {
6447                                 opcode = OP_ATOMIC_CAS_I4;
6448                                 cfg->has_atomic_cas_i4 = TRUE;
6449                         }
6450 #endif
6451                         else
6452                                 return NULL;
6453
6454                         if (!mono_arch_opcode_supported (opcode))
6455                                 return NULL;
6456
6457                         if (is_float) {
6458                                 /* TODO: Decompose these opcodes instead of bailing here. */
6459                                 if (COMPILE_SOFT_FLOAT (cfg))
6460                                         return NULL;
6461
6462                                 MONO_INST_NEW (cfg, f2i_new, f2i_opcode);
6463                                 f2i_new->dreg = mono_alloc_ireg (cfg);
6464                                 f2i_new->sreg1 = args [1]->dreg;
6465                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6466                                         f2i_new->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6467                                 MONO_ADD_INS (cfg->cbb, f2i_new);
6468
6469                                 MONO_INST_NEW (cfg, f2i_cmp, f2i_opcode);
6470                                 f2i_cmp->dreg = mono_alloc_ireg (cfg);
6471                                 f2i_cmp->sreg1 = args [2]->dreg;
6472                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6473                                         f2i_cmp->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6474                                 MONO_ADD_INS (cfg->cbb, f2i_cmp);
6475                         }
6476
6477                         MONO_INST_NEW (cfg, ins, opcode);
6478                         ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
6479                         ins->sreg1 = args [0]->dreg;
6480                         ins->sreg2 = is_float ? f2i_new->dreg : args [1]->dreg;
6481                         ins->sreg3 = is_float ? f2i_cmp->dreg : args [2]->dreg;
6482                         MONO_ADD_INS (cfg->cbb, ins);
6483
6484                         switch (fsig->params [1]->type) {
6485                         case MONO_TYPE_I4:
6486                                 ins->type = STACK_I4;
6487                                 break;
6488                         case MONO_TYPE_I8:
6489                                 ins->type = STACK_I8;
6490                                 break;
6491                         case MONO_TYPE_I:
6492 #if SIZEOF_REGISTER == 8
6493                                 ins->type = STACK_I8;
6494 #else
6495                                 ins->type = STACK_I4;
6496 #endif
6497                                 break;
6498                         case MONO_TYPE_R4:
6499                                 ins->type = cfg->r4_stack_type;
6500                                 break;
6501                         case MONO_TYPE_R8:
6502                                 ins->type = STACK_R8;
6503                                 break;
6504                         default:
6505                                 g_assert (mini_type_is_reference (fsig->params [1]));
6506                                 ins->type = STACK_OBJ;
6507                                 break;
6508                         }
6509
6510                         if (is_float) {
6511                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6512                                 i2f->dreg = mono_alloc_freg (cfg);
6513                                 i2f->sreg1 = ins->dreg;
6514                                 i2f->type = STACK_R8;
6515                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6516                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6517                                 MONO_ADD_INS (cfg->cbb, i2f);
6518
6519                                 ins = i2f;
6520                         }
6521
6522                         if (cfg->gen_write_barriers && is_ref)
6523                                 emit_write_barrier (cfg, args [0], args [1]);
6524                 }
6525                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 4 &&
6526                          fsig->params [1]->type == MONO_TYPE_I4) {
6527                         MonoInst *cmp, *ceq;
6528
6529                         if (!mono_arch_opcode_supported (OP_ATOMIC_CAS_I4))
6530                                 return NULL;
6531
6532                         /* int32 r = CAS (location, value, comparand); */
6533                         MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
6534                         ins->dreg = alloc_ireg (cfg);
6535                         ins->sreg1 = args [0]->dreg;
6536                         ins->sreg2 = args [1]->dreg;
6537                         ins->sreg3 = args [2]->dreg;
6538                         ins->type = STACK_I4;
6539                         MONO_ADD_INS (cfg->cbb, ins);
6540
6541                         /* bool result = r == comparand; */
6542                         MONO_INST_NEW (cfg, cmp, OP_ICOMPARE);
6543                         cmp->sreg1 = ins->dreg;
6544                         cmp->sreg2 = args [2]->dreg;
6545                         cmp->type = STACK_I4;
6546                         MONO_ADD_INS (cfg->cbb, cmp);
6547
6548                         MONO_INST_NEW (cfg, ceq, OP_ICEQ);
6549                         ceq->dreg = alloc_ireg (cfg);
6550                         ceq->type = STACK_I4;
6551                         MONO_ADD_INS (cfg->cbb, ceq);
6552
6553                         /* *success = result; */
6554                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, args [3]->dreg, 0, ceq->dreg);
6555
6556                         cfg->has_atomic_cas_i4 = TRUE;
6557                 }
6558                 else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0)
6559                         ins = emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6560
6561                 if (ins)
6562                         return ins;
6563         } else if (cmethod->klass->image == mono_defaults.corlib &&
6564                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6565                            (strcmp (cmethod->klass->name, "Volatile") == 0)) {
6566                 ins = NULL;
6567
6568                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Read") && fsig->param_count == 1) {
6569                         guint32 opcode = 0;
6570                         MonoType *t = fsig->params [0];
6571                         gboolean is_ref;
6572                         gboolean is_float = t->type == MONO_TYPE_R4 || t->type == MONO_TYPE_R8;
6573
6574                         g_assert (t->byref);
6575                         /* t is a byref type, so the reference check is more complicated */
6576                         is_ref = mini_type_is_reference (&mono_class_from_mono_type (t)->byval_arg);
6577                         if (t->type == MONO_TYPE_I1)
6578                                 opcode = OP_ATOMIC_LOAD_I1;
6579                         else if (t->type == MONO_TYPE_U1 || t->type == MONO_TYPE_BOOLEAN)
6580                                 opcode = OP_ATOMIC_LOAD_U1;
6581                         else if (t->type == MONO_TYPE_I2)
6582                                 opcode = OP_ATOMIC_LOAD_I2;
6583                         else if (t->type == MONO_TYPE_U2)
6584                                 opcode = OP_ATOMIC_LOAD_U2;
6585                         else if (t->type == MONO_TYPE_I4)
6586                                 opcode = OP_ATOMIC_LOAD_I4;
6587                         else if (t->type == MONO_TYPE_U4)
6588                                 opcode = OP_ATOMIC_LOAD_U4;
6589                         else if (t->type == MONO_TYPE_R4)
6590                                 opcode = OP_ATOMIC_LOAD_R4;
6591                         else if (t->type == MONO_TYPE_R8)
6592                                 opcode = OP_ATOMIC_LOAD_R8;
6593 #if SIZEOF_REGISTER == 8
6594                         else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_I)
6595                                 opcode = OP_ATOMIC_LOAD_I8;
6596                         else if (is_ref || t->type == MONO_TYPE_U8 || t->type == MONO_TYPE_U)
6597                                 opcode = OP_ATOMIC_LOAD_U8;
6598 #else
6599                         else if (t->type == MONO_TYPE_I)
6600                                 opcode = OP_ATOMIC_LOAD_I4;
6601                         else if (is_ref || t->type == MONO_TYPE_U)
6602                                 opcode = OP_ATOMIC_LOAD_U4;
6603 #endif
6604
6605                         if (opcode) {
6606                                 if (!mono_arch_opcode_supported (opcode))
6607                                         return NULL;
6608
6609                                 MONO_INST_NEW (cfg, ins, opcode);
6610                                 ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : (is_float ? mono_alloc_freg (cfg) : mono_alloc_ireg (cfg));
6611                                 ins->sreg1 = args [0]->dreg;
6612                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_ACQ;
6613                                 MONO_ADD_INS (cfg->cbb, ins);
6614
6615                                 switch (t->type) {
6616                                 case MONO_TYPE_BOOLEAN:
6617                                 case MONO_TYPE_I1:
6618                                 case MONO_TYPE_U1:
6619                                 case MONO_TYPE_I2:
6620                                 case MONO_TYPE_U2:
6621                                 case MONO_TYPE_I4:
6622                                 case MONO_TYPE_U4:
6623                                         ins->type = STACK_I4;
6624                                         break;
6625                                 case MONO_TYPE_I8:
6626                                 case MONO_TYPE_U8:
6627                                         ins->type = STACK_I8;
6628                                         break;
6629                                 case MONO_TYPE_I:
6630                                 case MONO_TYPE_U:
6631 #if SIZEOF_REGISTER == 8
6632                                         ins->type = STACK_I8;
6633 #else
6634                                         ins->type = STACK_I4;
6635 #endif
6636                                         break;
6637                                 case MONO_TYPE_R4:
6638                                         ins->type = cfg->r4_stack_type;
6639                                         break;
6640                                 case MONO_TYPE_R8:
6641                                         ins->type = STACK_R8;
6642                                         break;
6643                                 default:
6644                                         g_assert (is_ref);
6645                                         ins->type = STACK_OBJ;
6646                                         break;
6647                                 }
6648                         }
6649                 }
6650
6651                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Write") && fsig->param_count == 2) {
6652                         guint32 opcode = 0;
6653                         MonoType *t = fsig->params [0];
6654                         gboolean is_ref;
6655
6656                         g_assert (t->byref);
6657                         is_ref = mini_type_is_reference (&mono_class_from_mono_type (t)->byval_arg);
6658                         if (t->type == MONO_TYPE_I1)
6659                                 opcode = OP_ATOMIC_STORE_I1;
6660                         else if (t->type == MONO_TYPE_U1 || t->type == MONO_TYPE_BOOLEAN)
6661                                 opcode = OP_ATOMIC_STORE_U1;
6662                         else if (t->type == MONO_TYPE_I2)
6663                                 opcode = OP_ATOMIC_STORE_I2;
6664                         else if (t->type == MONO_TYPE_U2)
6665                                 opcode = OP_ATOMIC_STORE_U2;
6666                         else if (t->type == MONO_TYPE_I4)
6667                                 opcode = OP_ATOMIC_STORE_I4;
6668                         else if (t->type == MONO_TYPE_U4)
6669                                 opcode = OP_ATOMIC_STORE_U4;
6670                         else if (t->type == MONO_TYPE_R4)
6671                                 opcode = OP_ATOMIC_STORE_R4;
6672                         else if (t->type == MONO_TYPE_R8)
6673                                 opcode = OP_ATOMIC_STORE_R8;
6674 #if SIZEOF_REGISTER == 8
6675                         else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_I)
6676                                 opcode = OP_ATOMIC_STORE_I8;
6677                         else if (is_ref || t->type == MONO_TYPE_U8 || t->type == MONO_TYPE_U)
6678                                 opcode = OP_ATOMIC_STORE_U8;
6679 #else
6680                         else if (t->type == MONO_TYPE_I)
6681                                 opcode = OP_ATOMIC_STORE_I4;
6682                         else if (is_ref || t->type == MONO_TYPE_U)
6683                                 opcode = OP_ATOMIC_STORE_U4;
6684 #endif
6685
6686                         if (opcode) {
6687                                 if (!mono_arch_opcode_supported (opcode))
6688                                         return NULL;
6689
6690                                 MONO_INST_NEW (cfg, ins, opcode);
6691                                 ins->dreg = args [0]->dreg;
6692                                 ins->sreg1 = args [1]->dreg;
6693                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_REL;
6694                                 MONO_ADD_INS (cfg->cbb, ins);
6695
6696                                 if (cfg->gen_write_barriers && is_ref)
6697                                         emit_write_barrier (cfg, args [0], args [1]);
6698                         }
6699                 }
6700
6701                 if (ins)
6702                         return ins;
6703         } else if (cmethod->klass->image == mono_defaults.corlib &&
6704                            (strcmp (cmethod->klass->name_space, "System.Diagnostics") == 0) &&
6705                            (strcmp (cmethod->klass->name, "Debugger") == 0)) {
6706                 if (!strcmp (cmethod->name, "Break") && fsig->param_count == 0) {
6707                         if (should_insert_brekpoint (cfg->method)) {
6708                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
6709                         } else {
6710                                 MONO_INST_NEW (cfg, ins, OP_NOP);
6711                                 MONO_ADD_INS (cfg->cbb, ins);
6712                         }
6713                         return ins;
6714                 }
6715         } else if (cmethod->klass->image == mono_defaults.corlib &&
6716                    (strcmp (cmethod->klass->name_space, "System") == 0) &&
6717                    (strcmp (cmethod->klass->name, "Environment") == 0)) {
6718                 if (!strcmp (cmethod->name, "get_IsRunningOnWindows") && fsig->param_count == 0) {
6719 #ifdef TARGET_WIN32
6720                         EMIT_NEW_ICONST (cfg, ins, 1);
6721 #else
6722                         EMIT_NEW_ICONST (cfg, ins, 0);
6723 #endif
6724                 }
6725         } else if (cmethod->klass->image == mono_defaults.corlib &&
6726                            (strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
6727                            (strcmp (cmethod->klass->name, "Assembly") == 0)) {
6728                 if (cfg->llvm_only && !strcmp (cmethod->name, "GetExecutingAssembly")) {
6729                         /* No stack walks are currently available, so implement this as an intrinsic */
6730                         MonoInst *assembly_ins;
6731
6732                         EMIT_NEW_AOTCONST (cfg, assembly_ins, MONO_PATCH_INFO_IMAGE, cfg->method->klass->image);
6733                         ins = mono_emit_jit_icall (cfg, mono_get_assembly_object, &assembly_ins);
6734                         return ins;
6735                 }
6736                 if (cfg->llvm_only && !strcmp (cmethod->name, "GetCallingAssembly")) {
6737                         /* No stack walks are currently available, so implement this as an intrinsic */
6738                         ins = mono_emit_jit_icall (cfg, mono_llvmonly_get_calling_assembly, NULL);
6739                         return ins;
6740                 }
6741         } else if (cmethod->klass->image == mono_defaults.corlib &&
6742                            (strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
6743                            (strcmp (cmethod->klass->name, "MethodBase") == 0)) {
6744                 if (cfg->llvm_only && !strcmp (cmethod->name, "GetCurrentMethod")) {
6745                         /* No stack walks are currently available, so implement this as an intrinsic */
6746                         MonoInst *method_ins;
6747                         MonoMethod *declaring = cfg->method;
6748
6749                         /* This returns the declaring generic method */
6750                         if (declaring->is_inflated)
6751                                 declaring = ((MonoMethodInflated*)cfg->method)->declaring;
6752                         EMIT_NEW_AOTCONST (cfg, method_ins, MONO_PATCH_INFO_METHODCONST, declaring);
6753                         ins = mono_emit_jit_icall (cfg, mono_get_method_object, &method_ins);
6754                         cfg->no_inline = TRUE;
6755                         if (cfg->method != cfg->current_method)
6756                                 inline_failure (cfg, "MethodBase:GetCurrentMethod ()");
6757                         return ins;
6758                 }
6759         } else if (cmethod->klass == mono_defaults.math_class) {
6760                 /* 
6761                  * There is general branchless code for Min/Max, but it does not work for 
6762                  * all inputs:
6763                  * http://everything2.com/?node_id=1051618
6764                  */
6765         } else if (((!strcmp (cmethod->klass->image->assembly->aname.name, "MonoMac") ||
6766                     !strcmp (cmethod->klass->image->assembly->aname.name, "monotouch")) &&
6767                                 !strcmp (cmethod->klass->name_space, "XamCore.ObjCRuntime") &&
6768                                 !strcmp (cmethod->klass->name, "Selector")) ||
6769                            (!strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.iOS") &&
6770                                 !strcmp (cmethod->klass->name_space, "ObjCRuntime") &&
6771                                 !strcmp (cmethod->klass->name, "Selector"))
6772                            ) {
6773                 if (cfg->backend->have_objc_get_selector &&
6774                         !strcmp (cmethod->name, "GetHandle") && fsig->param_count == 1 &&
6775                     (args [0]->opcode == OP_GOT_ENTRY || args [0]->opcode == OP_AOTCONST) &&
6776                     cfg->compile_aot && !cfg->llvm_only) {
6777                         MonoInst *pi;
6778                         MonoJumpInfoToken *ji;
6779                         MonoString *s;
6780
6781                         // FIXME: llvmonly
6782
6783                         cfg->exception_message = g_strdup ("GetHandle");
6784                         cfg->disable_llvm = TRUE;
6785
6786                         if (args [0]->opcode == OP_GOT_ENTRY) {
6787                                 pi = (MonoInst *)args [0]->inst_p1;
6788                                 g_assert (pi->opcode == OP_PATCH_INFO);
6789                                 g_assert (GPOINTER_TO_INT (pi->inst_p1) == MONO_PATCH_INFO_LDSTR);
6790                                 ji = (MonoJumpInfoToken *)pi->inst_p0;
6791                         } else {
6792                                 g_assert (GPOINTER_TO_INT (args [0]->inst_p1) == MONO_PATCH_INFO_LDSTR);
6793                                 ji = (MonoJumpInfoToken *)args [0]->inst_p0;
6794                         }
6795
6796                         NULLIFY_INS (args [0]);
6797
6798                         // FIXME: Ugly
6799                         s = mono_ldstr (cfg->domain, ji->image, mono_metadata_token_index (ji->token));
6800                         MONO_INST_NEW (cfg, ins, OP_OBJC_GET_SELECTOR);
6801                         ins->dreg = mono_alloc_ireg (cfg);
6802                         // FIXME: Leaks
6803                         ins->inst_p0 = mono_string_to_utf8 (s);
6804                         MONO_ADD_INS (cfg->cbb, ins);
6805                         return ins;
6806                 }
6807         }
6808
6809 #ifdef MONO_ARCH_SIMD_INTRINSICS
6810         if (cfg->opt & MONO_OPT_SIMD) {
6811                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
6812                 if (ins)
6813                         return ins;
6814         }
6815 #endif
6816
6817         ins = mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
6818         if (ins)
6819                 return ins;
6820
6821         if (COMPILE_LLVM (cfg)) {
6822                 ins = llvm_emit_inst_for_method (cfg, cmethod, fsig, args);
6823                 if (ins)
6824                         return ins;
6825         }
6826
6827         return mono_arch_emit_inst_for_method (cfg, cmethod, fsig, args);
6828 }
6829
6830 /*
6831  * This entry point could be used later for arbitrary method
6832  * redirection.
6833  */
6834 inline static MonoInst*
6835 mini_redirect_call (MonoCompile *cfg, MonoMethod *method,  
6836                                         MonoMethodSignature *signature, MonoInst **args, MonoInst *this_ins)
6837 {
6838         if (method->klass == mono_defaults.string_class) {
6839                 /* managed string allocation support */
6840                 if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && !(cfg->opt & MONO_OPT_SHARED)) {
6841                         MonoInst *iargs [2];
6842                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
6843                         MonoMethod *managed_alloc = NULL;
6844
6845                         g_assert (vtable); /*Should not fail since it System.String*/
6846 #ifndef MONO_CROSS_COMPILE
6847                         managed_alloc = mono_gc_get_managed_allocator (method->klass, FALSE, FALSE);
6848 #endif
6849                         if (!managed_alloc)
6850                                 return NULL;
6851                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
6852                         iargs [1] = args [0];
6853                         return mono_emit_method_call (cfg, managed_alloc, iargs, this_ins);
6854                 }
6855         }
6856         return NULL;
6857 }
6858
6859 static void
6860 mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp)
6861 {
6862         MonoInst *store, *temp;
6863         int i;
6864
6865         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
6866                 MonoType *argtype = (sig->hasthis && (i == 0)) ? type_from_stack_type (*sp) : sig->params [i - sig->hasthis];
6867
6868                 /*
6869                  * FIXME: We should use *args++ = sp [0], but that would mean the arg
6870                  * would be different than the MonoInst's used to represent arguments, and
6871                  * the ldelema implementation can't deal with that.
6872                  * Solution: When ldelema is used on an inline argument, create a var for 
6873                  * it, emit ldelema on that var, and emit the saving code below in
6874                  * inline_method () if needed.
6875                  */
6876                 temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
6877                 cfg->args [i] = temp;
6878                 /* This uses cfg->args [i] which is set by the preceeding line */
6879                 EMIT_NEW_ARGSTORE (cfg, store, i, *sp);
6880                 store->cil_code = sp [0]->cil_code;
6881                 sp++;
6882         }
6883 }
6884
6885 #define MONO_INLINE_CALLED_LIMITED_METHODS 1
6886 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
6887
6888 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6889 static gboolean
6890 check_inline_called_method_name_limit (MonoMethod *called_method)
6891 {
6892         int strncmp_result;
6893         static const char *limit = NULL;
6894         
6895         if (limit == NULL) {
6896                 const char *limit_string = g_getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
6897
6898                 if (limit_string != NULL)
6899                         limit = limit_string;
6900                 else
6901                         limit = "";
6902         }
6903
6904         if (limit [0] != '\0') {
6905                 char *called_method_name = mono_method_full_name (called_method, TRUE);
6906
6907                 strncmp_result = strncmp (called_method_name, limit, strlen (limit));
6908                 g_free (called_method_name);
6909         
6910                 //return (strncmp_result <= 0);
6911                 return (strncmp_result == 0);
6912         } else {
6913                 return TRUE;
6914         }
6915 }
6916 #endif
6917
6918 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6919 static gboolean
6920 check_inline_caller_method_name_limit (MonoMethod *caller_method)
6921 {
6922         int strncmp_result;
6923         static const char *limit = NULL;
6924         
6925         if (limit == NULL) {
6926                 const char *limit_string = g_getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
6927                 if (limit_string != NULL) {
6928                         limit = limit_string;
6929                 } else {
6930                         limit = "";
6931                 }
6932         }
6933
6934         if (limit [0] != '\0') {
6935                 char *caller_method_name = mono_method_full_name (caller_method, TRUE);
6936
6937                 strncmp_result = strncmp (caller_method_name, limit, strlen (limit));
6938                 g_free (caller_method_name);
6939         
6940                 //return (strncmp_result <= 0);
6941                 return (strncmp_result == 0);
6942         } else {
6943                 return TRUE;
6944         }
6945 }
6946 #endif
6947
6948 static void
6949 emit_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6950 {
6951         static double r8_0 = 0.0;
6952         static float r4_0 = 0.0;
6953         MonoInst *ins;
6954         int t;
6955
6956         rtype = mini_get_underlying_type (rtype);
6957         t = rtype->type;
6958
6959         if (rtype->byref) {
6960                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6961         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6962                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
6963         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6964                 MONO_EMIT_NEW_I8CONST (cfg, dreg, 0);
6965         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6966                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
6967                 ins->type = STACK_R4;
6968                 ins->inst_p0 = (void*)&r4_0;
6969                 ins->dreg = dreg;
6970                 MONO_ADD_INS (cfg->cbb, ins);
6971         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6972                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
6973                 ins->type = STACK_R8;
6974                 ins->inst_p0 = (void*)&r8_0;
6975                 ins->dreg = dreg;
6976                 MONO_ADD_INS (cfg->cbb, ins);
6977         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6978                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6979                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6980         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
6981                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6982         } else {
6983                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6984         }
6985 }
6986
6987 static void
6988 emit_dummy_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6989 {
6990         int t;
6991
6992         rtype = mini_get_underlying_type (rtype);
6993         t = rtype->type;
6994
6995         if (rtype->byref) {
6996                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_PCONST);
6997         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6998                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_ICONST);
6999         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
7000                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_I8CONST);
7001         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
7002                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R4CONST);
7003         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
7004                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R8CONST);
7005         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
7006                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
7007                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
7008         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
7009                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
7010         } else {
7011                 emit_init_rvar (cfg, dreg, rtype);
7012         }
7013 }
7014
7015 /* If INIT is FALSE, emit dummy initialization statements to keep the IR valid */
7016 static void
7017 emit_init_local (MonoCompile *cfg, int local, MonoType *type, gboolean init)
7018 {
7019         MonoInst *var = cfg->locals [local];
7020         if (COMPILE_SOFT_FLOAT (cfg)) {
7021                 MonoInst *store;
7022                 int reg = alloc_dreg (cfg, (MonoStackType)var->type);
7023                 emit_init_rvar (cfg, reg, type);
7024                 EMIT_NEW_LOCSTORE (cfg, store, local, cfg->cbb->last_ins);
7025         } else {
7026                 if (init)
7027                         emit_init_rvar (cfg, var->dreg, type);
7028                 else
7029                         emit_dummy_init_rvar (cfg, var->dreg, type);
7030         }
7031 }
7032
7033 /*
7034  * inline_method:
7035  *
7036  *   Return the cost of inlining CMETHOD.
7037  */
7038 static int
7039 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
7040                            guchar *ip, guint real_offset, gboolean inline_always)
7041 {
7042         MonoInst *ins, *rvar = NULL;
7043         MonoMethodHeader *cheader;
7044         MonoBasicBlock *ebblock, *sbblock;
7045         int i, costs;
7046         MonoMethod *prev_inlined_method;
7047         MonoInst **prev_locals, **prev_args;
7048         MonoType **prev_arg_types;
7049         guint prev_real_offset;
7050         GHashTable *prev_cbb_hash;
7051         MonoBasicBlock **prev_cil_offset_to_bb;
7052         MonoBasicBlock *prev_cbb;
7053         unsigned char* prev_cil_start;
7054         guint32 prev_cil_offset_to_bb_len;
7055         MonoMethod *prev_current_method;
7056         MonoGenericContext *prev_generic_context;
7057         gboolean ret_var_set, prev_ret_var_set, prev_disable_inline, virtual_ = FALSE;
7058
7059         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
7060
7061 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
7062         if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod))
7063                 return 0;
7064 #endif
7065 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
7066         if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method))
7067                 return 0;
7068 #endif
7069
7070         if (!fsig)
7071                 fsig = mono_method_signature (cmethod);
7072
7073         if (cfg->verbose_level > 2)
7074                 printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
7075
7076         if (!cmethod->inline_info) {
7077                 cfg->stat_inlineable_methods++;
7078                 cmethod->inline_info = 1;
7079         }
7080
7081         /* allocate local variables */
7082         cheader = mono_method_get_header (cmethod);
7083
7084         if (cheader == NULL || mono_loader_get_last_error ()) {
7085                 MonoLoaderError *error = mono_loader_get_last_error ();
7086
7087                 if (cheader)
7088                         mono_metadata_free_mh (cheader);
7089                 if (inline_always && error)
7090                         mono_cfg_set_exception (cfg, error->exception_type);
7091
7092                 mono_loader_clear_error ();
7093                 return 0;
7094         }
7095
7096         /*Must verify before creating locals as it can cause the JIT to assert.*/
7097         if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
7098                 mono_metadata_free_mh (cheader);
7099                 return 0;
7100         }
7101
7102         /* allocate space to store the return value */
7103         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
7104                 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
7105         }
7106
7107         prev_locals = cfg->locals;
7108         cfg->locals = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));
7109         for (i = 0; i < cheader->num_locals; ++i)
7110                 cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
7111
7112         /* allocate start and end blocks */
7113         /* This is needed so if the inline is aborted, we can clean up */
7114         NEW_BBLOCK (cfg, sbblock);
7115         sbblock->real_offset = real_offset;
7116
7117         NEW_BBLOCK (cfg, ebblock);
7118         ebblock->block_num = cfg->num_bblocks++;
7119         ebblock->real_offset = real_offset;
7120
7121         prev_args = cfg->args;
7122         prev_arg_types = cfg->arg_types;
7123         prev_inlined_method = cfg->inlined_method;
7124         cfg->inlined_method = cmethod;
7125         cfg->ret_var_set = FALSE;
7126         cfg->inline_depth ++;
7127         prev_real_offset = cfg->real_offset;
7128         prev_cbb_hash = cfg->cbb_hash;
7129         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
7130         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
7131         prev_cil_start = cfg->cil_start;
7132         prev_cbb = cfg->cbb;
7133         prev_current_method = cfg->current_method;
7134         prev_generic_context = cfg->generic_context;
7135         prev_ret_var_set = cfg->ret_var_set;
7136         prev_disable_inline = cfg->disable_inline;
7137
7138         if (ip && *ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
7139                 virtual_ = TRUE;
7140
7141         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, sp, real_offset, virtual_);
7142
7143         ret_var_set = cfg->ret_var_set;
7144
7145         cfg->inlined_method = prev_inlined_method;
7146         cfg->real_offset = prev_real_offset;
7147         cfg->cbb_hash = prev_cbb_hash;
7148         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
7149         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
7150         cfg->cil_start = prev_cil_start;
7151         cfg->locals = prev_locals;
7152         cfg->args = prev_args;
7153         cfg->arg_types = prev_arg_types;
7154         cfg->current_method = prev_current_method;
7155         cfg->generic_context = prev_generic_context;
7156         cfg->ret_var_set = prev_ret_var_set;
7157         cfg->disable_inline = prev_disable_inline;
7158         cfg->inline_depth --;
7159
7160         if ((costs >= 0 && costs < 60) || inline_always || (costs >= 0 && (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))) {
7161                 if (cfg->verbose_level > 2)
7162                         printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
7163                 
7164                 cfg->stat_inlined_methods++;
7165
7166                 /* always add some code to avoid block split failures */
7167                 MONO_INST_NEW (cfg, ins, OP_NOP);
7168                 MONO_ADD_INS (prev_cbb, ins);
7169
7170                 prev_cbb->next_bb = sbblock;
7171                 link_bblock (cfg, prev_cbb, sbblock);
7172
7173                 /* 
7174                  * Get rid of the begin and end bblocks if possible to aid local
7175                  * optimizations.
7176                  */
7177                 mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
7178
7179                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
7180                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
7181
7182                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
7183                         MonoBasicBlock *prev = ebblock->in_bb [0];
7184                         mono_merge_basic_blocks (cfg, prev, ebblock);
7185                         cfg->cbb = prev;
7186                         if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
7187                                 mono_merge_basic_blocks (cfg, prev_cbb, prev);
7188                                 cfg->cbb = prev_cbb;
7189                         }
7190                 } else {
7191                         /* 
7192                          * Its possible that the rvar is set in some prev bblock, but not in others.
7193                          * (#1835).
7194                          */
7195                         if (rvar) {
7196                                 MonoBasicBlock *bb;
7197
7198                                 for (i = 0; i < ebblock->in_count; ++i) {
7199                                         bb = ebblock->in_bb [i];
7200
7201                                         if (bb->last_ins && bb->last_ins->opcode == OP_NOT_REACHED) {
7202                                                 cfg->cbb = bb;
7203
7204                                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
7205                                         }
7206                                 }
7207                         }
7208
7209                         cfg->cbb = ebblock;
7210                 }
7211
7212                 if (rvar) {
7213                         /*
7214                          * If the inlined method contains only a throw, then the ret var is not 
7215                          * set, so set it to a dummy value.
7216                          */
7217                         if (!ret_var_set)
7218                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
7219
7220                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
7221                         *sp++ = ins;
7222                 }
7223                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
7224                 return costs + 1;
7225         } else {
7226                 if (cfg->verbose_level > 2)
7227                         printf ("INLINE ABORTED %s (cost %d)\n", mono_method_full_name (cmethod, TRUE), costs);
7228                 cfg->exception_type = MONO_EXCEPTION_NONE;
7229                 mono_loader_clear_error ();
7230
7231                 /* This gets rid of the newly added bblocks */
7232                 cfg->cbb = prev_cbb;
7233         }
7234         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
7235         return 0;
7236 }
7237
7238 /*
7239  * Some of these comments may well be out-of-date.
7240  * Design decisions: we do a single pass over the IL code (and we do bblock 
7241  * splitting/merging in the few cases when it's required: a back jump to an IL
7242  * address that was not already seen as bblock starting point).
7243  * Code is validated as we go (full verification is still better left to metadata/verify.c).
7244  * Complex operations are decomposed in simpler ones right away. We need to let the 
7245  * arch-specific code peek and poke inside this process somehow (except when the 
7246  * optimizations can take advantage of the full semantic info of coarse opcodes).
7247  * All the opcodes of the form opcode.s are 'normalized' to opcode.
7248  * MonoInst->opcode initially is the IL opcode or some simplification of that 
7249  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
7250  * opcode with value bigger than OP_LAST.
7251  * At this point the IR can be handed over to an interpreter, a dumb code generator
7252  * or to the optimizing code generator that will translate it to SSA form.
7253  *
7254  * Profiling directed optimizations.
7255  * We may compile by default with few or no optimizations and instrument the code
7256  * or the user may indicate what methods to optimize the most either in a config file
7257  * or through repeated runs where the compiler applies offline the optimizations to 
7258  * each method and then decides if it was worth it.
7259  */
7260
7261 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
7262 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
7263 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
7264 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
7265 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
7266 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
7267 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
7268 #define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) TYPE_LOAD_ERROR ((klass))
7269
7270 /* offset from br.s -> br like opcodes */
7271 #define BIG_BRANCH_OFFSET 13
7272
7273 static gboolean
7274 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
7275 {
7276         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
7277
7278         return b == NULL || b == bb;
7279 }
7280
7281 static int
7282 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
7283 {
7284         unsigned char *ip = start;
7285         unsigned char *target;
7286         int i;
7287         guint cli_addr;
7288         MonoBasicBlock *bblock;
7289         const MonoOpcode *opcode;
7290
7291         while (ip < end) {
7292                 cli_addr = ip - start;
7293                 i = mono_opcode_value ((const guint8 **)&ip, end);
7294                 if (i < 0)
7295                         UNVERIFIED;
7296                 opcode = &mono_opcodes [i];
7297                 switch (opcode->argument) {
7298                 case MonoInlineNone:
7299                         ip++; 
7300                         break;
7301                 case MonoInlineString:
7302                 case MonoInlineType:
7303                 case MonoInlineField:
7304                 case MonoInlineMethod:
7305                 case MonoInlineTok:
7306                 case MonoInlineSig:
7307                 case MonoShortInlineR:
7308                 case MonoInlineI:
7309                         ip += 5;
7310                         break;
7311                 case MonoInlineVar:
7312                         ip += 3;
7313                         break;
7314                 case MonoShortInlineVar:
7315                 case MonoShortInlineI:
7316                         ip += 2;
7317                         break;
7318                 case MonoShortInlineBrTarget:
7319                         target = start + cli_addr + 2 + (signed char)ip [1];
7320                         GET_BBLOCK (cfg, bblock, target);
7321                         ip += 2;
7322                         if (ip < end)
7323                                 GET_BBLOCK (cfg, bblock, ip);
7324                         break;
7325                 case MonoInlineBrTarget:
7326                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
7327                         GET_BBLOCK (cfg, bblock, target);
7328                         ip += 5;
7329                         if (ip < end)
7330                                 GET_BBLOCK (cfg, bblock, ip);
7331                         break;
7332                 case MonoInlineSwitch: {
7333                         guint32 n = read32 (ip + 1);
7334                         guint32 j;
7335                         ip += 5;
7336                         cli_addr += 5 + 4 * n;
7337                         target = start + cli_addr;
7338                         GET_BBLOCK (cfg, bblock, target);
7339                         
7340                         for (j = 0; j < n; ++j) {
7341                                 target = start + cli_addr + (gint32)read32 (ip);
7342                                 GET_BBLOCK (cfg, bblock, target);
7343                                 ip += 4;
7344                         }
7345                         break;
7346                 }
7347                 case MonoInlineR:
7348                 case MonoInlineI8:
7349                         ip += 9;
7350                         break;
7351                 default:
7352                         g_assert_not_reached ();
7353                 }
7354
7355                 if (i == CEE_THROW) {
7356                         unsigned char *bb_start = ip - 1;
7357                         
7358                         /* Find the start of the bblock containing the throw */
7359                         bblock = NULL;
7360                         while ((bb_start >= start) && !bblock) {
7361                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
7362                                 bb_start --;
7363                         }
7364                         if (bblock)
7365                                 bblock->out_of_line = 1;
7366                 }
7367         }
7368         return 0;
7369 unverified:
7370 exception_exit:
7371         *pos = ip;
7372         return 1;
7373 }
7374
7375 static inline MonoMethod *
7376 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
7377 {
7378         MonoMethod *method;
7379
7380         if (m->wrapper_type != MONO_WRAPPER_NONE) {
7381                 method = (MonoMethod *)mono_method_get_wrapper_data (m, token);
7382                 if (context) {
7383                         MonoError error;
7384                         method = mono_class_inflate_generic_method_checked (method, context, &error);
7385                         g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
7386                 }
7387         } else {
7388                 method = mono_get_method_full (m->klass->image, token, klass, context);
7389         }
7390
7391         return method;
7392 }
7393
7394 static inline MonoMethod *
7395 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
7396 {
7397         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context);
7398
7399         if (method && cfg && !cfg->gshared && mono_class_is_open_constructed_type (&method->klass->byval_arg))
7400                 return NULL;
7401
7402         return method;
7403 }
7404
7405 static inline MonoClass*
7406 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
7407 {
7408         MonoError error;
7409         MonoClass *klass;
7410
7411         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7412                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
7413                 if (context)
7414                         klass = mono_class_inflate_generic_class (klass, context);
7415         } else {
7416                 klass = mono_class_get_and_inflate_typespec_checked (method->klass->image, token, context, &error);
7417                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
7418         }
7419         if (klass)
7420                 mono_class_init (klass);
7421         return klass;
7422 }
7423
7424 static inline MonoMethodSignature*
7425 mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context)
7426 {
7427         MonoMethodSignature *fsig;
7428
7429         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7430                 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
7431         } else {
7432                 fsig = mono_metadata_parse_signature (method->klass->image, token);
7433         }
7434         if (context) {
7435                 MonoError error;
7436                 fsig = mono_inflate_generic_signature(fsig, context, &error);
7437                 // FIXME:
7438                 g_assert(mono_error_ok(&error));
7439         }
7440         return fsig;
7441 }
7442
7443 static MonoMethod*
7444 throw_exception (void)
7445 {
7446         static MonoMethod *method = NULL;
7447
7448         if (!method) {
7449                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
7450                 method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
7451         }
7452         g_assert (method);
7453         return method;
7454 }
7455
7456 static void
7457 emit_throw_exception (MonoCompile *cfg, MonoException *ex)
7458 {
7459         MonoMethod *thrower = throw_exception ();
7460         MonoInst *args [1];
7461
7462         EMIT_NEW_PCONST (cfg, args [0], ex);
7463         mono_emit_method_call (cfg, thrower, args, NULL);
7464 }
7465
7466 /*
7467  * Return the original method is a wrapper is specified. We can only access 
7468  * the custom attributes from the original method.
7469  */
7470 static MonoMethod*
7471 get_original_method (MonoMethod *method)
7472 {
7473         if (method->wrapper_type == MONO_WRAPPER_NONE)
7474                 return method;
7475
7476         /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
7477         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
7478                 return NULL;
7479
7480         /* in other cases we need to find the original method */
7481         return mono_marshal_method_from_wrapper (method);
7482 }
7483
7484 static void
7485 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field)
7486 {
7487         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7488         MonoException *ex = mono_security_core_clr_is_field_access_allowed (get_original_method (caller), field);
7489         if (ex)
7490                 emit_throw_exception (cfg, ex);
7491 }
7492
7493 static void
7494 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
7495 {
7496         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7497         MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
7498         if (ex)
7499                 emit_throw_exception (cfg, ex);
7500 }
7501
7502 /*
7503  * Check that the IL instructions at ip are the array initialization
7504  * sequence and return the pointer to the data and the size.
7505  */
7506 static const char*
7507 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
7508 {
7509         /*
7510          * newarr[System.Int32]
7511          * dup
7512          * ldtoken field valuetype ...
7513          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
7514          */
7515         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
7516                 MonoError error;
7517                 guint32 token = read32 (ip + 7);
7518                 guint32 field_token = read32 (ip + 2);
7519                 guint32 field_index = field_token & 0xffffff;
7520                 guint32 rva;
7521                 const char *data_ptr;
7522                 int size = 0;
7523                 MonoMethod *cmethod;
7524                 MonoClass *dummy_class;
7525                 MonoClassField *field = mono_field_from_token_checked (method->klass->image, field_token, &dummy_class, NULL, &error);
7526                 int dummy_align;
7527
7528                 if (!field) {
7529                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7530                         return NULL;
7531                 }
7532
7533                 *out_field_token = field_token;
7534
7535                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
7536                 if (!cmethod)
7537                         return NULL;
7538                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
7539                         return NULL;
7540                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
7541                 case MONO_TYPE_BOOLEAN:
7542                 case MONO_TYPE_I1:
7543                 case MONO_TYPE_U1:
7544                         size = 1; break;
7545                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
7546 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
7547                 case MONO_TYPE_CHAR:
7548                 case MONO_TYPE_I2:
7549                 case MONO_TYPE_U2:
7550                         size = 2; break;
7551                 case MONO_TYPE_I4:
7552                 case MONO_TYPE_U4:
7553                 case MONO_TYPE_R4:
7554                         size = 4; break;
7555                 case MONO_TYPE_R8:
7556                 case MONO_TYPE_I8:
7557                 case MONO_TYPE_U8:
7558                         size = 8; break;
7559 #endif
7560                 default:
7561                         return NULL;
7562                 }
7563                 size *= len;
7564                 if (size > mono_type_size (field->type, &dummy_align))
7565                     return NULL;
7566                 *out_size = size;
7567                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
7568                 if (!image_is_dynamic (method->klass->image)) {
7569                         field_index = read32 (ip + 2) & 0xffffff;
7570                         mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
7571                         data_ptr = mono_image_rva_map (method->klass->image, rva);
7572                         /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
7573                         /* for aot code we do the lookup on load */
7574                         if (aot && data_ptr)
7575                                 return (const char *)GUINT_TO_POINTER (rva);
7576                 } else {
7577                         /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
7578                         g_assert (!aot);
7579                         data_ptr = mono_field_get_data (field);
7580                 }
7581                 return data_ptr;
7582         }
7583         return NULL;
7584 }
7585
7586 static void
7587 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
7588 {
7589         char *method_fname = mono_method_full_name (method, TRUE);
7590         char *method_code;
7591         MonoMethodHeader *header = mono_method_get_header (method);
7592
7593         if (header->code_size == 0)
7594                 method_code = g_strdup ("method body is empty.");
7595         else
7596                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
7597         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
7598         cfg->exception_message = g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code);
7599         g_free (method_fname);
7600         g_free (method_code);
7601         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
7602 }
7603
7604 static void
7605 set_exception_object (MonoCompile *cfg, MonoException *exception)
7606 {
7607         mono_cfg_set_exception (cfg, MONO_EXCEPTION_OBJECT_SUPPLIED);
7608         MONO_GC_REGISTER_ROOT_SINGLE (cfg->exception_ptr, MONO_ROOT_SOURCE_JIT, "jit exception");
7609         cfg->exception_ptr = exception;
7610 }
7611
7612 static void
7613 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
7614 {
7615         MonoInst *ins;
7616         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
7617         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
7618                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
7619                 /* Optimize reg-reg moves away */
7620                 /* 
7621                  * Can't optimize other opcodes, since sp[0] might point to
7622                  * the last ins of a decomposed opcode.
7623                  */
7624                 sp [0]->dreg = (cfg)->locals [n]->dreg;
7625         } else {
7626                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
7627         }
7628 }
7629
7630 /*
7631  * ldloca inhibits many optimizations so try to get rid of it in common
7632  * cases.
7633  */
7634 static inline unsigned char *
7635 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
7636 {
7637         int local, token;
7638         MonoClass *klass;
7639         MonoType *type;
7640
7641         if (size == 1) {
7642                 local = ip [1];
7643                 ip += 2;
7644         } else {
7645                 local = read16 (ip + 2);
7646                 ip += 4;
7647         }
7648         
7649         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
7650                 /* From the INITOBJ case */
7651                 token = read32 (ip + 2);
7652                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
7653                 CHECK_TYPELOAD (klass);
7654                 type = mini_get_underlying_type (&klass->byval_arg);
7655                 emit_init_local (cfg, local, type, TRUE);
7656                 return ip + 6;
7657         }
7658  exception_exit:
7659         return NULL;
7660 }
7661
7662 static MonoInst*
7663 emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used, MonoInst **sp)
7664 {
7665         MonoInst *icall_args [16];
7666         MonoInst *call_target, *ins, *vtable_ins;
7667         int arg_reg, this_reg, vtable_reg;
7668         gboolean is_iface = cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE;
7669         gboolean is_gsharedvt = cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig);
7670         gboolean variant_iface = FALSE;
7671         guint32 slot;
7672         int offset;
7673
7674         /*
7675          * In llvm-only mode, vtables contain function descriptors instead of
7676          * method addresses/trampolines.
7677          */
7678         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
7679
7680         if (is_iface)
7681                 slot = mono_method_get_imt_slot (cmethod);
7682         else
7683                 slot = mono_method_get_vtable_index (cmethod);
7684
7685         this_reg = sp [0]->dreg;
7686
7687         if (is_iface && mono_class_has_variant_generic_params (cmethod->klass))
7688                 variant_iface = TRUE;
7689
7690         if (!fsig->generic_param_count && !is_iface && !is_gsharedvt) {
7691                 /*
7692                  * The simplest case, a normal virtual call.
7693                  */
7694                 int slot_reg = alloc_preg (cfg);
7695                 int addr_reg = alloc_preg (cfg);
7696                 int arg_reg = alloc_preg (cfg);
7697                 MonoBasicBlock *non_null_bb;
7698
7699                 vtable_reg = alloc_preg (cfg);
7700                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7701                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) + (slot * SIZEOF_VOID_P);
7702
7703                 /* Load the vtable slot, which contains a function descriptor. */
7704                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7705
7706                 NEW_BBLOCK (cfg, non_null_bb);
7707
7708                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, slot_reg, 0);
7709                 cfg->cbb->last_ins->flags |= MONO_INST_LIKELY;
7710                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, non_null_bb);
7711
7712                 /* Slow path */
7713                 // FIXME: Make the wrapper use the preserveall cconv
7714                 // FIXME: Use one icall per slot for small slot numbers ?
7715                 icall_args [0] = vtable_ins;
7716                 EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7717                 /* Make the icall return the vtable slot value to save some code space */
7718                 ins = mono_emit_jit_icall (cfg, mono_init_vtable_slot, icall_args);
7719                 ins->dreg = slot_reg;
7720                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, non_null_bb);
7721
7722                 /* Fastpath */
7723                 MONO_START_BB (cfg, non_null_bb);
7724                 /* Load the address + arg from the vtable slot */
7725                 EMIT_NEW_LOAD_MEMBASE (cfg, call_target, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7726                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, arg_reg, slot_reg, SIZEOF_VOID_P);
7727
7728                 return emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
7729         }
7730
7731         if (!fsig->generic_param_count && is_iface && !variant_iface && !is_gsharedvt) {
7732                 /*
7733                  * A simple interface call
7734                  *
7735                  * We make a call through an imt slot to obtain the function descriptor we need to call.
7736                  * The imt slot contains a function descriptor for a runtime function + arg.
7737                  */
7738                 int slot_reg = alloc_preg (cfg);
7739                 int addr_reg = alloc_preg (cfg);
7740                 int arg_reg = alloc_preg (cfg);
7741                 MonoInst *thunk_addr_ins, *thunk_arg_ins, *ftndesc_ins;
7742
7743                 vtable_reg = alloc_preg (cfg);
7744                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7745                 offset = ((gint32)slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
7746
7747                 /*
7748                  * The slot is already initialized when the vtable is created so there is no need
7749                  * to check it here.
7750                  */
7751
7752                 /* Load the imt slot, which contains a function descriptor. */
7753                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7754
7755                 /* Load the address + arg of the imt thunk from the imt slot */
7756                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_addr_ins, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7757                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_arg_ins, OP_LOAD_MEMBASE, arg_reg, slot_reg, SIZEOF_VOID_P);
7758                 /*
7759                  * IMT thunks in llvm-only mode are C functions which take an info argument
7760                  * plus the imt method and return the ftndesc to call.
7761                  */
7762                 icall_args [0] = thunk_arg_ins;
7763                 icall_args [1] = emit_get_rgctx_method (cfg, context_used,
7764                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7765                 ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_thunk, icall_args, thunk_addr_ins, NULL, NULL);
7766
7767                 return emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
7768         }
7769
7770         if ((fsig->generic_param_count || variant_iface) && !is_gsharedvt) {
7771                 /*
7772                  * This is similar to the interface case, the vtable slot points to an imt thunk which is
7773                  * dynamically extended as more instantiations are discovered.
7774                  * This handles generic virtual methods both on classes and interfaces.
7775                  */
7776                 int slot_reg = alloc_preg (cfg);
7777                 int addr_reg = alloc_preg (cfg);
7778                 int arg_reg = alloc_preg (cfg);
7779                 int ftndesc_reg = alloc_preg (cfg);
7780                 MonoInst *thunk_addr_ins, *thunk_arg_ins, *ftndesc_ins;
7781                 MonoBasicBlock *slowpath_bb, *end_bb;
7782
7783                 NEW_BBLOCK (cfg, slowpath_bb);
7784                 NEW_BBLOCK (cfg, end_bb);
7785
7786                 vtable_reg = alloc_preg (cfg);
7787                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7788                 if (is_iface)
7789                         offset = ((gint32)slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
7790                 else
7791                         offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) + (slot * SIZEOF_VOID_P);
7792
7793                 /* Load the slot, which contains a function descriptor. */
7794                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7795
7796                 /* These slots are not initialized, so fall back to the slow path until they are initialized */
7797                 /* That happens when mono_method_add_generic_virtual_invocation () creates an IMT thunk */
7798                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, slot_reg, 0);
7799                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, slowpath_bb);
7800
7801                 /* Fastpath */
7802                 /* Same as with iface calls */
7803                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_addr_ins, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7804                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_arg_ins, OP_LOAD_MEMBASE, arg_reg, slot_reg, SIZEOF_VOID_P);
7805                 icall_args [0] = thunk_arg_ins;
7806                 icall_args [1] = emit_get_rgctx_method (cfg, context_used,
7807                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7808                 ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_thunk, icall_args, thunk_addr_ins, NULL, NULL);
7809                 ftndesc_ins->dreg = ftndesc_reg;
7810                 /*
7811                  * Unlike normal iface calls, these imt thunks can return NULL, i.e. when they are passed an instantiation
7812                  * they don't know about yet. Fall back to the slowpath in that case.
7813                  */
7814                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ftndesc_reg, 0);
7815                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, slowpath_bb);
7816
7817                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
7818
7819                 /* Slowpath */
7820                 MONO_START_BB (cfg, slowpath_bb);
7821                 icall_args [0] = vtable_ins;
7822                 EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7823                 icall_args [2] = emit_get_rgctx_method (cfg, context_used,
7824                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7825                 if (is_iface)
7826                         ftndesc_ins = mono_emit_jit_icall (cfg, mono_resolve_generic_virtual_iface_call, icall_args);
7827                 else
7828                         ftndesc_ins = mono_emit_jit_icall (cfg, mono_resolve_generic_virtual_call, icall_args);
7829                 ftndesc_ins->dreg = ftndesc_reg;
7830                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
7831
7832                 /* Common case */
7833                 MONO_START_BB (cfg, end_bb);
7834                 return emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
7835         }
7836
7837         /*
7838          * Non-optimized cases
7839          */
7840         icall_args [0] = sp [0];
7841         EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7842
7843         icall_args [2] = emit_get_rgctx_method (cfg, context_used,
7844                                                                                         cmethod, MONO_RGCTX_INFO_METHOD);
7845
7846         arg_reg = alloc_preg (cfg);
7847         MONO_EMIT_NEW_PCONST (cfg, arg_reg, NULL);
7848         EMIT_NEW_VARLOADA_VREG (cfg, icall_args [3], arg_reg, &mono_defaults.int_class->byval_arg);
7849
7850         g_assert (is_gsharedvt);
7851         if (is_iface)
7852                 call_target = mono_emit_jit_icall (cfg, mono_resolve_iface_call_gsharedvt, icall_args);
7853         else
7854                 call_target = mono_emit_jit_icall (cfg, mono_resolve_vcall_gsharedvt, icall_args);
7855
7856         /*
7857          * Pass the extra argument even if the callee doesn't receive it, most
7858          * calling conventions allow this.
7859          */
7860         return emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
7861 }
7862
7863 static gboolean
7864 is_exception_class (MonoClass *klass)
7865 {
7866         while (klass) {
7867                 if (klass == mono_defaults.exception_class)
7868                         return TRUE;
7869                 klass = klass->parent;
7870         }
7871         return FALSE;
7872 }
7873
7874 /*
7875  * is_jit_optimizer_disabled:
7876  *
7877  *   Determine whenever M's assembly has a DebuggableAttribute with the
7878  * IsJITOptimizerDisabled flag set.
7879  */
7880 static gboolean
7881 is_jit_optimizer_disabled (MonoMethod *m)
7882 {
7883         MonoAssembly *ass = m->klass->image->assembly;
7884         MonoCustomAttrInfo* attrs;
7885         static MonoClass *klass;
7886         int i;
7887         gboolean val = FALSE;
7888
7889         g_assert (ass);
7890         if (ass->jit_optimizer_disabled_inited)
7891                 return ass->jit_optimizer_disabled;
7892
7893         if (!klass)
7894                 klass = mono_class_from_name (mono_defaults.corlib, "System.Diagnostics", "DebuggableAttribute");
7895         if (!klass) {
7896                 /* Linked away */
7897                 ass->jit_optimizer_disabled = FALSE;
7898                 mono_memory_barrier ();
7899                 ass->jit_optimizer_disabled_inited = TRUE;
7900                 return FALSE;
7901         }
7902
7903         attrs = mono_custom_attrs_from_assembly (ass);
7904         if (attrs) {
7905                 for (i = 0; i < attrs->num_attrs; ++i) {
7906                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
7907                         const gchar *p;
7908                         MonoMethodSignature *sig;
7909
7910                         if (!attr->ctor || attr->ctor->klass != klass)
7911                                 continue;
7912                         /* Decode the attribute. See reflection.c */
7913                         p = (const char*)attr->data;
7914                         g_assert (read16 (p) == 0x0001);
7915                         p += 2;
7916
7917                         // FIXME: Support named parameters
7918                         sig = mono_method_signature (attr->ctor);
7919                         if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
7920                                 continue;
7921                         /* Two boolean arguments */
7922                         p ++;
7923                         val = *p;
7924                 }
7925                 mono_custom_attrs_free (attrs);
7926         }
7927
7928         ass->jit_optimizer_disabled = val;
7929         mono_memory_barrier ();
7930         ass->jit_optimizer_disabled_inited = TRUE;
7931
7932         return val;
7933 }
7934
7935 static gboolean
7936 is_supported_tail_call (MonoCompile *cfg, MonoMethod *method, MonoMethod *cmethod, MonoMethodSignature *fsig, int call_opcode)
7937 {
7938         gboolean supported_tail_call;
7939         int i;
7940
7941         supported_tail_call = mono_arch_tail_call_supported (cfg, mono_method_signature (method), mono_method_signature (cmethod));
7942
7943         for (i = 0; i < fsig->param_count; ++i) {
7944                 if (fsig->params [i]->byref || fsig->params [i]->type == MONO_TYPE_PTR || fsig->params [i]->type == MONO_TYPE_FNPTR)
7945                         /* These can point to the current method's stack */
7946                         supported_tail_call = FALSE;
7947         }
7948         if (fsig->hasthis && cmethod->klass->valuetype)
7949                 /* this might point to the current method's stack */
7950                 supported_tail_call = FALSE;
7951         if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
7952                 supported_tail_call = FALSE;
7953         if (cfg->method->save_lmf)
7954                 supported_tail_call = FALSE;
7955         if (cmethod->wrapper_type && cmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
7956                 supported_tail_call = FALSE;
7957         if (call_opcode != CEE_CALL)
7958                 supported_tail_call = FALSE;
7959
7960         /* Debugging support */
7961 #if 0
7962         if (supported_tail_call) {
7963                 if (!mono_debug_count ())
7964                         supported_tail_call = FALSE;
7965         }
7966 #endif
7967
7968         return supported_tail_call;
7969 }
7970
7971 /*
7972  * handle_ctor_call:
7973  *
7974  *   Handle calls made to ctors from NEWOBJ opcodes.
7975  */
7976 static void
7977 handle_ctor_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used,
7978                                   MonoInst **sp, guint8 *ip, int *inline_costs)
7979 {
7980         MonoInst *vtable_arg = NULL, *callvirt_this_arg = NULL, *ins;
7981
7982         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
7983                                         mono_method_is_generic_sharable (cmethod, TRUE)) {
7984                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
7985                         mono_class_vtable (cfg->domain, cmethod->klass);
7986                         CHECK_TYPELOAD (cmethod->klass);
7987
7988                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
7989                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
7990                 } else {
7991                         if (context_used) {
7992                                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
7993                                                                                                    cmethod->klass, MONO_RGCTX_INFO_VTABLE);
7994                         } else {
7995                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
7996
7997                                 CHECK_TYPELOAD (cmethod->klass);
7998                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
7999                         }
8000                 }
8001         }
8002
8003         /* Avoid virtual calls to ctors if possible */
8004         if (mono_class_is_marshalbyref (cmethod->klass))
8005                 callvirt_this_arg = sp [0];
8006
8007         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
8008                 g_assert (MONO_TYPE_IS_VOID (fsig->ret));
8009                 CHECK_CFG_EXCEPTION;
8010         } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
8011                            mono_method_check_inlining (cfg, cmethod) &&
8012                            !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE)) {
8013                 int costs;
8014
8015                 if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, FALSE))) {
8016                         cfg->real_offset += 5;
8017
8018                         *inline_costs += costs - 5;
8019                 } else {
8020                         INLINE_FAILURE ("inline failure");
8021                         // FIXME-VT: Clean this up
8022                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
8023                                 GSHAREDVT_FAILURE(*ip);
8024                         mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, callvirt_this_arg, NULL, NULL);
8025                 }
8026         } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
8027                 MonoInst *addr;
8028
8029                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
8030
8031                 if (cfg->llvm_only) {
8032                         // FIXME: Avoid initializing vtable_arg
8033                         emit_llvmonly_calli (cfg, fsig, sp, addr);
8034                 } else {
8035                         mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
8036                 }
8037         } else if (context_used &&
8038                            ((!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
8039                                  !mono_class_generic_sharing_enabled (cmethod->klass)) || cfg->gsharedvt)) {
8040                 MonoInst *cmethod_addr;
8041
8042                 /* Generic calls made out of gsharedvt methods cannot be patched, so use an indirect call */
8043
8044                 if (cfg->llvm_only) {
8045                         MonoInst *addr = emit_get_rgctx_method (cfg, context_used, cmethod,
8046                                                                                                         MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
8047                         emit_llvmonly_calli (cfg, fsig, sp, addr);
8048                 } else {
8049                         cmethod_addr = emit_get_rgctx_method (cfg, context_used,
8050                                                                                                   cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
8051
8052                         mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
8053                 }
8054         } else {
8055                 INLINE_FAILURE ("ctor call");
8056                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
8057                                                                                   callvirt_this_arg, NULL, vtable_arg);
8058         }
8059  exception_exit:
8060         return;
8061 }
8062
8063 static void
8064 emit_setret (MonoCompile *cfg, MonoInst *val)
8065 {
8066         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (cfg->method)->ret);
8067         MonoInst *ins;
8068
8069         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
8070                 MonoInst *ret_addr;
8071
8072                 if (!cfg->vret_addr) {
8073                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, val);
8074                 } else {
8075                         EMIT_NEW_RETLOADA (cfg, ret_addr);
8076
8077                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, val->dreg);
8078                         ins->klass = mono_class_from_mono_type (ret_type);
8079                 }
8080         } else {
8081 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
8082                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
8083                         MonoInst *iargs [1];
8084                         MonoInst *conv;
8085
8086                         iargs [0] = val;
8087                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
8088                         mono_arch_emit_setret (cfg, cfg->method, conv);
8089                 } else {
8090                         mono_arch_emit_setret (cfg, cfg->method, val);
8091                 }
8092 #else
8093                 mono_arch_emit_setret (cfg, cfg->method, val);
8094 #endif
8095         }
8096 }
8097
8098 /*
8099  * mono_method_to_ir:
8100  *
8101  *   Translate the .net IL into linear IR.
8102  */
8103 int
8104 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
8105                    MonoInst *return_var, MonoInst **inline_args, 
8106                    guint inline_offset, gboolean is_virtual_call)
8107 {
8108         MonoError error;
8109         MonoInst *ins, **sp, **stack_start;
8110         MonoBasicBlock *tblock = NULL, *init_localsbb = NULL;
8111         MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
8112         MonoMethod *cmethod, *method_definition;
8113         MonoInst **arg_array;
8114         MonoMethodHeader *header;
8115         MonoImage *image;
8116         guint32 token, ins_flag;
8117         MonoClass *klass;
8118         MonoClass *constrained_class = NULL;
8119         unsigned char *ip, *end, *target, *err_pos;
8120         MonoMethodSignature *sig;
8121         MonoGenericContext *generic_context = NULL;
8122         MonoGenericContainer *generic_container = NULL;
8123         MonoType **param_types;
8124         int i, n, start_new_bblock, dreg;
8125         int num_calls = 0, inline_costs = 0;
8126         int breakpoint_id = 0;
8127         guint num_args;
8128         GSList *class_inits = NULL;
8129         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
8130         int context_used;
8131         gboolean init_locals, seq_points, skip_dead_blocks;
8132         gboolean sym_seq_points = FALSE;
8133         MonoDebugMethodInfo *minfo;
8134         MonoBitSet *seq_point_locs = NULL;
8135         MonoBitSet *seq_point_set_locs = NULL;
8136
8137         cfg->disable_inline = is_jit_optimizer_disabled (method);
8138
8139         /* serialization and xdomain stuff may need access to private fields and methods */
8140         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
8141         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
8142         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
8143         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
8144         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
8145         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
8146
8147         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
8148         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
8149         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
8150         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
8151         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF;
8152
8153         image = method->klass->image;
8154         header = mono_method_get_header (method);
8155         if (!header) {
8156                 MonoLoaderError *error;
8157
8158                 if ((error = mono_loader_get_last_error ())) {
8159                         mono_cfg_set_exception (cfg, error->exception_type);
8160                 } else {
8161                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
8162                         cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
8163                 }
8164                 goto exception_exit;
8165         }
8166         generic_container = mono_method_get_generic_container (method);
8167         sig = mono_method_signature (method);
8168         num_args = sig->hasthis + sig->param_count;
8169         ip = (unsigned char*)header->code;
8170         cfg->cil_start = ip;
8171         end = ip + header->code_size;
8172         cfg->stat_cil_code_size += header->code_size;
8173
8174         seq_points = cfg->gen_seq_points && cfg->method == method;
8175
8176         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
8177                 /* We could hit a seq point before attaching to the JIT (#8338) */
8178                 seq_points = FALSE;
8179         }
8180
8181         if (cfg->gen_sdb_seq_points && cfg->method == method) {
8182                 minfo = mono_debug_lookup_method (method);
8183                 if (minfo) {
8184                         MonoSymSeqPoint *sps;
8185                         int i, n_il_offsets;
8186
8187                         mono_debug_get_seq_points (minfo, NULL, NULL, NULL, &sps, &n_il_offsets);
8188                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
8189                         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);
8190                         sym_seq_points = TRUE;
8191                         for (i = 0; i < n_il_offsets; ++i) {
8192                                 if (sps [i].il_offset < header->code_size)
8193                                         mono_bitset_set_fast (seq_point_locs, sps [i].il_offset);
8194                         }
8195                         g_free (sps);
8196                 } else if (!method->wrapper_type && !method->dynamic && mono_debug_image_has_debug_info (method->klass->image)) {
8197                         /* Methods without line number info like auto-generated property accessors */
8198                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
8199                         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);
8200                         sym_seq_points = TRUE;
8201                 }
8202         }
8203
8204         /* 
8205          * Methods without init_locals set could cause asserts in various passes
8206          * (#497220). To work around this, we emit dummy initialization opcodes
8207          * (OP_DUMMY_ICONST etc.) which generate no code. These are only supported
8208          * on some platforms.
8209          */
8210         if ((cfg->opt & MONO_OPT_UNSAFE) && cfg->backend->have_dummy_init)
8211                 init_locals = header->init_locals;
8212         else
8213                 init_locals = TRUE;
8214
8215         method_definition = method;
8216         while (method_definition->is_inflated) {
8217                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
8218                 method_definition = imethod->declaring;
8219         }
8220
8221         /* SkipVerification is not allowed if core-clr is enabled */
8222         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
8223                 dont_verify = TRUE;
8224                 dont_verify_stloc = TRUE;
8225         }
8226
8227         if (sig->is_inflated)
8228                 generic_context = mono_method_get_context (method);
8229         else if (generic_container)
8230                 generic_context = &generic_container->context;
8231         cfg->generic_context = generic_context;
8232
8233         if (!cfg->gshared)
8234                 g_assert (!sig->has_type_parameters);
8235
8236         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
8237                 g_assert (method->is_inflated);
8238                 g_assert (mono_method_get_context (method)->method_inst);
8239         }
8240         if (method->is_inflated && mono_method_get_context (method)->method_inst)
8241                 g_assert (sig->generic_param_count);
8242
8243         if (cfg->method == method) {
8244                 cfg->real_offset = 0;
8245         } else {
8246                 cfg->real_offset = inline_offset;
8247         }
8248
8249         cfg->cil_offset_to_bb = (MonoBasicBlock **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
8250         cfg->cil_offset_to_bb_len = header->code_size;
8251
8252         cfg->current_method = method;
8253
8254         if (cfg->verbose_level > 2)
8255                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
8256
8257         param_types = (MonoType **)mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
8258         if (sig->hasthis)
8259                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
8260         for (n = 0; n < sig->param_count; ++n)
8261                 param_types [n + sig->hasthis] = sig->params [n];
8262         cfg->arg_types = param_types;
8263
8264         cfg->dont_inline = g_list_prepend (cfg->dont_inline, method);
8265         if (cfg->method == method) {
8266
8267                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
8268                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
8269
8270                 /* ENTRY BLOCK */
8271                 NEW_BBLOCK (cfg, start_bblock);
8272                 cfg->bb_entry = start_bblock;
8273                 start_bblock->cil_code = NULL;
8274                 start_bblock->cil_length = 0;
8275
8276                 /* EXIT BLOCK */
8277                 NEW_BBLOCK (cfg, end_bblock);
8278                 cfg->bb_exit = end_bblock;
8279                 end_bblock->cil_code = NULL;
8280                 end_bblock->cil_length = 0;
8281                 end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
8282                 g_assert (cfg->num_bblocks == 2);
8283
8284                 arg_array = cfg->args;
8285
8286                 if (header->num_clauses) {
8287                         cfg->spvars = g_hash_table_new (NULL, NULL);
8288                         cfg->exvars = g_hash_table_new (NULL, NULL);
8289                 }
8290                 /* handle exception clauses */
8291                 for (i = 0; i < header->num_clauses; ++i) {
8292                         MonoBasicBlock *try_bb;
8293                         MonoExceptionClause *clause = &header->clauses [i];
8294                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
8295
8296                         try_bb->real_offset = clause->try_offset;
8297                         try_bb->try_start = TRUE;
8298                         try_bb->region = ((i + 1) << 8) | clause->flags;
8299                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
8300                         tblock->real_offset = clause->handler_offset;
8301                         tblock->flags |= BB_EXCEPTION_HANDLER;
8302
8303                         /*
8304                          * Linking the try block with the EH block hinders inlining as we won't be able to 
8305                          * merge the bblocks from inlining and produce an artificial hole for no good reason.
8306                          */
8307                         if (COMPILE_LLVM (cfg))
8308                                 link_bblock (cfg, try_bb, tblock);
8309
8310                         if (*(ip + clause->handler_offset) == CEE_POP)
8311                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
8312
8313                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
8314                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
8315                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
8316                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
8317                                 MONO_ADD_INS (tblock, ins);
8318
8319                                 if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FILTER) {
8320                                         /* finally clauses already have a seq point */
8321                                         /* seq points for filter clauses are emitted below */
8322                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
8323                                         MONO_ADD_INS (tblock, ins);
8324                                 }
8325
8326                                 /* todo: is a fault block unsafe to optimize? */
8327                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
8328                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
8329                         }
8330
8331                         /*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);
8332                           while (p < end) {
8333                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
8334                           }*/
8335                         /* catch and filter blocks get the exception object on the stack */
8336                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
8337                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8338
8339                                 /* mostly like handle_stack_args (), but just sets the input args */
8340                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
8341                                 tblock->in_scount = 1;
8342                                 tblock->in_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
8343                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
8344
8345                                 cfg->cbb = tblock;
8346
8347 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
8348                                 /* The EH code passes in the exception in a register to both JITted and LLVM compiled code */
8349                                 if (!cfg->compile_llvm) {
8350                                         MONO_INST_NEW (cfg, ins, OP_GET_EX_OBJ);
8351                                         ins->dreg = tblock->in_stack [0]->dreg;
8352                                         MONO_ADD_INS (tblock, ins);
8353                                 }
8354 #else
8355                                 MonoInst *dummy_use;
8356
8357                                 /* 
8358                                  * Add a dummy use for the exvar so its liveness info will be
8359                                  * correct.
8360                                  */
8361                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
8362 #endif
8363
8364                                 if (seq_points && clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8365                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
8366                                         MONO_ADD_INS (tblock, ins);
8367                                 }
8368                                 
8369                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8370                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
8371                                         tblock->flags |= BB_EXCEPTION_HANDLER;
8372                                         tblock->real_offset = clause->data.filter_offset;
8373                                         tblock->in_scount = 1;
8374                                         tblock->in_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
8375                                         /* The filter block shares the exvar with the handler block */
8376                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
8377                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
8378                                         MONO_ADD_INS (tblock, ins);
8379                                 }
8380                         }
8381
8382                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
8383                                         clause->data.catch_class &&
8384                                         cfg->gshared &&
8385                                         mono_class_check_context_used (clause->data.catch_class)) {
8386                                 /*
8387                                  * In shared generic code with catch
8388                                  * clauses containing type variables
8389                                  * the exception handling code has to
8390                                  * be able to get to the rgctx.
8391                                  * Therefore we have to make sure that
8392                                  * the vtable/mrgctx argument (for
8393                                  * static or generic methods) or the
8394                                  * "this" argument (for non-static
8395                                  * methods) are live.
8396                                  */
8397                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8398                                                 mini_method_get_context (method)->method_inst ||
8399                                                 method->klass->valuetype) {
8400                                         mono_get_vtable_var (cfg);
8401                                 } else {
8402                                         MonoInst *dummy_use;
8403
8404                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
8405                                 }
8406                         }
8407                 }
8408         } else {
8409                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
8410                 cfg->cbb = start_bblock;
8411                 cfg->args = arg_array;
8412                 mono_save_args (cfg, sig, inline_args);
8413         }
8414
8415         /* FIRST CODE BLOCK */
8416         NEW_BBLOCK (cfg, tblock);
8417         tblock->cil_code = ip;
8418         cfg->cbb = tblock;
8419         cfg->ip = ip;
8420
8421         ADD_BBLOCK (cfg, tblock);
8422
8423         if (cfg->method == method) {
8424                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
8425                 if (breakpoint_id) {
8426                         MONO_INST_NEW (cfg, ins, OP_BREAK);
8427                         MONO_ADD_INS (cfg->cbb, ins);
8428                 }
8429         }
8430
8431         /* we use a separate basic block for the initialization code */
8432         NEW_BBLOCK (cfg, init_localsbb);
8433         cfg->bb_init = init_localsbb;
8434         init_localsbb->real_offset = cfg->real_offset;
8435         start_bblock->next_bb = init_localsbb;
8436         init_localsbb->next_bb = cfg->cbb;
8437         link_bblock (cfg, start_bblock, init_localsbb);
8438         link_bblock (cfg, init_localsbb, cfg->cbb);
8439                 
8440         cfg->cbb = init_localsbb;
8441
8442         if (cfg->gsharedvt && cfg->method == method) {
8443                 MonoGSharedVtMethodInfo *info;
8444                 MonoInst *var, *locals_var;
8445                 int dreg;
8446
8447                 info = (MonoGSharedVtMethodInfo *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoGSharedVtMethodInfo));
8448                 info->method = cfg->method;
8449                 info->count_entries = 16;
8450                 info->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
8451                 cfg->gsharedvt_info = info;
8452
8453                 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8454                 /* prevent it from being register allocated */
8455                 //var->flags |= MONO_INST_VOLATILE;
8456                 cfg->gsharedvt_info_var = var;
8457
8458                 ins = emit_get_rgctx_gsharedvt_method (cfg, mini_method_check_context_used (cfg, method), method, info);
8459                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, var->dreg, ins->dreg);
8460
8461                 /* Allocate locals */
8462                 locals_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8463                 /* prevent it from being register allocated */
8464                 //locals_var->flags |= MONO_INST_VOLATILE;
8465                 cfg->gsharedvt_locals_var = locals_var;
8466
8467                 dreg = alloc_ireg (cfg);
8468                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, dreg, var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, locals_size));
8469
8470                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
8471                 ins->dreg = locals_var->dreg;
8472                 ins->sreg1 = dreg;
8473                 MONO_ADD_INS (cfg->cbb, ins);
8474                 cfg->gsharedvt_locals_var_ins = ins;
8475                 
8476                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
8477                 /*
8478                 if (init_locals)
8479                         ins->flags |= MONO_INST_INIT;
8480                 */
8481         }
8482
8483         if (mono_security_core_clr_enabled ()) {
8484                 /* check if this is native code, e.g. an icall or a p/invoke */
8485                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
8486                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
8487                         if (wrapped) {
8488                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
8489                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
8490
8491                                 /* if this ia a native call then it can only be JITted from platform code */
8492                                 if ((icall || pinvk) && method->klass && method->klass->image) {
8493                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
8494                                                 MonoException *ex = icall ? mono_get_exception_security () : 
8495                                                         mono_get_exception_method_access ();
8496                                                 emit_throw_exception (cfg, ex);
8497                                         }
8498                                 }
8499                         }
8500                 }
8501         }
8502
8503         CHECK_CFG_EXCEPTION;
8504
8505         if (header->code_size == 0)
8506                 UNVERIFIED;
8507
8508         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
8509                 ip = err_pos;
8510                 UNVERIFIED;
8511         }
8512
8513         if (cfg->method == method)
8514                 mono_debug_init_method (cfg, cfg->cbb, breakpoint_id);
8515
8516         for (n = 0; n < header->num_locals; ++n) {
8517                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
8518                         UNVERIFIED;
8519         }
8520         class_inits = NULL;
8521
8522         /* We force the vtable variable here for all shared methods
8523            for the possibility that they might show up in a stack
8524            trace where their exact instantiation is needed. */
8525         if (cfg->gshared && method == cfg->method) {
8526                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8527                                 mini_method_get_context (method)->method_inst ||
8528                                 method->klass->valuetype) {
8529                         mono_get_vtable_var (cfg);
8530                 } else {
8531                         /* FIXME: Is there a better way to do this?
8532                            We need the variable live for the duration
8533                            of the whole method. */
8534                         cfg->args [0]->flags |= MONO_INST_VOLATILE;
8535                 }
8536         }
8537
8538         /* add a check for this != NULL to inlined methods */
8539         if (is_virtual_call) {
8540                 MonoInst *arg_ins;
8541
8542                 NEW_ARGLOAD (cfg, arg_ins, 0);
8543                 MONO_ADD_INS (cfg->cbb, arg_ins);
8544                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
8545         }
8546
8547         skip_dead_blocks = !dont_verify;
8548         if (skip_dead_blocks) {
8549                 original_bb = bb = mono_basic_block_split (method, &cfg->error);
8550                 CHECK_CFG_ERROR;
8551                 g_assert (bb);
8552         }
8553
8554         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
8555         stack_start = sp = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
8556
8557         ins_flag = 0;
8558         start_new_bblock = 0;
8559         while (ip < end) {
8560                 if (cfg->method == method)
8561                         cfg->real_offset = ip - header->code;
8562                 else
8563                         cfg->real_offset = inline_offset;
8564                 cfg->ip = ip;
8565
8566                 context_used = 0;
8567
8568                 if (start_new_bblock) {
8569                         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
8570                         if (start_new_bblock == 2) {
8571                                 g_assert (ip == tblock->cil_code);
8572                         } else {
8573                                 GET_BBLOCK (cfg, tblock, ip);
8574                         }
8575                         cfg->cbb->next_bb = tblock;
8576                         cfg->cbb = tblock;
8577                         start_new_bblock = 0;
8578                         for (i = 0; i < cfg->cbb->in_scount; ++i) {
8579                                 if (cfg->verbose_level > 3)
8580                                         printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8581                                 EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8582                                 *sp++ = ins;
8583                         }
8584                         if (class_inits)
8585                                 g_slist_free (class_inits);
8586                         class_inits = NULL;
8587                 } else {
8588                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != cfg->cbb)) {
8589                                 link_bblock (cfg, cfg->cbb, tblock);
8590                                 if (sp != stack_start) {
8591                                         handle_stack_args (cfg, stack_start, sp - stack_start);
8592                                         sp = stack_start;
8593                                         CHECK_UNVERIFIABLE (cfg);
8594                                 }
8595                                 cfg->cbb->next_bb = tblock;
8596                                 cfg->cbb = tblock;
8597                                 for (i = 0; i < cfg->cbb->in_scount; ++i) {
8598                                         if (cfg->verbose_level > 3)
8599                                                 printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8600                                         EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8601                                         *sp++ = ins;
8602                                 }
8603                                 g_slist_free (class_inits);
8604                                 class_inits = NULL;
8605                         }
8606                 }
8607
8608                 if (skip_dead_blocks) {
8609                         int ip_offset = ip - header->code;
8610
8611                         if (ip_offset == bb->end)
8612                                 bb = bb->next;
8613
8614                         if (bb->dead) {
8615                                 int op_size = mono_opcode_size (ip, end);
8616                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
8617
8618                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
8619
8620                                 if (ip_offset + op_size == bb->end) {
8621                                         MONO_INST_NEW (cfg, ins, OP_NOP);
8622                                         MONO_ADD_INS (cfg->cbb, ins);
8623                                         start_new_bblock = 1;
8624                                 }
8625
8626                                 ip += op_size;
8627                                 continue;
8628                         }
8629                 }
8630                 /*
8631                  * Sequence points are points where the debugger can place a breakpoint.
8632                  * Currently, we generate these automatically at points where the IL
8633                  * stack is empty.
8634                  */
8635                 if (seq_points && ((!sym_seq_points && (sp == stack_start)) || (sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code)))) {
8636                         /*
8637                          * Make methods interruptable at the beginning, and at the targets of
8638                          * backward branches.
8639                          * Also, do this at the start of every bblock in methods with clauses too,
8640                          * to be able to handle instructions with inprecise control flow like
8641                          * throw/endfinally.
8642                          * Backward branches are handled at the end of method-to-ir ().
8643                          */
8644                         gboolean intr_loc = ip == header->code || (!cfg->cbb->last_ins && cfg->header->num_clauses);
8645                         gboolean sym_seq_point = sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code);
8646
8647                         /* Avoid sequence points on empty IL like .volatile */
8648                         // FIXME: Enable this
8649                         //if (!(cfg->cbb->last_ins && cfg->cbb->last_ins->opcode == OP_SEQ_POINT)) {
8650                         NEW_SEQ_POINT (cfg, ins, ip - header->code, intr_loc);
8651                         if ((sp != stack_start) && !sym_seq_point)
8652                                 ins->flags |= MONO_INST_NONEMPTY_STACK;
8653                         MONO_ADD_INS (cfg->cbb, ins);
8654
8655                         if (sym_seq_points)
8656                                 mono_bitset_set_fast (seq_point_set_locs, ip - header->code);
8657                 }
8658
8659                 cfg->cbb->real_offset = cfg->real_offset;
8660
8661                 if ((cfg->method == method) && cfg->coverage_info) {
8662                         guint32 cil_offset = ip - header->code;
8663                         cfg->coverage_info->data [cil_offset].cil_code = ip;
8664
8665                         /* TODO: Use an increment here */
8666 #if defined(TARGET_X86)
8667                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
8668                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
8669                         ins->inst_imm = 1;
8670                         MONO_ADD_INS (cfg->cbb, ins);
8671 #else
8672                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
8673                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
8674 #endif
8675                 }
8676
8677                 if (cfg->verbose_level > 3)
8678                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
8679
8680                 switch (*ip) {
8681                 case CEE_NOP:
8682                         if (seq_points && !sym_seq_points && sp != stack_start) {
8683                                 /*
8684                                  * The C# compiler uses these nops to notify the JIT that it should
8685                                  * insert seq points.
8686                                  */
8687                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, FALSE);
8688                                 MONO_ADD_INS (cfg->cbb, ins);
8689                         }
8690                         if (cfg->keep_cil_nops)
8691                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
8692                         else
8693                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8694                         ip++;
8695                         MONO_ADD_INS (cfg->cbb, ins);
8696                         break;
8697                 case CEE_BREAK:
8698                         if (should_insert_brekpoint (cfg->method)) {
8699                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
8700                         } else {
8701                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8702                         }
8703                         ip++;
8704                         MONO_ADD_INS (cfg->cbb, ins);
8705                         break;
8706                 case CEE_LDARG_0:
8707                 case CEE_LDARG_1:
8708                 case CEE_LDARG_2:
8709                 case CEE_LDARG_3:
8710                         CHECK_STACK_OVF (1);
8711                         n = (*ip)-CEE_LDARG_0;
8712                         CHECK_ARG (n);
8713                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8714                         ip++;
8715                         *sp++ = ins;
8716                         break;
8717                 case CEE_LDLOC_0:
8718                 case CEE_LDLOC_1:
8719                 case CEE_LDLOC_2:
8720                 case CEE_LDLOC_3:
8721                         CHECK_STACK_OVF (1);
8722                         n = (*ip)-CEE_LDLOC_0;
8723                         CHECK_LOCAL (n);
8724                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8725                         ip++;
8726                         *sp++ = ins;
8727                         break;
8728                 case CEE_STLOC_0:
8729                 case CEE_STLOC_1:
8730                 case CEE_STLOC_2:
8731                 case CEE_STLOC_3: {
8732                         CHECK_STACK (1);
8733                         n = (*ip)-CEE_STLOC_0;
8734                         CHECK_LOCAL (n);
8735                         --sp;
8736                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
8737                                 UNVERIFIED;
8738                         emit_stloc_ir (cfg, sp, header, n);
8739                         ++ip;
8740                         inline_costs += 1;
8741                         break;
8742                         }
8743                 case CEE_LDARG_S:
8744                         CHECK_OPSIZE (2);
8745                         CHECK_STACK_OVF (1);
8746                         n = ip [1];
8747                         CHECK_ARG (n);
8748                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8749                         *sp++ = ins;
8750                         ip += 2;
8751                         break;
8752                 case CEE_LDARGA_S:
8753                         CHECK_OPSIZE (2);
8754                         CHECK_STACK_OVF (1);
8755                         n = ip [1];
8756                         CHECK_ARG (n);
8757                         NEW_ARGLOADA (cfg, ins, n);
8758                         MONO_ADD_INS (cfg->cbb, ins);
8759                         *sp++ = ins;
8760                         ip += 2;
8761                         break;
8762                 case CEE_STARG_S:
8763                         CHECK_OPSIZE (2);
8764                         CHECK_STACK (1);
8765                         --sp;
8766                         n = ip [1];
8767                         CHECK_ARG (n);
8768                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
8769                                 UNVERIFIED;
8770                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
8771                         ip += 2;
8772                         break;
8773                 case CEE_LDLOC_S:
8774                         CHECK_OPSIZE (2);
8775                         CHECK_STACK_OVF (1);
8776                         n = ip [1];
8777                         CHECK_LOCAL (n);
8778                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8779                         *sp++ = ins;
8780                         ip += 2;
8781                         break;
8782                 case CEE_LDLOCA_S: {
8783                         unsigned char *tmp_ip;
8784                         CHECK_OPSIZE (2);
8785                         CHECK_STACK_OVF (1);
8786                         CHECK_LOCAL (ip [1]);
8787
8788                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
8789                                 ip = tmp_ip;
8790                                 inline_costs += 1;
8791                                 break;
8792                         }
8793
8794                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
8795                         *sp++ = ins;
8796                         ip += 2;
8797                         break;
8798                 }
8799                 case CEE_STLOC_S:
8800                         CHECK_OPSIZE (2);
8801                         CHECK_STACK (1);
8802                         --sp;
8803                         CHECK_LOCAL (ip [1]);
8804                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
8805                                 UNVERIFIED;
8806                         emit_stloc_ir (cfg, sp, header, ip [1]);
8807                         ip += 2;
8808                         inline_costs += 1;
8809                         break;
8810                 case CEE_LDNULL:
8811                         CHECK_STACK_OVF (1);
8812                         EMIT_NEW_PCONST (cfg, ins, NULL);
8813                         ins->type = STACK_OBJ;
8814                         ++ip;
8815                         *sp++ = ins;
8816                         break;
8817                 case CEE_LDC_I4_M1:
8818                         CHECK_STACK_OVF (1);
8819                         EMIT_NEW_ICONST (cfg, ins, -1);
8820                         ++ip;
8821                         *sp++ = ins;
8822                         break;
8823                 case CEE_LDC_I4_0:
8824                 case CEE_LDC_I4_1:
8825                 case CEE_LDC_I4_2:
8826                 case CEE_LDC_I4_3:
8827                 case CEE_LDC_I4_4:
8828                 case CEE_LDC_I4_5:
8829                 case CEE_LDC_I4_6:
8830                 case CEE_LDC_I4_7:
8831                 case CEE_LDC_I4_8:
8832                         CHECK_STACK_OVF (1);
8833                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
8834                         ++ip;
8835                         *sp++ = ins;
8836                         break;
8837                 case CEE_LDC_I4_S:
8838                         CHECK_OPSIZE (2);
8839                         CHECK_STACK_OVF (1);
8840                         ++ip;
8841                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
8842                         ++ip;
8843                         *sp++ = ins;
8844                         break;
8845                 case CEE_LDC_I4:
8846                         CHECK_OPSIZE (5);
8847                         CHECK_STACK_OVF (1);
8848                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
8849                         ip += 5;
8850                         *sp++ = ins;
8851                         break;
8852                 case CEE_LDC_I8:
8853                         CHECK_OPSIZE (9);
8854                         CHECK_STACK_OVF (1);
8855                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
8856                         ins->type = STACK_I8;
8857                         ins->dreg = alloc_dreg (cfg, STACK_I8);
8858                         ++ip;
8859                         ins->inst_l = (gint64)read64 (ip);
8860                         MONO_ADD_INS (cfg->cbb, ins);
8861                         ip += 8;
8862                         *sp++ = ins;
8863                         break;
8864                 case CEE_LDC_R4: {
8865                         float *f;
8866                         gboolean use_aotconst = FALSE;
8867
8868 #ifdef TARGET_POWERPC
8869                         /* FIXME: Clean this up */
8870                         if (cfg->compile_aot)
8871                                 use_aotconst = TRUE;
8872 #endif
8873
8874                         /* FIXME: we should really allocate this only late in the compilation process */
8875                         f = (float *)mono_domain_alloc (cfg->domain, sizeof (float));
8876                         CHECK_OPSIZE (5);
8877                         CHECK_STACK_OVF (1);
8878
8879                         if (use_aotconst) {
8880                                 MonoInst *cons;
8881                                 int dreg;
8882
8883                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
8884
8885                                 dreg = alloc_freg (cfg);
8886                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
8887                                 ins->type = cfg->r4_stack_type;
8888                         } else {
8889                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
8890                                 ins->type = cfg->r4_stack_type;
8891                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8892                                 ins->inst_p0 = f;
8893                                 MONO_ADD_INS (cfg->cbb, ins);
8894                         }
8895                         ++ip;
8896                         readr4 (ip, f);
8897                         ip += 4;
8898                         *sp++ = ins;                    
8899                         break;
8900                 }
8901                 case CEE_LDC_R8: {
8902                         double *d;
8903                         gboolean use_aotconst = FALSE;
8904
8905 #ifdef TARGET_POWERPC
8906                         /* FIXME: Clean this up */
8907                         if (cfg->compile_aot)
8908                                 use_aotconst = TRUE;
8909 #endif
8910
8911                         /* FIXME: we should really allocate this only late in the compilation process */
8912                         d = (double *)mono_domain_alloc (cfg->domain, sizeof (double));
8913                         CHECK_OPSIZE (9);
8914                         CHECK_STACK_OVF (1);
8915
8916                         if (use_aotconst) {
8917                                 MonoInst *cons;
8918                                 int dreg;
8919
8920                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
8921
8922                                 dreg = alloc_freg (cfg);
8923                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
8924                                 ins->type = STACK_R8;
8925                         } else {
8926                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
8927                                 ins->type = STACK_R8;
8928                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8929                                 ins->inst_p0 = d;
8930                                 MONO_ADD_INS (cfg->cbb, ins);
8931                         }
8932                         ++ip;
8933                         readr8 (ip, d);
8934                         ip += 8;
8935                         *sp++ = ins;
8936                         break;
8937                 }
8938                 case CEE_DUP: {
8939                         MonoInst *temp, *store;
8940                         CHECK_STACK (1);
8941                         CHECK_STACK_OVF (1);
8942                         sp--;
8943                         ins = *sp;
8944
8945                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
8946                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
8947
8948                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8949                         *sp++ = ins;
8950
8951                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8952                         *sp++ = ins;
8953
8954                         ++ip;
8955                         inline_costs += 2;
8956                         break;
8957                 }
8958                 case CEE_POP:
8959                         CHECK_STACK (1);
8960                         ip++;
8961                         --sp;
8962
8963 #ifdef TARGET_X86
8964                         if (sp [0]->type == STACK_R8)
8965                                 /* we need to pop the value from the x86 FP stack */
8966                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
8967 #endif
8968                         break;
8969                 case CEE_JMP: {
8970                         MonoCallInst *call;
8971                         MonoMethodSignature *fsig;
8972                         int i, n;
8973
8974                         INLINE_FAILURE ("jmp");
8975                         GSHAREDVT_FAILURE (*ip);
8976
8977                         CHECK_OPSIZE (5);
8978                         if (stack_start != sp)
8979                                 UNVERIFIED;
8980                         token = read32 (ip + 1);
8981                         /* FIXME: check the signature matches */
8982                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8983
8984                         if (!cmethod || mono_loader_get_last_error ())
8985                                 LOAD_ERROR;
8986  
8987                         if (cfg->gshared && mono_method_check_context_used (cmethod))
8988                                 GENERIC_SHARING_FAILURE (CEE_JMP);
8989
8990                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
8991
8992                         fsig = mono_method_signature (cmethod);
8993                         n = fsig->param_count + fsig->hasthis;
8994                         if (cfg->llvm_only) {
8995                                 MonoInst **args;
8996
8997                                 args = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
8998                                 for (i = 0; i < n; ++i)
8999                                         EMIT_NEW_ARGLOAD (cfg, args [i], i);
9000                                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, TRUE, args, NULL, NULL, NULL);
9001                                 /*
9002                                  * The code in mono-basic-block.c treats the rest of the code as dead, but we
9003                                  * have to emit a normal return since llvm expects it.
9004                                  */
9005                                 if (cfg->ret)
9006                                         emit_setret (cfg, ins);
9007                                 MONO_INST_NEW (cfg, ins, OP_BR);
9008                                 ins->inst_target_bb = end_bblock;
9009                                 MONO_ADD_INS (cfg->cbb, ins);
9010                                 link_bblock (cfg, cfg->cbb, end_bblock);
9011                                 ip += 5;
9012                                 break;
9013                         } else if (cfg->backend->have_op_tail_call) {
9014                                 /* Handle tail calls similarly to calls */
9015                                 DISABLE_AOT (cfg);
9016
9017                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
9018                                 call->method = cmethod;
9019                                 call->tail_call = TRUE;
9020                                 call->signature = mono_method_signature (cmethod);
9021                                 call->args = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
9022                                 call->inst.inst_p0 = cmethod;
9023                                 for (i = 0; i < n; ++i)
9024                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
9025
9026                                 mono_arch_emit_call (cfg, call);
9027                                 cfg->param_area = MAX(cfg->param_area, call->stack_usage);
9028                                 MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
9029                         } else {
9030                                 for (i = 0; i < num_args; ++i)
9031                                         /* Prevent arguments from being optimized away */
9032                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
9033
9034                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9035                                 ins = (MonoInst*)call;
9036                                 ins->inst_p0 = cmethod;
9037                                 MONO_ADD_INS (cfg->cbb, ins);
9038                         }
9039
9040                         ip += 5;
9041                         start_new_bblock = 1;
9042                         break;
9043                 }
9044                 case CEE_CALLI: {
9045                         MonoInst *addr;
9046                         MonoMethodSignature *fsig;
9047
9048                         CHECK_OPSIZE (5);
9049                         token = read32 (ip + 1);
9050
9051                         ins = NULL;
9052
9053                         //GSHAREDVT_FAILURE (*ip);
9054                         cmethod = NULL;
9055                         CHECK_STACK (1);
9056                         --sp;
9057                         addr = *sp;
9058                         fsig = mini_get_signature (method, token, generic_context);
9059
9060                         if (method->dynamic && fsig->pinvoke) {
9061                                 MonoInst *args [3];
9062
9063                                 /*
9064                                  * This is a call through a function pointer using a pinvoke
9065                                  * signature. Have to create a wrapper and call that instead.
9066                                  * FIXME: This is very slow, need to create a wrapper at JIT time
9067                                  * instead based on the signature.
9068                                  */
9069                                 EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
9070                                 EMIT_NEW_PCONST (cfg, args [1], fsig);
9071                                 args [2] = addr;
9072                                 addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
9073                         }
9074
9075                         n = fsig->param_count + fsig->hasthis;
9076
9077                         CHECK_STACK (n);
9078
9079                         //g_assert (!virtual_ || fsig->hasthis);
9080
9081                         sp -= n;
9082
9083                         inline_costs += 10 * num_calls++;
9084
9085                         /*
9086                          * Making generic calls out of gsharedvt methods.
9087                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9088                          * patching gshared method addresses into a gsharedvt method.
9089                          */
9090                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
9091                                 /*
9092                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
9093                                  */
9094                                 MonoInst *callee = addr;
9095
9096                                 if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
9097                                         /* Not tested */
9098                                         GSHAREDVT_FAILURE (*ip);
9099
9100                                 if (cfg->llvm_only)
9101                                         // FIXME:
9102                                         GSHAREDVT_FAILURE (*ip);
9103
9104                                 addr = emit_get_rgctx_sig (cfg, context_used,
9105                                                                                           fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
9106                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
9107                                 goto calli_end;
9108                         }
9109
9110                         /* Prevent inlining of methods with indirect calls */
9111                         INLINE_FAILURE ("indirect call");
9112
9113                         if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
9114                                 MonoJumpInfoType info_type;
9115                                 gpointer info_data;
9116
9117                                 /*
9118                                  * Instead of emitting an indirect call, emit a direct call
9119                                  * with the contents of the aotconst as the patch info.
9120                                  */
9121                                 if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
9122                                         info_type = (MonoJumpInfoType)addr->inst_c1;
9123                                         info_data = addr->inst_p0;
9124                                 } else {
9125                                         info_type = (MonoJumpInfoType)addr->inst_right->inst_c1;
9126                                         info_data = addr->inst_right->inst_left;
9127                                 }
9128
9129                                 if (info_type == MONO_PATCH_INFO_ICALL_ADDR || info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
9130                                         ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
9131                                         NULLIFY_INS (addr);
9132                                         goto calli_end;
9133                                 }
9134                         }
9135                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9136
9137                         calli_end:
9138
9139                         /* End of call, INS should contain the result of the call, if any */
9140
9141                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9142                                 g_assert (ins);
9143                                 *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
9144                         }
9145
9146                         CHECK_CFG_EXCEPTION;
9147
9148                         ip += 5;
9149                         ins_flag = 0;
9150                         constrained_class = NULL;
9151                         break;
9152                 }
9153                 case CEE_CALL:
9154                 case CEE_CALLVIRT: {
9155                         MonoInst *addr = NULL;
9156                         MonoMethodSignature *fsig = NULL;
9157                         int array_rank = 0;
9158                         int virtual_ = *ip == CEE_CALLVIRT;
9159                         gboolean pass_imt_from_rgctx = FALSE;
9160                         MonoInst *imt_arg = NULL;
9161                         MonoInst *keep_this_alive = NULL;
9162                         gboolean pass_vtable = FALSE;
9163                         gboolean pass_mrgctx = FALSE;
9164                         MonoInst *vtable_arg = NULL;
9165                         gboolean check_this = FALSE;
9166                         gboolean supported_tail_call = FALSE;
9167                         gboolean tail_call = FALSE;
9168                         gboolean need_seq_point = FALSE;
9169                         guint32 call_opcode = *ip;
9170                         gboolean emit_widen = TRUE;
9171                         gboolean push_res = TRUE;
9172                         gboolean skip_ret = FALSE;
9173                         gboolean delegate_invoke = FALSE;
9174                         gboolean direct_icall = FALSE;
9175                         gboolean constrained_partial_call = FALSE;
9176                         gboolean needs_calling_assembly = FALSE;
9177                         MonoMethod *cil_method;
9178
9179                         CHECK_OPSIZE (5);
9180                         token = read32 (ip + 1);
9181
9182                         ins = NULL;
9183
9184                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
9185                         cil_method = cmethod;
9186                                 
9187                         if (constrained_class) {
9188                                 if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
9189                                         if (!mini_is_gsharedvt_klass (constrained_class)) {
9190                                                 g_assert (!cmethod->klass->valuetype);
9191                                                 if (!mini_type_is_reference (&constrained_class->byval_arg))
9192                                                         constrained_partial_call = TRUE;
9193                                         }
9194                                 }
9195
9196                                 if (method->wrapper_type != MONO_WRAPPER_NONE) {
9197                                         if (cfg->verbose_level > 2)
9198                                                 printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_class));
9199                                         if (!((constrained_class->byval_arg.type == MONO_TYPE_VAR ||
9200                                                    constrained_class->byval_arg.type == MONO_TYPE_MVAR) &&
9201                                                   cfg->gshared)) {
9202                                                 cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_class, generic_context, &cfg->error);
9203                                                 CHECK_CFG_ERROR;
9204                                         }
9205                                 } else {
9206                                         if (cfg->verbose_level > 2)
9207                                                 printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_class));
9208
9209                                         if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
9210                                                 /* 
9211                                                  * This is needed since get_method_constrained can't find 
9212                                                  * the method in klass representing a type var.
9213                                                  * The type var is guaranteed to be a reference type in this
9214                                                  * case.
9215                                                  */
9216                                                 if (!mini_is_gsharedvt_klass (constrained_class))
9217                                                         g_assert (!cmethod->klass->valuetype);
9218                                         } else {
9219                                                 cmethod = mono_get_method_constrained_checked (image, token, constrained_class, generic_context, &cil_method, &cfg->error);
9220                                                 CHECK_CFG_ERROR;
9221                                         }
9222                                 }
9223                         }
9224                                         
9225                         if (!cmethod || mono_loader_get_last_error ())
9226                                 LOAD_ERROR;
9227                         if (!dont_verify && !cfg->skip_visibility) {
9228                                 MonoMethod *target_method = cil_method;
9229                                 if (method->is_inflated) {
9230                                         target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context));
9231                                 }
9232                                 if (!mono_method_can_access_method (method_definition, target_method) &&
9233                                         !mono_method_can_access_method (method, cil_method))
9234                                         METHOD_ACCESS_FAILURE (method, cil_method);
9235                         }
9236
9237                         if (mono_security_core_clr_enabled ())
9238                                 ensure_method_is_allowed_to_call_method (cfg, method, cil_method);
9239
9240                         if (!virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
9241                                 /* MS.NET seems to silently convert this to a callvirt */
9242                                 virtual_ = 1;
9243
9244                         {
9245                                 /*
9246                                  * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
9247                                  * converts to a callvirt.
9248                                  *
9249                                  * tests/bug-515884.il is an example of this behavior
9250                                  */
9251                                 const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
9252                                 const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
9253                                 if (!virtual_ && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
9254                                         virtual_ = 1;
9255                         }
9256
9257                         if (!cmethod->klass->inited)
9258                                 if (!mono_class_init (cmethod->klass))
9259                                         TYPE_LOAD_ERROR (cmethod->klass);
9260
9261                         fsig = mono_method_signature (cmethod);
9262                         if (!fsig)
9263                                 LOAD_ERROR;
9264                         if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
9265                                 mini_class_is_system_array (cmethod->klass)) {
9266                                 array_rank = cmethod->klass->rank;
9267                         } else if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && icall_is_direct_callable (cfg, cmethod)) {
9268                                 direct_icall = TRUE;
9269                         } else if (fsig->pinvoke) {
9270                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
9271                                 fsig = mono_method_signature (wrapper);
9272                         } else if (constrained_class) {
9273                         } else {
9274                                 fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
9275                                 CHECK_CFG_ERROR;
9276                         }
9277
9278                         if (cfg->llvm_only && !cfg->method->wrapper_type)
9279                                 cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, fsig);
9280
9281                         /* See code below */
9282                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
9283                                 MonoBasicBlock *tbb;
9284
9285                                 GET_BBLOCK (cfg, tbb, ip + 5);
9286                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
9287                                         /*
9288                                          * We want to extend the try block to cover the call, but we can't do it if the
9289                                          * call is made directly since its followed by an exception check.
9290                                          */
9291                                         direct_icall = FALSE;
9292                                 }
9293                         }
9294
9295                         /*
9296                          * Stack walks are not supported in llvmonly mode, so
9297                          * when calling methods which call GetCallingAssembly (), save the
9298                          * current assembly in the caller. The call to GetCallingAssembly ()
9299                          * will be turned into an icall which will retrieve the value.
9300                          */
9301                         if (cfg->llvm_only && cmethod && method_needs_calling_assembly (cmethod)) {
9302                                 needs_calling_assembly = TRUE;
9303
9304                                 MonoInst *assembly_ins;
9305
9306                                 EMIT_NEW_AOTCONST (cfg, assembly_ins, MONO_PATCH_INFO_IMAGE, cfg->method->klass->image);
9307                                 ins = mono_emit_jit_icall (cfg, mono_llvmonly_set_calling_assembly, &assembly_ins);
9308                         }
9309
9310                         mono_save_token_info (cfg, image, token, cil_method);
9311
9312                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip + 5 - header->code)))
9313                                 need_seq_point = TRUE;
9314
9315                         /* Don't support calls made using type arguments for now */
9316                         /*
9317                           if (cfg->gsharedvt) {
9318                           if (mini_is_gsharedvt_signature (fsig))
9319                           GSHAREDVT_FAILURE (*ip);
9320                           }
9321                         */
9322
9323                         if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
9324                                 g_assert_not_reached ();
9325
9326                         n = fsig->param_count + fsig->hasthis;
9327
9328                         if (!cfg->gshared && cmethod->klass->generic_container)
9329                                 UNVERIFIED;
9330
9331                         if (!cfg->gshared)
9332                                 g_assert (!mono_method_check_context_used (cmethod));
9333
9334                         CHECK_STACK (n);
9335
9336                         //g_assert (!virtual_ || fsig->hasthis);
9337
9338                         sp -= n;
9339
9340                         /*
9341                          * We have the `constrained.' prefix opcode.
9342                          */
9343                         if (constrained_class) {
9344                                 if (mini_is_gsharedvt_klass (constrained_class)) {
9345                                         if ((cmethod->klass != mono_defaults.object_class) && constrained_class->valuetype && cmethod->klass->valuetype) {
9346                                                 /* The 'Own method' case below */
9347                                         } else if (cmethod->klass->image != mono_defaults.corlib && !(cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !cmethod->klass->valuetype) {
9348                                                 /* 'The type parameter is instantiated as a reference type' case below. */
9349                                         } else {
9350                                                 ins = handle_constrained_gsharedvt_call (cfg, cmethod, fsig, sp, constrained_class, &emit_widen);
9351                                                 CHECK_CFG_EXCEPTION;
9352                                                 g_assert (ins);
9353                                                 goto call_end;
9354                                         }
9355                                 }
9356
9357                                 if (constrained_partial_call) {
9358                                         gboolean need_box = TRUE;
9359
9360                                         /*
9361                                          * The receiver is a valuetype, but the exact type is not known at compile time. This means the
9362                                          * called method is not known at compile time either. The called method could end up being
9363                                          * one of the methods on the parent classes (object/valuetype/enum), in which case we need
9364                                          * to box the receiver.
9365                                          * A simple solution would be to box always and make a normal virtual call, but that would
9366                                          * be bad performance wise.
9367                                          */
9368                                         if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE && cmethod->klass->generic_class) {
9369                                                 /*
9370                                                  * The parent classes implement no generic interfaces, so the called method will be a vtype method, so no boxing neccessary.
9371                                                  */
9372                                                 need_box = FALSE;
9373                                         }
9374
9375                                         if (!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
9376                                                 /* The called method is not virtual, i.e. Object:GetType (), the receiver is a vtype, has to box */
9377                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9378                                                 ins->klass = constrained_class;
9379                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9380                                                 CHECK_CFG_EXCEPTION;
9381                                         } else if (need_box) {
9382                                                 MonoInst *box_type;
9383                                                 MonoBasicBlock *is_ref_bb, *end_bb;
9384                                                 MonoInst *nonbox_call;
9385
9386                                                 /*
9387                                                  * Determine at runtime whenever the called method is defined on object/valuetype/enum, and emit a boxing call
9388                                                  * if needed.
9389                                                  * FIXME: It is possible to inline the called method in a lot of cases, i.e. for T_INT,
9390                                                  * the no-box case goes to a method in Int32, while the box case goes to a method in Enum.
9391                                                  */
9392                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
9393
9394                                                 NEW_BBLOCK (cfg, is_ref_bb);
9395                                                 NEW_BBLOCK (cfg, end_bb);
9396
9397                                                 box_type = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE);
9398                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, box_type->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
9399                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
9400
9401                                                 /* Non-ref case */
9402                                                 nonbox_call = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9403
9404                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9405
9406                                                 /* Ref case */
9407                                                 MONO_START_BB (cfg, is_ref_bb);
9408                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9409                                                 ins->klass = constrained_class;
9410                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9411                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9412
9413                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9414
9415                                                 MONO_START_BB (cfg, end_bb);
9416                                                 cfg->cbb = end_bb;
9417
9418                                                 nonbox_call->dreg = ins->dreg;
9419                                                 goto call_end;
9420                                         } else {
9421                                                 g_assert (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
9422                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
9423                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9424                                                 goto call_end;
9425                                         }
9426                                 } else if (constrained_class->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
9427                                         /*
9428                                          * The type parameter is instantiated as a valuetype,
9429                                          * but that type doesn't override the method we're
9430                                          * calling, so we need to box `this'.
9431                                          */
9432                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9433                                         ins->klass = constrained_class;
9434                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9435                                         CHECK_CFG_EXCEPTION;
9436                                 } else if (!constrained_class->valuetype) {
9437                                         int dreg = alloc_ireg_ref (cfg);
9438
9439                                         /*
9440                                          * The type parameter is instantiated as a reference
9441                                          * type.  We have a managed pointer on the stack, so
9442                                          * we need to dereference it here.
9443                                          */
9444                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
9445                                         ins->type = STACK_OBJ;
9446                                         sp [0] = ins;
9447                                 } else {
9448                                         if (cmethod->klass->valuetype) {
9449                                                 /* Own method */
9450                                         } else {
9451                                                 /* Interface method */
9452                                                 int ioffset, slot;
9453
9454                                                 mono_class_setup_vtable (constrained_class);
9455                                                 CHECK_TYPELOAD (constrained_class);
9456                                                 ioffset = mono_class_interface_offset (constrained_class, cmethod->klass);
9457                                                 if (ioffset == -1)
9458                                                         TYPE_LOAD_ERROR (constrained_class);
9459                                                 slot = mono_method_get_vtable_slot (cmethod);
9460                                                 if (slot == -1)
9461                                                         TYPE_LOAD_ERROR (cmethod->klass);
9462                                                 cmethod = constrained_class->vtable [ioffset + slot];
9463
9464                                                 if (cmethod->klass == mono_defaults.enum_class) {
9465                                                         /* Enum implements some interfaces, so treat this as the first case */
9466                                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9467                                                         ins->klass = constrained_class;
9468                                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9469                                                         CHECK_CFG_EXCEPTION;
9470                                                 }
9471                                         }
9472                                         virtual_ = 0;
9473                                 }
9474                                 constrained_class = NULL;
9475                         }
9476
9477                         if (check_call_signature (cfg, fsig, sp))
9478                                 UNVERIFIED;
9479
9480                         if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
9481                                 delegate_invoke = TRUE;
9482
9483                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
9484                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9485                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9486                                         emit_widen = FALSE;
9487                                 }
9488
9489                                 goto call_end;
9490                         }
9491
9492                         /* 
9493                          * If the callee is a shared method, then its static cctor
9494                          * might not get called after the call was patched.
9495                          */
9496                         if (cfg->gshared && cmethod->klass != method->klass && cmethod->klass->generic_class && mono_method_is_generic_sharable (cmethod, TRUE) && mono_class_needs_cctor_run (cmethod->klass, method)) {
9497                                 emit_class_init (cfg, cmethod->klass);
9498                                 CHECK_TYPELOAD (cmethod->klass);
9499                         }
9500
9501                         check_method_sharing (cfg, cmethod, &pass_vtable, &pass_mrgctx);
9502
9503                         if (cfg->gshared) {
9504                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
9505
9506                                 context_used = mini_method_check_context_used (cfg, cmethod);
9507
9508                                 if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9509                                         /* Generic method interface
9510                                            calls are resolved via a
9511                                            helper function and don't
9512                                            need an imt. */
9513                                         if (!cmethod_context || !cmethod_context->method_inst)
9514                                                 pass_imt_from_rgctx = TRUE;
9515                                 }
9516
9517                                 /*
9518                                  * If a shared method calls another
9519                                  * shared method then the caller must
9520                                  * have a generic sharing context
9521                                  * because the magic trampoline
9522                                  * requires it.  FIXME: We shouldn't
9523                                  * have to force the vtable/mrgctx
9524                                  * variable here.  Instead there
9525                                  * should be a flag in the cfg to
9526                                  * request a generic sharing context.
9527                                  */
9528                                 if (context_used &&
9529                                                 ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
9530                                         mono_get_vtable_var (cfg);
9531                         }
9532
9533                         if (pass_vtable) {
9534                                 if (context_used) {
9535                                         vtable_arg = emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
9536                                 } else {
9537                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
9538
9539                                         CHECK_TYPELOAD (cmethod->klass);
9540                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
9541                                 }
9542                         }
9543
9544                         if (pass_mrgctx) {
9545                                 g_assert (!vtable_arg);
9546
9547                                 if (!cfg->compile_aot) {
9548                                         /* 
9549                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
9550                                          * for type load errors before.
9551                                          */
9552                                         mono_class_setup_vtable (cmethod->klass);
9553                                         CHECK_TYPELOAD (cmethod->klass);
9554                                 }
9555
9556                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
9557
9558                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
9559                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
9560                                          MONO_METHOD_IS_FINAL (cmethod)) &&
9561                                         !mono_class_is_marshalbyref (cmethod->klass)) {
9562                                         if (virtual_)
9563                                                 check_this = TRUE;
9564                                         virtual_ = 0;
9565                                 }
9566                         }
9567
9568                         if (pass_imt_from_rgctx) {
9569                                 g_assert (!pass_vtable);
9570
9571                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9572                                         cmethod, MONO_RGCTX_INFO_METHOD);
9573                         }
9574
9575                         if (check_this)
9576                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9577
9578                         /* Calling virtual generic methods */
9579                         if (virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) &&
9580                             !(MONO_METHOD_IS_FINAL (cmethod) && 
9581                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
9582                             fsig->generic_param_count && 
9583                                 !(cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) &&
9584                                 !cfg->llvm_only) {
9585                                 MonoInst *this_temp, *this_arg_temp, *store;
9586                                 MonoInst *iargs [4];
9587
9588                                 g_assert (fsig->is_inflated);
9589
9590                                 /* Prevent inlining of methods that contain indirect calls */
9591                                 INLINE_FAILURE ("virtual generic call");
9592
9593                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
9594                                         GSHAREDVT_FAILURE (*ip);
9595
9596                                 if (cfg->backend->have_generalized_imt_thunk && cfg->backend->gshared_supported && cmethod->wrapper_type == MONO_WRAPPER_NONE) {
9597                                         g_assert (!imt_arg);
9598                                         if (!context_used)
9599                                                 g_assert (cmethod->is_inflated);
9600                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
9601                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
9602                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, sp [0], imt_arg, NULL);
9603                                 } else {
9604                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
9605                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
9606                                         MONO_ADD_INS (cfg->cbb, store);
9607
9608                                         /* FIXME: This should be a managed pointer */
9609                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
9610
9611                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
9612                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
9613                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
9614                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
9615                                         addr = mono_emit_jit_icall (cfg,
9616                                                                                                 mono_helper_compile_generic_method, iargs);
9617
9618                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
9619
9620                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9621                                 }
9622
9623                                 goto call_end;
9624                         }
9625
9626                         /*
9627                          * Implement a workaround for the inherent races involved in locking:
9628                          * Monitor.Enter ()
9629                          * try {
9630                          * } finally {
9631                          *    Monitor.Exit ()
9632                          * }
9633                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
9634                          * try block, the Exit () won't be executed, see:
9635                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
9636                          * To work around this, we extend such try blocks to include the last x bytes
9637                          * of the Monitor.Enter () call.
9638                          */
9639                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
9640                                 MonoBasicBlock *tbb;
9641
9642                                 GET_BBLOCK (cfg, tbb, ip + 5);
9643                                 /* 
9644                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
9645                                  * from Monitor.Enter like ArgumentNullException.
9646                                  */
9647                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
9648                                         /* Mark this bblock as needing to be extended */
9649                                         tbb->extend_try_block = TRUE;
9650                                 }
9651                         }
9652
9653                         /* Conversion to a JIT intrinsic */
9654                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
9655                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9656                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9657                                         emit_widen = FALSE;
9658                                 }
9659                                 goto call_end;
9660                         }
9661
9662                         /* Inlining */
9663                         if ((cfg->opt & MONO_OPT_INLINE) &&
9664                                 (!virtual_ || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
9665                             mono_method_check_inlining (cfg, cmethod)) {
9666                                 int costs;
9667                                 gboolean always = FALSE;
9668
9669                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
9670                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
9671                                         /* Prevent inlining of methods that call wrappers */
9672                                         INLINE_FAILURE ("wrapper call");
9673                                         cmethod = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
9674                                         always = TRUE;
9675                                 }
9676
9677                                 costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, always);
9678                                 if (costs) {
9679                                         cfg->real_offset += 5;
9680
9681                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9682                                                 /* *sp is already set by inline_method */
9683                                                 sp++;
9684                                                 push_res = FALSE;
9685                                         }
9686
9687                                         inline_costs += costs;
9688
9689                                         goto call_end;
9690                                 }
9691                         }
9692
9693                         /* Tail recursion elimination */
9694                         if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
9695                                 gboolean has_vtargs = FALSE;
9696                                 int i;
9697
9698                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9699                                 INLINE_FAILURE ("tail call");
9700
9701                                 /* keep it simple */
9702                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
9703                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
9704                                                 has_vtargs = TRUE;
9705                                 }
9706
9707                                 if (!has_vtargs) {
9708                                         for (i = 0; i < n; ++i)
9709                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9710                                         MONO_INST_NEW (cfg, ins, OP_BR);
9711                                         MONO_ADD_INS (cfg->cbb, ins);
9712                                         tblock = start_bblock->out_bb [0];
9713                                         link_bblock (cfg, cfg->cbb, tblock);
9714                                         ins->inst_target_bb = tblock;
9715                                         start_new_bblock = 1;
9716
9717                                         /* skip the CEE_RET, too */
9718                                         if (ip_in_bb (cfg, cfg->cbb, ip + 5))
9719                                                 skip_ret = TRUE;
9720                                         push_res = FALSE;
9721                                         goto call_end;
9722                                 }
9723                         }
9724
9725                         inline_costs += 10 * num_calls++;
9726
9727                         /*
9728                          * Making generic calls out of gsharedvt methods.
9729                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9730                          * patching gshared method addresses into a gsharedvt method.
9731                          */
9732                         if (cfg->gsharedvt && (mini_is_gsharedvt_signature (fsig) || cmethod->is_inflated || cmethod->klass->generic_class) &&
9733                                 !(cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY) &&
9734                                 (!(cfg->llvm_only && virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)))) {
9735                                 MonoRgctxInfoType info_type;
9736
9737                                 if (virtual_) {
9738                                         //if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
9739                                                 //GSHAREDVT_FAILURE (*ip);
9740                                         // disable for possible remoting calls
9741                                         if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
9742                                                 GSHAREDVT_FAILURE (*ip);
9743                                         if (fsig->generic_param_count) {
9744                                                 /* virtual generic call */
9745                                                 g_assert (!imt_arg);
9746                                                 /* Same as the virtual generic case above */
9747                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9748                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9749                                                 /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
9750                                                 vtable_arg = NULL;
9751                                         } else if ((cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !imt_arg) {
9752                                                 /* This can happen when we call a fully instantiated iface method */
9753                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9754                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9755                                                 vtable_arg = NULL;
9756                                         }
9757                                 }
9758
9759                                 if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
9760                                         keep_this_alive = sp [0];
9761
9762                                 if (virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
9763                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
9764                                 else
9765                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
9766                                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
9767
9768                                 if (cfg->llvm_only) {
9769                                         // FIXME: Avoid initializing vtable_arg
9770                                         ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
9771                                 } else {
9772                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9773                                 }
9774                                 goto call_end;
9775                         }
9776
9777                         /* Generic sharing */
9778
9779                         /*
9780                          * Use this if the callee is gsharedvt sharable too, since
9781                          * at runtime we might find an instantiation so the call cannot
9782                          * be patched (the 'no_patch' code path in mini-trampolines.c).
9783                          */
9784                         if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
9785                                 (!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
9786                                  !mono_class_generic_sharing_enabled (cmethod->klass)) &&
9787                                 (!virtual_ || MONO_METHOD_IS_FINAL (cmethod) ||
9788                                  !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
9789                                 INLINE_FAILURE ("gshared");
9790
9791                                 g_assert (cfg->gshared && cmethod);
9792                                 g_assert (!addr);
9793
9794                                 /*
9795                                  * We are compiling a call to a
9796                                  * generic method from shared code,
9797                                  * which means that we have to look up
9798                                  * the method in the rgctx and do an
9799                                  * indirect call.
9800                                  */
9801                                 if (fsig->hasthis)
9802                                         MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9803
9804                                 if (cfg->llvm_only) {
9805                                         if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig))
9806                                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER);
9807                                         else
9808                                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9809                                         // FIXME: Avoid initializing imt_arg/vtable_arg
9810                                         ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
9811                                 } else {
9812                                         addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9813                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9814                                 }
9815                                 goto call_end;
9816                         }
9817
9818                         /* Direct calls to icalls */
9819                         if (direct_icall) {
9820                                 MonoMethod *wrapper;
9821                                 int costs;
9822
9823                                 /* Inline the wrapper */
9824                                 wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
9825
9826                                 costs = inline_method (cfg, wrapper, fsig, sp, ip, cfg->real_offset, TRUE);
9827                                 g_assert (costs > 0);
9828                                 cfg->real_offset += 5;
9829
9830                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9831                                         /* *sp is already set by inline_method */
9832                                         sp++;
9833                                         push_res = FALSE;
9834                                 }
9835
9836                                 inline_costs += costs;
9837
9838                                 goto call_end;
9839                         }
9840                                         
9841                         /* Array methods */
9842                         if (array_rank) {
9843                                 MonoInst *addr;
9844
9845                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
9846                                         MonoInst *val = sp [fsig->param_count];
9847
9848                                         if (val->type == STACK_OBJ) {
9849                                                 MonoInst *iargs [2];
9850
9851                                                 iargs [0] = sp [0];
9852                                                 iargs [1] = val;
9853                                                 
9854                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
9855                                         }
9856                                         
9857                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
9858                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
9859                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !(val->opcode == OP_PCONST && val->inst_c0 == 0))
9860                                                 emit_write_barrier (cfg, addr, val);
9861                                         if (cfg->gen_write_barriers && mini_is_gsharedvt_klass (cmethod->klass))
9862                                                 GSHAREDVT_FAILURE (*ip);
9863                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
9864                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9865
9866                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
9867                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
9868                                         if (!cmethod->klass->element_class->valuetype && !readonly)
9869                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
9870                                         CHECK_TYPELOAD (cmethod->klass);
9871                                         
9872                                         readonly = FALSE;
9873                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9874                                         ins = addr;
9875                                 } else {
9876                                         g_assert_not_reached ();
9877                                 }
9878
9879                                 emit_widen = FALSE;
9880                                 goto call_end;
9881                         }
9882
9883                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual_ ? sp [0] : NULL);
9884                         if (ins)
9885                                 goto call_end;
9886
9887                         /* Tail prefix / tail call optimization */
9888
9889                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
9890                         /* FIXME: runtime generic context pointer for jumps? */
9891                         /* FIXME: handle this for generic sharing eventually */
9892                         if ((ins_flag & MONO_INST_TAILCALL) &&
9893                                 !vtable_arg && !cfg->gshared && is_supported_tail_call (cfg, method, cmethod, fsig, call_opcode))
9894                                 supported_tail_call = TRUE;
9895
9896                         if (supported_tail_call) {
9897                                 MonoCallInst *call;
9898
9899                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9900                                 INLINE_FAILURE ("tail call");
9901
9902                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
9903
9904                                 if (cfg->backend->have_op_tail_call) {
9905                                         /* Handle tail calls similarly to normal calls */
9906                                         tail_call = TRUE;
9907                                 } else {
9908                                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
9909
9910                                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9911                                         call->tail_call = TRUE;
9912                                         call->method = cmethod;
9913                                         call->signature = mono_method_signature (cmethod);
9914
9915                                         /*
9916                                          * We implement tail calls by storing the actual arguments into the 
9917                                          * argument variables, then emitting a CEE_JMP.
9918                                          */
9919                                         for (i = 0; i < n; ++i) {
9920                                                 /* Prevent argument from being register allocated */
9921                                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
9922                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9923                                         }
9924                                         ins = (MonoInst*)call;
9925                                         ins->inst_p0 = cmethod;
9926                                         ins->inst_p1 = arg_array [0];
9927                                         MONO_ADD_INS (cfg->cbb, ins);
9928                                         link_bblock (cfg, cfg->cbb, end_bblock);
9929                                         start_new_bblock = 1;
9930
9931                                         // FIXME: Eliminate unreachable epilogs
9932
9933                                         /*
9934                                          * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9935                                          * only reachable from this call.
9936                                          */
9937                                         GET_BBLOCK (cfg, tblock, ip + 5);
9938                                         if (tblock == cfg->cbb || tblock->in_count == 0)
9939                                                 skip_ret = TRUE;
9940                                         push_res = FALSE;
9941
9942                                         goto call_end;
9943                                 }
9944                         }
9945
9946                         /* 
9947                          * Synchronized wrappers.
9948                          * Its hard to determine where to replace a method with its synchronized
9949                          * wrapper without causing an infinite recursion. The current solution is
9950                          * to add the synchronized wrapper in the trampolines, and to
9951                          * change the called method to a dummy wrapper, and resolve that wrapper
9952                          * to the real method in mono_jit_compile_method ().
9953                          */
9954                         if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
9955                                 MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
9956                                 if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
9957                                         cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
9958                         }
9959
9960                         /*
9961                          * Virtual calls in llvm-only mode.
9962                          */
9963                         if (cfg->llvm_only && virtual_ && cmethod && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
9964                                 ins = emit_llvmonly_virtual_call (cfg, cmethod, fsig, context_used, sp);
9965                                 goto call_end;
9966                         }
9967
9968                         /* Common call */
9969                         INLINE_FAILURE ("call");
9970                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual_ ? sp [0] : NULL,
9971                                                                                           imt_arg, vtable_arg);
9972
9973                         if (tail_call && !cfg->llvm_only) {
9974                                 link_bblock (cfg, cfg->cbb, end_bblock);
9975                                 start_new_bblock = 1;
9976
9977                                 // FIXME: Eliminate unreachable epilogs
9978
9979                                 /*
9980                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9981                                  * only reachable from this call.
9982                                  */
9983                                 GET_BBLOCK (cfg, tblock, ip + 5);
9984                                 if (tblock == cfg->cbb || tblock->in_count == 0)
9985                                         skip_ret = TRUE;
9986                                 push_res = FALSE;
9987                         }
9988
9989                         call_end:
9990
9991                         /* End of call, INS should contain the result of the call, if any */
9992
9993                         if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
9994                                 g_assert (ins);
9995                                 if (emit_widen)
9996                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
9997                                 else
9998                                         *sp++ = ins;
9999                         }
10000
10001                         if (keep_this_alive) {
10002                                 MonoInst *dummy_use;
10003
10004                                 /* See mono_emit_method_call_full () */
10005                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
10006                         }
10007
10008                         if (needs_calling_assembly) {
10009                                 /*
10010                                  * Clear the calling assembly.
10011                                  * This is not EH safe, but this is not a problem in practice, since
10012                                  * the null value is only used for error checking.
10013                                  */
10014                                 MonoInst *assembly_ins;
10015
10016                                 EMIT_NEW_PCONST (cfg, assembly_ins, NULL);
10017                                 ins = mono_emit_jit_icall (cfg, mono_llvmonly_set_calling_assembly, &assembly_ins);
10018                         }
10019
10020                         CHECK_CFG_EXCEPTION;
10021
10022                         ip += 5;
10023                         if (skip_ret) {
10024                                 g_assert (*ip == CEE_RET);
10025                                 ip += 1;
10026                         }
10027                         ins_flag = 0;
10028                         constrained_class = NULL;
10029                         if (need_seq_point)
10030                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10031                         break;
10032                 }
10033                 case CEE_RET:
10034                         if (cfg->method != method) {
10035                                 /* return from inlined method */
10036                                 /* 
10037                                  * If in_count == 0, that means the ret is unreachable due to
10038                                  * being preceeded by a throw. In that case, inline_method () will
10039                                  * handle setting the return value 
10040                                  * (test case: test_0_inline_throw ()).
10041                                  */
10042                                 if (return_var && cfg->cbb->in_count) {
10043                                         MonoType *ret_type = mono_method_signature (method)->ret;
10044
10045                                         MonoInst *store;
10046                                         CHECK_STACK (1);
10047                                         --sp;
10048
10049                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
10050                                                 UNVERIFIED;
10051
10052                                         //g_assert (returnvar != -1);
10053                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
10054                                         cfg->ret_var_set = TRUE;
10055                                 } 
10056                         } else {
10057                                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
10058
10059                                 if (cfg->lmf_var && cfg->cbb->in_count && !cfg->llvm_only)
10060                                         emit_pop_lmf (cfg);
10061
10062                                 if (cfg->ret) {
10063                                         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (method)->ret);
10064
10065                                         if (seq_points && !sym_seq_points) {
10066                                                 /* 
10067                                                  * Place a seq point here too even through the IL stack is not
10068                                                  * empty, so a step over on
10069                                                  * call <FOO>
10070                                                  * ret
10071                                                  * will work correctly.
10072                                                  */
10073                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
10074                                                 MONO_ADD_INS (cfg->cbb, ins);
10075                                         }
10076
10077                                         g_assert (!return_var);
10078                                         CHECK_STACK (1);
10079                                         --sp;
10080
10081                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
10082                                                 UNVERIFIED;
10083
10084                                         emit_setret (cfg, *sp);
10085                                 }
10086                         }
10087                         if (sp != stack_start)
10088                                 UNVERIFIED;
10089                         MONO_INST_NEW (cfg, ins, OP_BR);
10090                         ip++;
10091                         ins->inst_target_bb = end_bblock;
10092                         MONO_ADD_INS (cfg->cbb, ins);
10093                         link_bblock (cfg, cfg->cbb, end_bblock);
10094                         start_new_bblock = 1;
10095                         break;
10096                 case CEE_BR_S:
10097                         CHECK_OPSIZE (2);
10098                         MONO_INST_NEW (cfg, ins, OP_BR);
10099                         ip++;
10100                         target = ip + 1 + (signed char)(*ip);
10101                         ++ip;
10102                         GET_BBLOCK (cfg, tblock, target);
10103                         link_bblock (cfg, cfg->cbb, tblock);
10104                         ins->inst_target_bb = tblock;
10105                         if (sp != stack_start) {
10106                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10107                                 sp = stack_start;
10108                                 CHECK_UNVERIFIABLE (cfg);
10109                         }
10110                         MONO_ADD_INS (cfg->cbb, ins);
10111                         start_new_bblock = 1;
10112                         inline_costs += BRANCH_COST;
10113                         break;
10114                 case CEE_BEQ_S:
10115                 case CEE_BGE_S:
10116                 case CEE_BGT_S:
10117                 case CEE_BLE_S:
10118                 case CEE_BLT_S:
10119                 case CEE_BNE_UN_S:
10120                 case CEE_BGE_UN_S:
10121                 case CEE_BGT_UN_S:
10122                 case CEE_BLE_UN_S:
10123                 case CEE_BLT_UN_S:
10124                         CHECK_OPSIZE (2);
10125                         CHECK_STACK (2);
10126                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
10127                         ip++;
10128                         target = ip + 1 + *(signed char*)ip;
10129                         ip++;
10130
10131                         ADD_BINCOND (NULL);
10132
10133                         sp = stack_start;
10134                         inline_costs += BRANCH_COST;
10135                         break;
10136                 case CEE_BR:
10137                         CHECK_OPSIZE (5);
10138                         MONO_INST_NEW (cfg, ins, OP_BR);
10139                         ip++;
10140
10141                         target = ip + 4 + (gint32)read32(ip);
10142                         ip += 4;
10143                         GET_BBLOCK (cfg, tblock, target);
10144                         link_bblock (cfg, cfg->cbb, tblock);
10145                         ins->inst_target_bb = tblock;
10146                         if (sp != stack_start) {
10147                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10148                                 sp = stack_start;
10149                                 CHECK_UNVERIFIABLE (cfg);
10150                         }
10151
10152                         MONO_ADD_INS (cfg->cbb, ins);
10153
10154                         start_new_bblock = 1;
10155                         inline_costs += BRANCH_COST;
10156                         break;
10157                 case CEE_BRFALSE_S:
10158                 case CEE_BRTRUE_S:
10159                 case CEE_BRFALSE:
10160                 case CEE_BRTRUE: {
10161                         MonoInst *cmp;
10162                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
10163                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
10164                         guint32 opsize = is_short ? 1 : 4;
10165
10166                         CHECK_OPSIZE (opsize);
10167                         CHECK_STACK (1);
10168                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
10169                                 UNVERIFIED;
10170                         ip ++;
10171                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
10172                         ip += opsize;
10173
10174                         sp--;
10175
10176                         GET_BBLOCK (cfg, tblock, target);
10177                         link_bblock (cfg, cfg->cbb, tblock);
10178                         GET_BBLOCK (cfg, tblock, ip);
10179                         link_bblock (cfg, cfg->cbb, tblock);
10180
10181                         if (sp != stack_start) {
10182                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10183                                 CHECK_UNVERIFIABLE (cfg);
10184                         }
10185
10186                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
10187                         cmp->sreg1 = sp [0]->dreg;
10188                         type_from_op (cfg, cmp, sp [0], NULL);
10189                         CHECK_TYPE (cmp);
10190
10191 #if SIZEOF_REGISTER == 4
10192                         if (cmp->opcode == OP_LCOMPARE_IMM) {
10193                                 /* Convert it to OP_LCOMPARE */
10194                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
10195                                 ins->type = STACK_I8;
10196                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
10197                                 ins->inst_l = 0;
10198                                 MONO_ADD_INS (cfg->cbb, ins);
10199                                 cmp->opcode = OP_LCOMPARE;
10200                                 cmp->sreg2 = ins->dreg;
10201                         }
10202 #endif
10203                         MONO_ADD_INS (cfg->cbb, cmp);
10204
10205                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
10206                         type_from_op (cfg, ins, sp [0], NULL);
10207                         MONO_ADD_INS (cfg->cbb, ins);
10208                         ins->inst_many_bb = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
10209                         GET_BBLOCK (cfg, tblock, target);
10210                         ins->inst_true_bb = tblock;
10211                         GET_BBLOCK (cfg, tblock, ip);
10212                         ins->inst_false_bb = tblock;
10213                         start_new_bblock = 2;
10214
10215                         sp = stack_start;
10216                         inline_costs += BRANCH_COST;
10217                         break;
10218                 }
10219                 case CEE_BEQ:
10220                 case CEE_BGE:
10221                 case CEE_BGT:
10222                 case CEE_BLE:
10223                 case CEE_BLT:
10224                 case CEE_BNE_UN:
10225                 case CEE_BGE_UN:
10226                 case CEE_BGT_UN:
10227                 case CEE_BLE_UN:
10228                 case CEE_BLT_UN:
10229                         CHECK_OPSIZE (5);
10230                         CHECK_STACK (2);
10231                         MONO_INST_NEW (cfg, ins, *ip);
10232                         ip++;
10233                         target = ip + 4 + (gint32)read32(ip);
10234                         ip += 4;
10235
10236                         ADD_BINCOND (NULL);
10237
10238                         sp = stack_start;
10239                         inline_costs += BRANCH_COST;
10240                         break;
10241                 case CEE_SWITCH: {
10242                         MonoInst *src1;
10243                         MonoBasicBlock **targets;
10244                         MonoBasicBlock *default_bblock;
10245                         MonoJumpInfoBBTable *table;
10246                         int offset_reg = alloc_preg (cfg);
10247                         int target_reg = alloc_preg (cfg);
10248                         int table_reg = alloc_preg (cfg);
10249                         int sum_reg = alloc_preg (cfg);
10250                         gboolean use_op_switch;
10251
10252                         CHECK_OPSIZE (5);
10253                         CHECK_STACK (1);
10254                         n = read32 (ip + 1);
10255                         --sp;
10256                         src1 = sp [0];
10257                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
10258                                 UNVERIFIED;
10259
10260                         ip += 5;
10261                         CHECK_OPSIZE (n * sizeof (guint32));
10262                         target = ip + n * sizeof (guint32);
10263
10264                         GET_BBLOCK (cfg, default_bblock, target);
10265                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
10266
10267                         targets = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
10268                         for (i = 0; i < n; ++i) {
10269                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
10270                                 targets [i] = tblock;
10271                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
10272                                 ip += 4;
10273                         }
10274
10275                         if (sp != stack_start) {
10276                                 /* 
10277                                  * Link the current bb with the targets as well, so handle_stack_args
10278                                  * will set their in_stack correctly.
10279                                  */
10280                                 link_bblock (cfg, cfg->cbb, default_bblock);
10281                                 for (i = 0; i < n; ++i)
10282                                         link_bblock (cfg, cfg->cbb, targets [i]);
10283
10284                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10285                                 sp = stack_start;
10286                                 CHECK_UNVERIFIABLE (cfg);
10287
10288                                 /* Undo the links */
10289                                 mono_unlink_bblock (cfg, cfg->cbb, default_bblock);
10290                                 for (i = 0; i < n; ++i)
10291                                         mono_unlink_bblock (cfg, cfg->cbb, targets [i]);
10292                         }
10293
10294                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
10295                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
10296
10297                         for (i = 0; i < n; ++i)
10298                                 link_bblock (cfg, cfg->cbb, targets [i]);
10299
10300                         table = (MonoJumpInfoBBTable *)mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
10301                         table->table = targets;
10302                         table->table_size = n;
10303
10304                         use_op_switch = FALSE;
10305 #ifdef TARGET_ARM
10306                         /* ARM implements SWITCH statements differently */
10307                         /* FIXME: Make it use the generic implementation */
10308                         if (!cfg->compile_aot)
10309                                 use_op_switch = TRUE;
10310 #endif
10311
10312                         if (COMPILE_LLVM (cfg))
10313                                 use_op_switch = TRUE;
10314
10315                         cfg->cbb->has_jump_table = 1;
10316
10317                         if (use_op_switch) {
10318                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
10319                                 ins->sreg1 = src1->dreg;
10320                                 ins->inst_p0 = table;
10321                                 ins->inst_many_bb = targets;
10322                                 ins->klass = (MonoClass *)GUINT_TO_POINTER (n);
10323                                 MONO_ADD_INS (cfg->cbb, ins);
10324                         } else {
10325                                 if (sizeof (gpointer) == 8)
10326                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
10327                                 else
10328                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
10329
10330 #if SIZEOF_REGISTER == 8
10331                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
10332                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
10333 #endif
10334
10335                                 if (cfg->compile_aot) {
10336                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
10337                                 } else {
10338                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
10339                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
10340                                         ins->inst_p0 = table;
10341                                         ins->dreg = table_reg;
10342                                         MONO_ADD_INS (cfg->cbb, ins);
10343                                 }
10344
10345                                 /* FIXME: Use load_memindex */
10346                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
10347                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
10348                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
10349                         }
10350                         start_new_bblock = 1;
10351                         inline_costs += (BRANCH_COST * 2);
10352                         break;
10353                 }
10354                 case CEE_LDIND_I1:
10355                 case CEE_LDIND_U1:
10356                 case CEE_LDIND_I2:
10357                 case CEE_LDIND_U2:
10358                 case CEE_LDIND_I4:
10359                 case CEE_LDIND_U4:
10360                 case CEE_LDIND_I8:
10361                 case CEE_LDIND_I:
10362                 case CEE_LDIND_R4:
10363                 case CEE_LDIND_R8:
10364                 case CEE_LDIND_REF:
10365                         CHECK_STACK (1);
10366                         --sp;
10367
10368                         switch (*ip) {
10369                         case CEE_LDIND_R4:
10370                         case CEE_LDIND_R8:
10371                                 dreg = alloc_freg (cfg);
10372                                 break;
10373                         case CEE_LDIND_I8:
10374                                 dreg = alloc_lreg (cfg);
10375                                 break;
10376                         case CEE_LDIND_REF:
10377                                 dreg = alloc_ireg_ref (cfg);
10378                                 break;
10379                         default:
10380                                 dreg = alloc_preg (cfg);
10381                         }
10382
10383                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
10384                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
10385                         if (*ip == CEE_LDIND_R4)
10386                                 ins->type = cfg->r4_stack_type;
10387                         ins->flags |= ins_flag;
10388                         MONO_ADD_INS (cfg->cbb, ins);
10389                         *sp++ = ins;
10390                         if (ins_flag & MONO_INST_VOLATILE) {
10391                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10392                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10393                         }
10394                         ins_flag = 0;
10395                         ++ip;
10396                         break;
10397                 case CEE_STIND_REF:
10398                 case CEE_STIND_I1:
10399                 case CEE_STIND_I2:
10400                 case CEE_STIND_I4:
10401                 case CEE_STIND_I8:
10402                 case CEE_STIND_R4:
10403                 case CEE_STIND_R8:
10404                 case CEE_STIND_I:
10405                         CHECK_STACK (2);
10406                         sp -= 2;
10407
10408                         if (ins_flag & MONO_INST_VOLATILE) {
10409                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
10410                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
10411                         }
10412
10413                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
10414                         ins->flags |= ins_flag;
10415                         ins_flag = 0;
10416
10417                         MONO_ADD_INS (cfg->cbb, ins);
10418
10419                         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)))
10420                                 emit_write_barrier (cfg, sp [0], sp [1]);
10421
10422                         inline_costs += 1;
10423                         ++ip;
10424                         break;
10425
10426                 case CEE_MUL:
10427                         CHECK_STACK (2);
10428
10429                         MONO_INST_NEW (cfg, ins, (*ip));
10430                         sp -= 2;
10431                         ins->sreg1 = sp [0]->dreg;
10432                         ins->sreg2 = sp [1]->dreg;
10433                         type_from_op (cfg, ins, sp [0], sp [1]);
10434                         CHECK_TYPE (ins);
10435                         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type);
10436
10437                         /* Use the immediate opcodes if possible */
10438                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
10439                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
10440                                 if (imm_opcode != -1) {
10441                                         ins->opcode = imm_opcode;
10442                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
10443                                         ins->sreg2 = -1;
10444
10445                                         NULLIFY_INS (sp [1]);
10446                                 }
10447                         }
10448
10449                         MONO_ADD_INS ((cfg)->cbb, (ins));
10450
10451                         *sp++ = mono_decompose_opcode (cfg, ins);
10452                         ip++;
10453                         break;
10454                 case CEE_ADD:
10455                 case CEE_SUB:
10456                 case CEE_DIV:
10457                 case CEE_DIV_UN:
10458                 case CEE_REM:
10459                 case CEE_REM_UN:
10460                 case CEE_AND:
10461                 case CEE_OR:
10462                 case CEE_XOR:
10463                 case CEE_SHL:
10464                 case CEE_SHR:
10465                 case CEE_SHR_UN:
10466                         CHECK_STACK (2);
10467
10468                         MONO_INST_NEW (cfg, ins, (*ip));
10469                         sp -= 2;
10470                         ins->sreg1 = sp [0]->dreg;
10471                         ins->sreg2 = sp [1]->dreg;
10472                         type_from_op (cfg, ins, sp [0], sp [1]);
10473                         CHECK_TYPE (ins);
10474                         add_widen_op (cfg, ins, &sp [0], &sp [1]);
10475                         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type);
10476
10477                         /* FIXME: Pass opcode to is_inst_imm */
10478
10479                         /* Use the immediate opcodes if possible */
10480                         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)) {
10481                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
10482                                 if (imm_opcode != -1) {
10483                                         ins->opcode = imm_opcode;
10484                                         if (sp [1]->opcode == OP_I8CONST) {
10485 #if SIZEOF_REGISTER == 8
10486                                                 ins->inst_imm = sp [1]->inst_l;
10487 #else
10488                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
10489                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
10490 #endif
10491                                         }
10492                                         else
10493                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
10494                                         ins->sreg2 = -1;
10495
10496                                         /* Might be followed by an instruction added by add_widen_op */
10497                                         if (sp [1]->next == NULL)
10498                                                 NULLIFY_INS (sp [1]);
10499                                 }
10500                         }
10501                         MONO_ADD_INS ((cfg)->cbb, (ins));
10502
10503                         *sp++ = mono_decompose_opcode (cfg, ins);
10504                         ip++;
10505                         break;
10506                 case CEE_NEG:
10507                 case CEE_NOT:
10508                 case CEE_CONV_I1:
10509                 case CEE_CONV_I2:
10510                 case CEE_CONV_I4:
10511                 case CEE_CONV_R4:
10512                 case CEE_CONV_R8:
10513                 case CEE_CONV_U4:
10514                 case CEE_CONV_I8:
10515                 case CEE_CONV_U8:
10516                 case CEE_CONV_OVF_I8:
10517                 case CEE_CONV_OVF_U8:
10518                 case CEE_CONV_R_UN:
10519                         CHECK_STACK (1);
10520
10521                         /* Special case this earlier so we have long constants in the IR */
10522                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
10523                                 int data = sp [-1]->inst_c0;
10524                                 sp [-1]->opcode = OP_I8CONST;
10525                                 sp [-1]->type = STACK_I8;
10526 #if SIZEOF_REGISTER == 8
10527                                 if ((*ip) == CEE_CONV_U8)
10528                                         sp [-1]->inst_c0 = (guint32)data;
10529                                 else
10530                                         sp [-1]->inst_c0 = data;
10531 #else
10532                                 sp [-1]->inst_ls_word = data;
10533                                 if ((*ip) == CEE_CONV_U8)
10534                                         sp [-1]->inst_ms_word = 0;
10535                                 else
10536                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
10537 #endif
10538                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
10539                         }
10540                         else {
10541                                 ADD_UNOP (*ip);
10542                         }
10543                         ip++;
10544                         break;
10545                 case CEE_CONV_OVF_I4:
10546                 case CEE_CONV_OVF_I1:
10547                 case CEE_CONV_OVF_I2:
10548                 case CEE_CONV_OVF_I:
10549                 case CEE_CONV_OVF_U:
10550                         CHECK_STACK (1);
10551
10552                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10553                                 ADD_UNOP (CEE_CONV_OVF_I8);
10554                                 ADD_UNOP (*ip);
10555                         } else {
10556                                 ADD_UNOP (*ip);
10557                         }
10558                         ip++;
10559                         break;
10560                 case CEE_CONV_OVF_U1:
10561                 case CEE_CONV_OVF_U2:
10562                 case CEE_CONV_OVF_U4:
10563                         CHECK_STACK (1);
10564
10565                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10566                                 ADD_UNOP (CEE_CONV_OVF_U8);
10567                                 ADD_UNOP (*ip);
10568                         } else {
10569                                 ADD_UNOP (*ip);
10570                         }
10571                         ip++;
10572                         break;
10573                 case CEE_CONV_OVF_I1_UN:
10574                 case CEE_CONV_OVF_I2_UN:
10575                 case CEE_CONV_OVF_I4_UN:
10576                 case CEE_CONV_OVF_I8_UN:
10577                 case CEE_CONV_OVF_U1_UN:
10578                 case CEE_CONV_OVF_U2_UN:
10579                 case CEE_CONV_OVF_U4_UN:
10580                 case CEE_CONV_OVF_U8_UN:
10581                 case CEE_CONV_OVF_I_UN:
10582                 case CEE_CONV_OVF_U_UN:
10583                 case CEE_CONV_U2:
10584                 case CEE_CONV_U1:
10585                 case CEE_CONV_I:
10586                 case CEE_CONV_U:
10587                         CHECK_STACK (1);
10588                         ADD_UNOP (*ip);
10589                         CHECK_CFG_EXCEPTION;
10590                         ip++;
10591                         break;
10592                 case CEE_ADD_OVF:
10593                 case CEE_ADD_OVF_UN:
10594                 case CEE_MUL_OVF:
10595                 case CEE_MUL_OVF_UN:
10596                 case CEE_SUB_OVF:
10597                 case CEE_SUB_OVF_UN:
10598                         CHECK_STACK (2);
10599                         ADD_BINOP (*ip);
10600                         ip++;
10601                         break;
10602                 case CEE_CPOBJ:
10603                         GSHAREDVT_FAILURE (*ip);
10604                         CHECK_OPSIZE (5);
10605                         CHECK_STACK (2);
10606                         token = read32 (ip + 1);
10607                         klass = mini_get_class (method, token, generic_context);
10608                         CHECK_TYPELOAD (klass);
10609                         sp -= 2;
10610                         if (generic_class_is_reference_type (cfg, klass)) {
10611                                 MonoInst *store, *load;
10612                                 int dreg = alloc_ireg_ref (cfg);
10613
10614                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
10615                                 load->flags |= ins_flag;
10616                                 MONO_ADD_INS (cfg->cbb, load);
10617
10618                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
10619                                 store->flags |= ins_flag;
10620                                 MONO_ADD_INS (cfg->cbb, store);
10621
10622                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
10623                                         emit_write_barrier (cfg, sp [0], sp [1]);
10624                         } else {
10625                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10626                         }
10627                         ins_flag = 0;
10628                         ip += 5;
10629                         break;
10630                 case CEE_LDOBJ: {
10631                         int loc_index = -1;
10632                         int stloc_len = 0;
10633
10634                         CHECK_OPSIZE (5);
10635                         CHECK_STACK (1);
10636                         --sp;
10637                         token = read32 (ip + 1);
10638                         klass = mini_get_class (method, token, generic_context);
10639                         CHECK_TYPELOAD (klass);
10640
10641                         /* Optimize the common ldobj+stloc combination */
10642                         switch (ip [5]) {
10643                         case CEE_STLOC_S:
10644                                 loc_index = ip [6];
10645                                 stloc_len = 2;
10646                                 break;
10647                         case CEE_STLOC_0:
10648                         case CEE_STLOC_1:
10649                         case CEE_STLOC_2:
10650                         case CEE_STLOC_3:
10651                                 loc_index = ip [5] - CEE_STLOC_0;
10652                                 stloc_len = 1;
10653                                 break;
10654                         default:
10655                                 break;
10656                         }
10657
10658                         if ((loc_index != -1) && ip_in_bb (cfg, cfg->cbb, ip + 5)) {
10659                                 CHECK_LOCAL (loc_index);
10660
10661                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10662                                 ins->dreg = cfg->locals [loc_index]->dreg;
10663                                 ins->flags |= ins_flag;
10664                                 ip += 5;
10665                                 ip += stloc_len;
10666                                 if (ins_flag & MONO_INST_VOLATILE) {
10667                                         /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10668                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10669                                 }
10670                                 ins_flag = 0;
10671                                 break;
10672                         }
10673
10674                         /* Optimize the ldobj+stobj combination */
10675                         /* The reference case ends up being a load+store anyway */
10676                         /* Skip this if the operation is volatile. */
10677                         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)) {
10678                                 CHECK_STACK (1);
10679
10680                                 sp --;
10681
10682                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10683
10684                                 ip += 5 + 5;
10685                                 ins_flag = 0;
10686                                 break;
10687                         }
10688
10689                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10690                         ins->flags |= ins_flag;
10691                         *sp++ = ins;
10692
10693                         if (ins_flag & MONO_INST_VOLATILE) {
10694                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10695                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10696                         }
10697
10698                         ip += 5;
10699                         ins_flag = 0;
10700                         inline_costs += 1;
10701                         break;
10702                 }
10703                 case CEE_LDSTR:
10704                         CHECK_STACK_OVF (1);
10705                         CHECK_OPSIZE (5);
10706                         n = read32 (ip + 1);
10707
10708                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
10709                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
10710                                 ins->type = STACK_OBJ;
10711                                 *sp = ins;
10712                         }
10713                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
10714                                 MonoInst *iargs [1];
10715                                 char *str = (char *)mono_method_get_wrapper_data (method, n);
10716
10717                                 if (cfg->compile_aot)
10718                                         EMIT_NEW_LDSTRLITCONST (cfg, iargs [0], str);
10719                                 else
10720                                         EMIT_NEW_PCONST (cfg, iargs [0], str);
10721                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
10722                         } else {
10723                                 if (cfg->opt & MONO_OPT_SHARED) {
10724                                         MonoInst *iargs [3];
10725
10726                                         if (cfg->compile_aot) {
10727                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
10728                                         }
10729                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10730                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
10731                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
10732                                         *sp = mono_emit_jit_icall (cfg, mono_ldstr, iargs);
10733                                         mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
10734                                 } else {
10735                                         if (cfg->cbb->out_of_line) {
10736                                                 MonoInst *iargs [2];
10737
10738                                                 if (image == mono_defaults.corlib) {
10739                                                         /* 
10740                                                          * Avoid relocations in AOT and save some space by using a 
10741                                                          * version of helper_ldstr specialized to mscorlib.
10742                                                          */
10743                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
10744                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
10745                                                 } else {
10746                                                         /* Avoid creating the string object */
10747                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
10748                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
10749                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
10750                                                 }
10751                                         } 
10752                                         else
10753                                         if (cfg->compile_aot) {
10754                                                 NEW_LDSTRCONST (cfg, ins, image, n);
10755                                                 *sp = ins;
10756                                                 MONO_ADD_INS (cfg->cbb, ins);
10757                                         } 
10758                                         else {
10759                                                 NEW_PCONST (cfg, ins, NULL);
10760                                                 ins->type = STACK_OBJ;
10761                                                 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
10762                                                 if (!ins->inst_p0)
10763                                                         OUT_OF_MEMORY_FAILURE;
10764
10765                                                 *sp = ins;
10766                                                 MONO_ADD_INS (cfg->cbb, ins);
10767                                         }
10768                                 }
10769                         }
10770
10771                         sp++;
10772                         ip += 5;
10773                         break;
10774                 case CEE_NEWOBJ: {
10775                         MonoInst *iargs [2];
10776                         MonoMethodSignature *fsig;
10777                         MonoInst this_ins;
10778                         MonoInst *alloc;
10779                         MonoInst *vtable_arg = NULL;
10780
10781                         CHECK_OPSIZE (5);
10782                         token = read32 (ip + 1);
10783                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
10784                         if (!cmethod || mono_loader_get_last_error ())
10785                                 LOAD_ERROR;
10786                         fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
10787                         CHECK_CFG_ERROR;
10788
10789                         mono_save_token_info (cfg, image, token, cmethod);
10790
10791                         if (!mono_class_init (cmethod->klass))
10792                                 TYPE_LOAD_ERROR (cmethod->klass);
10793
10794                         context_used = mini_method_check_context_used (cfg, cmethod);
10795
10796                         if (mono_security_core_clr_enabled ())
10797                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
10798
10799                         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)) {
10800                                 emit_class_init (cfg, cmethod->klass);
10801                                 CHECK_TYPELOAD (cmethod->klass);
10802                         }
10803
10804                         /*
10805                         if (cfg->gsharedvt) {
10806                                 if (mini_is_gsharedvt_variable_signature (sig))
10807                                         GSHAREDVT_FAILURE (*ip);
10808                         }
10809                         */
10810
10811                         n = fsig->param_count;
10812                         CHECK_STACK (n);
10813
10814                         /* 
10815                          * Generate smaller code for the common newobj <exception> instruction in
10816                          * argument checking code.
10817                          */
10818                         if (cfg->cbb->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
10819                                 is_exception_class (cmethod->klass) && n <= 2 &&
10820                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
10821                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
10822                                 MonoInst *iargs [3];
10823
10824                                 sp -= n;
10825
10826                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
10827                                 switch (n) {
10828                                 case 0:
10829                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
10830                                         break;
10831                                 case 1:
10832                                         iargs [1] = sp [0];
10833                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
10834                                         break;
10835                                 case 2:
10836                                         iargs [1] = sp [0];
10837                                         iargs [2] = sp [1];
10838                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
10839                                         break;
10840                                 default:
10841                                         g_assert_not_reached ();
10842                                 }
10843
10844                                 ip += 5;
10845                                 inline_costs += 5;
10846                                 break;
10847                         }
10848
10849                         /* move the args to allow room for 'this' in the first position */
10850                         while (n--) {
10851                                 --sp;
10852                                 sp [1] = sp [0];
10853                         }
10854
10855                         /* check_call_signature () requires sp[0] to be set */
10856                         this_ins.type = STACK_OBJ;
10857                         sp [0] = &this_ins;
10858                         if (check_call_signature (cfg, fsig, sp))
10859                                 UNVERIFIED;
10860
10861                         iargs [0] = NULL;
10862
10863                         if (mini_class_is_system_array (cmethod->klass)) {
10864                                 *sp = emit_get_rgctx_method (cfg, context_used,
10865                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
10866
10867                                 /* Avoid varargs in the common case */
10868                                 if (fsig->param_count == 1)
10869                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
10870                                 else if (fsig->param_count == 2)
10871                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
10872                                 else if (fsig->param_count == 3)
10873                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
10874                                 else if (fsig->param_count == 4)
10875                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
10876                                 else
10877                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
10878                         } else if (cmethod->string_ctor) {
10879                                 g_assert (!context_used);
10880                                 g_assert (!vtable_arg);
10881                                 /* we simply pass a null pointer */
10882                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
10883                                 /* now call the string ctor */
10884                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
10885                         } else {
10886                                 if (cmethod->klass->valuetype) {
10887                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
10888                                         emit_init_rvar (cfg, iargs [0]->dreg, &cmethod->klass->byval_arg);
10889                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
10890
10891                                         alloc = NULL;
10892
10893                                         /* 
10894                                          * The code generated by mini_emit_virtual_call () expects
10895                                          * iargs [0] to be a boxed instance, but luckily the vcall
10896                                          * will be transformed into a normal call there.
10897                                          */
10898                                 } else if (context_used) {
10899                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
10900                                         *sp = alloc;
10901                                 } else {
10902                                         MonoVTable *vtable = NULL;
10903
10904                                         if (!cfg->compile_aot)
10905                                                 vtable = mono_class_vtable (cfg->domain, cmethod->klass);
10906                                         CHECK_TYPELOAD (cmethod->klass);
10907
10908                                         /*
10909                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
10910                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
10911                                          * As a workaround, we call class cctors before allocating objects.
10912                                          */
10913                                         if (mini_field_access_needs_cctor_run (cfg, method, cmethod->klass, vtable) && !(g_slist_find (class_inits, cmethod->klass))) {
10914                                                 emit_class_init (cfg, cmethod->klass);
10915                                                 if (cfg->verbose_level > 2)
10916                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
10917                                                 class_inits = g_slist_prepend (class_inits, cmethod->klass);
10918                                         }
10919
10920                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
10921                                         *sp = alloc;
10922                                 }
10923                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
10924
10925                                 if (alloc)
10926                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
10927
10928                                 /* Now call the actual ctor */
10929                                 handle_ctor_call (cfg, cmethod, fsig, context_used, sp, ip, &inline_costs);
10930                                 CHECK_CFG_EXCEPTION;
10931                         }
10932
10933                         if (alloc == NULL) {
10934                                 /* Valuetype */
10935                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
10936                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
10937                                 *sp++= ins;
10938                         } else {
10939                                 *sp++ = alloc;
10940                         }
10941                         
10942                         ip += 5;
10943                         inline_costs += 5;
10944                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip - header->code)))
10945                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10946                         break;
10947                 }
10948                 case CEE_CASTCLASS:
10949                         CHECK_STACK (1);
10950                         --sp;
10951                         CHECK_OPSIZE (5);
10952                         token = read32 (ip + 1);
10953                         klass = mini_get_class (method, token, generic_context);
10954                         CHECK_TYPELOAD (klass);
10955                         if (sp [0]->type != STACK_OBJ)
10956                                 UNVERIFIED;
10957
10958                         ins = handle_castclass (cfg, klass, *sp, ip, &inline_costs);
10959                         CHECK_CFG_EXCEPTION;
10960
10961                         *sp ++ = ins;
10962                         ip += 5;
10963                         break;
10964                 case CEE_ISINST: {
10965                         CHECK_STACK (1);
10966                         --sp;
10967                         CHECK_OPSIZE (5);
10968                         token = read32 (ip + 1);
10969                         klass = mini_get_class (method, token, generic_context);
10970                         CHECK_TYPELOAD (klass);
10971                         if (sp [0]->type != STACK_OBJ)
10972                                 UNVERIFIED;
10973  
10974                         context_used = mini_class_check_context_used (cfg, klass);
10975
10976                         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
10977                                 MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
10978                                 MonoInst *args [3];
10979                                 int idx;
10980
10981                                 /* obj */
10982                                 args [0] = *sp;
10983
10984                                 /* klass */
10985                                 EMIT_NEW_CLASSCONST (cfg, args [1], klass);
10986
10987                                 /* inline cache*/
10988                                 idx = get_castclass_cache_idx (cfg);
10989                                 args [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
10990
10991                                 *sp++ = mono_emit_method_call (cfg, mono_isinst, args, NULL);
10992                                 ip += 5;
10993                                 inline_costs += 2;
10994                         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
10995                                 MonoMethod *mono_isinst;
10996                                 MonoInst *iargs [1];
10997                                 int costs;
10998
10999                                 mono_isinst = mono_marshal_get_isinst (klass); 
11000                                 iargs [0] = sp [0];
11001
11002                                 costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), 
11003                                                                            iargs, ip, cfg->real_offset, TRUE);
11004                                 CHECK_CFG_EXCEPTION;
11005                                 g_assert (costs > 0);
11006                                 
11007                                 ip += 5;
11008                                 cfg->real_offset += 5;
11009
11010                                 *sp++= iargs [0];
11011
11012                                 inline_costs += costs;
11013                         }
11014                         else {
11015                                 ins = handle_isinst (cfg, klass, *sp, context_used);
11016                                 CHECK_CFG_EXCEPTION;
11017                                 *sp ++ = ins;
11018                                 ip += 5;
11019                         }
11020                         break;
11021                 }
11022                 case CEE_UNBOX_ANY: {
11023                         MonoInst *res, *addr;
11024
11025                         CHECK_STACK (1);
11026                         --sp;
11027                         CHECK_OPSIZE (5);
11028                         token = read32 (ip + 1);
11029                         klass = mini_get_class (method, token, generic_context);
11030                         CHECK_TYPELOAD (klass);
11031
11032                         mono_save_token_info (cfg, image, token, klass);
11033
11034                         context_used = mini_class_check_context_used (cfg, klass);
11035
11036                         if (mini_is_gsharedvt_klass (klass)) {
11037                                 res = handle_unbox_gsharedvt (cfg, klass, *sp);
11038                                 inline_costs += 2;
11039                         } else if (generic_class_is_reference_type (cfg, klass)) {
11040                                 res = handle_castclass (cfg, klass, *sp, ip, &inline_costs);
11041                                 CHECK_CFG_EXCEPTION;
11042                         } else if (mono_class_is_nullable (klass)) {
11043                                 res = handle_unbox_nullable (cfg, *sp, klass, context_used);
11044                         } else {
11045                                 addr = handle_unbox (cfg, klass, sp, context_used);
11046                                 /* LDOBJ */
11047                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11048                                 res = ins;
11049                                 inline_costs += 2;
11050                         }
11051
11052                         *sp ++ = res;
11053                         ip += 5;
11054                         break;
11055                 }
11056                 case CEE_BOX: {
11057                         MonoInst *val;
11058                         MonoClass *enum_class;
11059                         MonoMethod *has_flag;
11060
11061                         CHECK_STACK (1);
11062                         --sp;
11063                         val = *sp;
11064                         CHECK_OPSIZE (5);
11065                         token = read32 (ip + 1);
11066                         klass = mini_get_class (method, token, generic_context);
11067                         CHECK_TYPELOAD (klass);
11068
11069                         mono_save_token_info (cfg, image, token, klass);
11070
11071                         context_used = mini_class_check_context_used (cfg, klass);
11072
11073                         if (generic_class_is_reference_type (cfg, klass)) {
11074                                 *sp++ = val;
11075                                 ip += 5;
11076                                 break;
11077                         }
11078
11079                         if (klass == mono_defaults.void_class)
11080                                 UNVERIFIED;
11081                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
11082                                 UNVERIFIED;
11083                         /* frequent check in generic code: box (struct), brtrue */
11084
11085                         /*
11086                          * Look for:
11087                          *
11088                          *   <push int/long ptr>
11089                          *   <push int/long>
11090                          *   box MyFlags
11091                          *   constrained. MyFlags
11092                          *   callvirt instace bool class [mscorlib] System.Enum::HasFlag (class [mscorlib] System.Enum)
11093                          *
11094                          * If we find this sequence and the operand types on box and constrained
11095                          * are equal, we can emit a specialized instruction sequence instead of
11096                          * the very slow HasFlag () call.
11097                          */
11098                         if ((cfg->opt & MONO_OPT_INTRINS) &&
11099                             /* Cheap checks first. */
11100                             ip + 5 + 6 + 5 < end &&
11101                             ip [5] == CEE_PREFIX1 &&
11102                             ip [6] == CEE_CONSTRAINED_ &&
11103                             ip [11] == CEE_CALLVIRT &&
11104                             ip_in_bb (cfg, cfg->cbb, ip + 5 + 6 + 5) &&
11105                             mono_class_is_enum (klass) &&
11106                             (enum_class = mini_get_class (method, read32 (ip + 7), generic_context)) &&
11107                             (has_flag = mini_get_method (cfg, method, read32 (ip + 12), NULL, generic_context)) &&
11108                             has_flag->klass == mono_defaults.enum_class &&
11109                             !strcmp (has_flag->name, "HasFlag") &&
11110                             has_flag->signature->hasthis &&
11111                             has_flag->signature->param_count == 1) {
11112                                 CHECK_TYPELOAD (enum_class);
11113
11114                                 if (enum_class == klass) {
11115                                         MonoInst *enum_this, *enum_flag;
11116
11117                                         ip += 5 + 6 + 5;
11118                                         --sp;
11119
11120                                         enum_this = sp [0];
11121                                         enum_flag = sp [1];
11122
11123                                         *sp++ = handle_enum_has_flag (cfg, klass, enum_this, enum_flag);
11124                                         break;
11125                                 }
11126                         }
11127
11128                         // FIXME: LLVM can't handle the inconsistent bb linking
11129                         if (!mono_class_is_nullable (klass) &&
11130                                 !mini_is_gsharedvt_klass (klass) &&
11131                                 ip + 5 < end && ip_in_bb (cfg, cfg->cbb, ip + 5) &&
11132                                 (ip [5] == CEE_BRTRUE || 
11133                                  ip [5] == CEE_BRTRUE_S ||
11134                                  ip [5] == CEE_BRFALSE ||
11135                                  ip [5] == CEE_BRFALSE_S)) {
11136                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
11137                                 int dreg;
11138                                 MonoBasicBlock *true_bb, *false_bb;
11139
11140                                 ip += 5;
11141
11142                                 if (cfg->verbose_level > 3) {
11143                                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
11144                                         printf ("<box+brtrue opt>\n");
11145                                 }
11146
11147                                 switch (*ip) {
11148                                 case CEE_BRTRUE_S:
11149                                 case CEE_BRFALSE_S:
11150                                         CHECK_OPSIZE (2);
11151                                         ip++;
11152                                         target = ip + 1 + (signed char)(*ip);
11153                                         ip++;
11154                                         break;
11155                                 case CEE_BRTRUE:
11156                                 case CEE_BRFALSE:
11157                                         CHECK_OPSIZE (5);
11158                                         ip++;
11159                                         target = ip + 4 + (gint)(read32 (ip));
11160                                         ip += 4;
11161                                         break;
11162                                 default:
11163                                         g_assert_not_reached ();
11164                                 }
11165
11166                                 /* 
11167                                  * We need to link both bblocks, since it is needed for handling stack
11168                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
11169                                  * Branching to only one of them would lead to inconsistencies, so
11170                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
11171                                  */
11172                                 GET_BBLOCK (cfg, true_bb, target);
11173                                 GET_BBLOCK (cfg, false_bb, ip);
11174
11175                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
11176                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
11177
11178                                 if (sp != stack_start) {
11179                                         handle_stack_args (cfg, stack_start, sp - stack_start);
11180                                         sp = stack_start;
11181                                         CHECK_UNVERIFIABLE (cfg);
11182                                 }
11183
11184                                 if (COMPILE_LLVM (cfg)) {
11185                                         dreg = alloc_ireg (cfg);
11186                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
11187                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
11188
11189                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
11190                                 } else {
11191                                         /* The JIT can't eliminate the iconst+compare */
11192                                         MONO_INST_NEW (cfg, ins, OP_BR);
11193                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
11194                                         MONO_ADD_INS (cfg->cbb, ins);
11195                                 }
11196
11197                                 start_new_bblock = 1;
11198                                 break;
11199                         }
11200
11201                         *sp++ = handle_box (cfg, val, klass, context_used);
11202
11203                         CHECK_CFG_EXCEPTION;
11204                         ip += 5;
11205                         inline_costs += 1;
11206                         break;
11207                 }
11208                 case CEE_UNBOX: {
11209                         CHECK_STACK (1);
11210                         --sp;
11211                         CHECK_OPSIZE (5);
11212                         token = read32 (ip + 1);
11213                         klass = mini_get_class (method, token, generic_context);
11214                         CHECK_TYPELOAD (klass);
11215
11216                         mono_save_token_info (cfg, image, token, klass);
11217
11218                         context_used = mini_class_check_context_used (cfg, klass);
11219
11220                         if (mono_class_is_nullable (klass)) {
11221                                 MonoInst *val;
11222
11223                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
11224                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
11225
11226                                 *sp++= ins;
11227                         } else {
11228                                 ins = handle_unbox (cfg, klass, sp, context_used);
11229                                 *sp++ = ins;
11230                         }
11231                         ip += 5;
11232                         inline_costs += 2;
11233                         break;
11234                 }
11235                 case CEE_LDFLD:
11236                 case CEE_LDFLDA:
11237                 case CEE_STFLD:
11238                 case CEE_LDSFLD:
11239                 case CEE_LDSFLDA:
11240                 case CEE_STSFLD: {
11241                         MonoClassField *field;
11242 #ifndef DISABLE_REMOTING
11243                         int costs;
11244 #endif
11245                         guint foffset;
11246                         gboolean is_instance;
11247                         int op;
11248                         gpointer addr = NULL;
11249                         gboolean is_special_static;
11250                         MonoType *ftype;
11251                         MonoInst *store_val = NULL;
11252                         MonoInst *thread_ins;
11253
11254                         op = *ip;
11255                         is_instance = (op == CEE_LDFLD || op == CEE_LDFLDA || op == CEE_STFLD);
11256                         if (is_instance) {
11257                                 if (op == CEE_STFLD) {
11258                                         CHECK_STACK (2);
11259                                         sp -= 2;
11260                                         store_val = sp [1];
11261                                 } else {
11262                                         CHECK_STACK (1);
11263                                         --sp;
11264                                 }
11265                                 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
11266                                         UNVERIFIED;
11267                                 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
11268                                         UNVERIFIED;
11269                         } else {
11270                                 if (op == CEE_STSFLD) {
11271                                         CHECK_STACK (1);
11272                                         sp--;
11273                                         store_val = sp [0];
11274                                 }
11275                         }
11276
11277                         CHECK_OPSIZE (5);
11278                         token = read32 (ip + 1);
11279                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
11280                                 field = (MonoClassField *)mono_method_get_wrapper_data (method, token);
11281                                 klass = field->parent;
11282                         }
11283                         else {
11284                                 field = mono_field_from_token_checked (image, token, &klass, generic_context, &cfg->error);
11285                                 CHECK_CFG_ERROR;
11286                         }
11287                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
11288                                 FIELD_ACCESS_FAILURE (method, field);
11289                         mono_class_init (klass);
11290
11291                         /* if the class is Critical then transparent code cannot access it's fields */
11292                         if (!is_instance && mono_security_core_clr_enabled ())
11293                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
11294
11295                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
11296                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
11297                         if (mono_security_core_clr_enabled ())
11298                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
11299                         */
11300
11301                         ftype = mono_field_get_type (field);
11302
11303                         /*
11304                          * LDFLD etc. is usable on static fields as well, so convert those cases to
11305                          * the static case.
11306                          */
11307                         if (is_instance && ftype->attrs & FIELD_ATTRIBUTE_STATIC) {
11308                                 switch (op) {
11309                                 case CEE_LDFLD:
11310                                         op = CEE_LDSFLD;
11311                                         break;
11312                                 case CEE_STFLD:
11313                                         op = CEE_STSFLD;
11314                                         break;
11315                                 case CEE_LDFLDA:
11316                                         op = CEE_LDSFLDA;
11317                                         break;
11318                                 default:
11319                                         g_assert_not_reached ();
11320                                 }
11321                                 is_instance = FALSE;
11322                         }
11323
11324                         context_used = mini_class_check_context_used (cfg, klass);
11325
11326                         /* INSTANCE CASE */
11327
11328                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
11329                         if (op == CEE_STFLD) {
11330                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
11331                                         UNVERIFIED;
11332 #ifndef DISABLE_REMOTING
11333                                 if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
11334                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
11335                                         MonoInst *iargs [5];
11336
11337                                         GSHAREDVT_FAILURE (op);
11338
11339                                         iargs [0] = sp [0];
11340                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11341                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
11342                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
11343                                                     field->offset);
11344                                         iargs [4] = sp [1];
11345
11346                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
11347                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
11348                                                                                            iargs, ip, cfg->real_offset, TRUE);
11349                                                 CHECK_CFG_EXCEPTION;
11350                                                 g_assert (costs > 0);
11351                                                       
11352                                                 cfg->real_offset += 5;
11353
11354                                                 inline_costs += costs;
11355                                         } else {
11356                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
11357                                         }
11358                                 } else
11359 #endif
11360                                 {
11361                                         MonoInst *store;
11362
11363                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
11364
11365                                         if (mini_is_gsharedvt_klass (klass)) {
11366                                                 MonoInst *offset_ins;
11367
11368                                                 context_used = mini_class_check_context_used (cfg, klass);
11369
11370                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11371                                                 /* The value is offset by 1 */
11372                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11373                                                 dreg = alloc_ireg_mp (cfg);
11374                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11375                                                 /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
11376                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
11377                                         } else {
11378                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
11379                                         }
11380                                         if (sp [0]->opcode != OP_LDADDR)
11381                                                 store->flags |= MONO_INST_FAULT;
11382
11383                                 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)) {
11384                                         /* insert call to write barrier */
11385                                         MonoInst *ptr;
11386                                         int dreg;
11387
11388                                         dreg = alloc_ireg_mp (cfg);
11389                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
11390                                         emit_write_barrier (cfg, ptr, sp [1]);
11391                                 }
11392
11393                                         store->flags |= ins_flag;
11394                                 }
11395                                 ins_flag = 0;
11396                                 ip += 5;
11397                                 break;
11398                         }
11399
11400 #ifndef DISABLE_REMOTING
11401                         if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
11402                                 MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
11403                                 MonoInst *iargs [4];
11404
11405                                 GSHAREDVT_FAILURE (op);
11406
11407                                 iargs [0] = sp [0];
11408                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11409                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
11410                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
11411                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
11412                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
11413                                                                                    iargs, ip, cfg->real_offset, TRUE);
11414                                         CHECK_CFG_EXCEPTION;
11415                                         g_assert (costs > 0);
11416                                                       
11417                                         cfg->real_offset += 5;
11418
11419                                         *sp++ = iargs [0];
11420
11421                                         inline_costs += costs;
11422                                 } else {
11423                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
11424                                         *sp++ = ins;
11425                                 }
11426                         } else 
11427 #endif
11428                         if (is_instance) {
11429                                 if (sp [0]->type == STACK_VTYPE) {
11430                                         MonoInst *var;
11431
11432                                         /* Have to compute the address of the variable */
11433
11434                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
11435                                         if (!var)
11436                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
11437                                         else
11438                                                 g_assert (var->klass == klass);
11439                                         
11440                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
11441                                         sp [0] = ins;
11442                                 }
11443
11444                                 if (op == CEE_LDFLDA) {
11445                                         if (sp [0]->type == STACK_OBJ) {
11446                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
11447                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
11448                                         }
11449
11450                                         dreg = alloc_ireg_mp (cfg);
11451
11452                                         if (mini_is_gsharedvt_klass (klass)) {
11453                                                 MonoInst *offset_ins;
11454
11455                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11456                                                 /* The value is offset by 1 */
11457                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11458                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11459                                         } else {
11460                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
11461                                         }
11462                                         ins->klass = mono_class_from_mono_type (field->type);
11463                                         ins->type = STACK_MP;
11464                                         *sp++ = ins;
11465                                 } else {
11466                                         MonoInst *load;
11467
11468                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
11469
11470                                         if (mini_is_gsharedvt_klass (klass)) {
11471                                                 MonoInst *offset_ins;
11472
11473                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11474                                                 /* The value is offset by 1 */
11475                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11476                                                 dreg = alloc_ireg_mp (cfg);
11477                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11478                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
11479                                         } else {
11480                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
11481                                         }
11482                                         load->flags |= ins_flag;
11483                                         if (sp [0]->opcode != OP_LDADDR)
11484                                                 load->flags |= MONO_INST_FAULT;
11485                                         *sp++ = load;
11486                                 }
11487                         }
11488
11489                         if (is_instance) {
11490                                 ins_flag = 0;
11491                                 ip += 5;
11492                                 break;
11493                         }
11494
11495                         /* STATIC CASE */
11496                         context_used = mini_class_check_context_used (cfg, klass);
11497
11498                         if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL)
11499                                 UNVERIFIED;
11500
11501                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
11502                          * to be called here.
11503                          */
11504                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
11505                                 mono_class_vtable (cfg->domain, klass);
11506                                 CHECK_TYPELOAD (klass);
11507                         }
11508                         mono_domain_lock (cfg->domain);
11509                         if (cfg->domain->special_static_fields)
11510                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
11511                         mono_domain_unlock (cfg->domain);
11512
11513                         is_special_static = mono_class_field_is_special_static (field);
11514
11515                         if (is_special_static && ((gsize)addr & 0x80000000) == 0)
11516                                 thread_ins = mono_get_thread_intrinsic (cfg);
11517                         else
11518                                 thread_ins = NULL;
11519
11520                         /* Generate IR to compute the field address */
11521                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && thread_ins && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
11522                                 /*
11523                                  * Fast access to TLS data
11524                                  * Inline version of get_thread_static_data () in
11525                                  * threads.c.
11526                                  */
11527                                 guint32 offset;
11528                                 int idx, static_data_reg, array_reg, dreg;
11529
11530                                 GSHAREDVT_FAILURE (op);
11531
11532                                 MONO_ADD_INS (cfg->cbb, thread_ins);
11533                                 static_data_reg = alloc_ireg (cfg);
11534                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
11535
11536                                 if (cfg->compile_aot) {
11537                                         int offset_reg, offset2_reg, idx_reg;
11538
11539                                         /* For TLS variables, this will return the TLS offset */
11540                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
11541                                         offset_reg = ins->dreg;
11542                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
11543                                         idx_reg = alloc_ireg (cfg);
11544                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, idx_reg, offset_reg, 0x3f);
11545                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
11546                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
11547                                         array_reg = alloc_ireg (cfg);
11548                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
11549                                         offset2_reg = alloc_ireg (cfg);
11550                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, offset2_reg, offset_reg, 6);
11551                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset2_reg, 0x1ffffff);
11552                                         dreg = alloc_ireg (cfg);
11553                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
11554                                 } else {
11555                                         offset = (gsize)addr & 0x7fffffff;
11556                                         idx = offset & 0x3f;
11557
11558                                         array_reg = alloc_ireg (cfg);
11559                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
11560                                         dreg = alloc_ireg (cfg);
11561                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, ((offset >> 6) & 0x1ffffff));
11562                                 }
11563                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
11564                                         (cfg->compile_aot && is_special_static) ||
11565                                         (context_used && is_special_static)) {
11566                                 MonoInst *iargs [2];
11567
11568                                 g_assert (field->parent);
11569                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11570                                 if (context_used) {
11571                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
11572                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
11573                                 } else {
11574                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11575                                 }
11576                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11577                         } else if (context_used) {
11578                                 MonoInst *static_data;
11579
11580                                 /*
11581                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
11582                                         method->klass->name_space, method->klass->name, method->name,
11583                                         depth, field->offset);
11584                                 */
11585
11586                                 if (mono_class_needs_cctor_run (klass, method))
11587                                         emit_class_init (cfg, klass);
11588
11589                                 /*
11590                                  * The pointer we're computing here is
11591                                  *
11592                                  *   super_info.static_data + field->offset
11593                                  */
11594                                 static_data = emit_get_rgctx_klass (cfg, context_used,
11595                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
11596
11597                                 if (mini_is_gsharedvt_klass (klass)) {
11598                                         MonoInst *offset_ins;
11599
11600                                         offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11601                                         /* The value is offset by 1 */
11602                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11603                                         dreg = alloc_ireg_mp (cfg);
11604                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
11605                                 } else if (field->offset == 0) {
11606                                         ins = static_data;
11607                                 } else {
11608                                         int addr_reg = mono_alloc_preg (cfg);
11609                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
11610                                 }
11611                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
11612                                 MonoInst *iargs [2];
11613
11614                                 g_assert (field->parent);
11615                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11616                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11617                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11618                         } else {
11619                                 MonoVTable *vtable = NULL;
11620
11621                                 if (!cfg->compile_aot)
11622                                         vtable = mono_class_vtable (cfg->domain, klass);
11623                                 CHECK_TYPELOAD (klass);
11624
11625                                 if (!addr) {
11626                                         if (mini_field_access_needs_cctor_run (cfg, method, klass, vtable)) {
11627                                                 if (!(g_slist_find (class_inits, klass))) {
11628                                                         emit_class_init (cfg, klass);
11629                                                         if (cfg->verbose_level > 2)
11630                                                                 printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
11631                                                         class_inits = g_slist_prepend (class_inits, klass);
11632                                                 }
11633                                         } else {
11634                                                 if (cfg->run_cctors) {
11635                                                         MonoException *ex;
11636                                                         /* This makes so that inline cannot trigger */
11637                                                         /* .cctors: too many apps depend on them */
11638                                                         /* running with a specific order... */
11639                                                         g_assert (vtable);
11640                                                         if (! vtable->initialized)
11641                                                                 INLINE_FAILURE ("class init");
11642                                                         ex = mono_runtime_class_init_full (vtable, FALSE);
11643                                                         if (ex) {
11644                                                                 set_exception_object (cfg, ex);
11645                                                                 goto exception_exit;
11646                                                         }
11647                                                 }
11648                                         }
11649                                         if (cfg->compile_aot)
11650                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
11651                                         else {
11652                                                 g_assert (vtable);
11653                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11654                                                 g_assert (addr);
11655                                                 EMIT_NEW_PCONST (cfg, ins, addr);
11656                                         }
11657                                 } else {
11658                                         MonoInst *iargs [1];
11659                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
11660                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
11661                                 }
11662                         }
11663
11664                         /* Generate IR to do the actual load/store operation */
11665
11666                         if ((op == CEE_STFLD || op == CEE_STSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11667                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11668                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11669                         }
11670
11671                         if (op == CEE_LDSFLDA) {
11672                                 ins->klass = mono_class_from_mono_type (ftype);
11673                                 ins->type = STACK_PTR;
11674                                 *sp++ = ins;
11675                         } else if (op == CEE_STSFLD) {
11676                                 MonoInst *store;
11677
11678                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
11679                                 store->flags |= ins_flag;
11680                         } else {
11681                                 gboolean is_const = FALSE;
11682                                 MonoVTable *vtable = NULL;
11683                                 gpointer addr = NULL;
11684
11685                                 if (!context_used) {
11686                                         vtable = mono_class_vtable (cfg->domain, klass);
11687                                         CHECK_TYPELOAD (klass);
11688                                 }
11689                                 if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) ||
11690                                                 (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) {
11691                                         int ro_type = ftype->type;
11692                                         if (!addr)
11693                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11694                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
11695                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
11696                                         }
11697
11698                                         GSHAREDVT_FAILURE (op);
11699
11700                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
11701                                         is_const = TRUE;
11702                                         switch (ro_type) {
11703                                         case MONO_TYPE_BOOLEAN:
11704                                         case MONO_TYPE_U1:
11705                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
11706                                                 sp++;
11707                                                 break;
11708                                         case MONO_TYPE_I1:
11709                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
11710                                                 sp++;
11711                                                 break;                                          
11712                                         case MONO_TYPE_CHAR:
11713                                         case MONO_TYPE_U2:
11714                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
11715                                                 sp++;
11716                                                 break;
11717                                         case MONO_TYPE_I2:
11718                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
11719                                                 sp++;
11720                                                 break;
11721                                                 break;
11722                                         case MONO_TYPE_I4:
11723                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
11724                                                 sp++;
11725                                                 break;                                          
11726                                         case MONO_TYPE_U4:
11727                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
11728                                                 sp++;
11729                                                 break;
11730                                         case MONO_TYPE_I:
11731                                         case MONO_TYPE_U:
11732                                         case MONO_TYPE_PTR:
11733                                         case MONO_TYPE_FNPTR:
11734                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11735                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
11736                                                 sp++;
11737                                                 break;
11738                                         case MONO_TYPE_STRING:
11739                                         case MONO_TYPE_OBJECT:
11740                                         case MONO_TYPE_CLASS:
11741                                         case MONO_TYPE_SZARRAY:
11742                                         case MONO_TYPE_ARRAY:
11743                                                 if (!mono_gc_is_moving ()) {
11744                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11745                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
11746                                                         sp++;
11747                                                 } else {
11748                                                         is_const = FALSE;
11749                                                 }
11750                                                 break;
11751                                         case MONO_TYPE_I8:
11752                                         case MONO_TYPE_U8:
11753                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
11754                                                 sp++;
11755                                                 break;
11756                                         case MONO_TYPE_R4:
11757                                         case MONO_TYPE_R8:
11758                                         case MONO_TYPE_VALUETYPE:
11759                                         default:
11760                                                 is_const = FALSE;
11761                                                 break;
11762                                         }
11763                                 }
11764
11765                                 if (!is_const) {
11766                                         MonoInst *load;
11767
11768                                         CHECK_STACK_OVF (1);
11769
11770                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
11771                                         load->flags |= ins_flag;
11772                                         ins_flag = 0;
11773                                         *sp++ = load;
11774                                 }
11775                         }
11776
11777                         if ((op == CEE_LDFLD || op == CEE_LDSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11778                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
11779                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
11780                         }
11781
11782                         ins_flag = 0;
11783                         ip += 5;
11784                         break;
11785                 }
11786                 case CEE_STOBJ:
11787                         CHECK_STACK (2);
11788                         sp -= 2;
11789                         CHECK_OPSIZE (5);
11790                         token = read32 (ip + 1);
11791                         klass = mini_get_class (method, token, generic_context);
11792                         CHECK_TYPELOAD (klass);
11793                         if (ins_flag & MONO_INST_VOLATILE) {
11794                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11795                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11796                         }
11797                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
11798                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
11799                         ins->flags |= ins_flag;
11800                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
11801                                         generic_class_is_reference_type (cfg, klass)) {
11802                                 /* insert call to write barrier */
11803                                 emit_write_barrier (cfg, sp [0], sp [1]);
11804                         }
11805                         ins_flag = 0;
11806                         ip += 5;
11807                         inline_costs += 1;
11808                         break;
11809
11810                         /*
11811                          * Array opcodes
11812                          */
11813                 case CEE_NEWARR: {
11814                         MonoInst *len_ins;
11815                         const char *data_ptr;
11816                         int data_size = 0;
11817                         guint32 field_token;
11818
11819                         CHECK_STACK (1);
11820                         --sp;
11821
11822                         CHECK_OPSIZE (5);
11823                         token = read32 (ip + 1);
11824
11825                         klass = mini_get_class (method, token, generic_context);
11826                         CHECK_TYPELOAD (klass);
11827
11828                         context_used = mini_class_check_context_used (cfg, klass);
11829
11830                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
11831                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_OVF_U4);
11832                                 ins->sreg1 = sp [0]->dreg;
11833                                 ins->type = STACK_I4;
11834                                 ins->dreg = alloc_ireg (cfg);
11835                                 MONO_ADD_INS (cfg->cbb, ins);
11836                                 *sp = mono_decompose_opcode (cfg, ins);
11837                         }
11838
11839                         if (context_used) {
11840                                 MonoInst *args [3];
11841                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11842                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
11843
11844                                 /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
11845
11846                                 /* vtable */
11847                                 args [0] = emit_get_rgctx_klass (cfg, context_used,
11848                                         array_class, MONO_RGCTX_INFO_VTABLE);
11849                                 /* array len */
11850                                 args [1] = sp [0];
11851
11852                                 if (managed_alloc)
11853                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
11854                                 else
11855                                         ins = mono_emit_jit_icall (cfg, mono_array_new_specific, args);
11856                         } else {
11857                                 if (cfg->opt & MONO_OPT_SHARED) {
11858                                         /* Decompose now to avoid problems with references to the domainvar */
11859                                         MonoInst *iargs [3];
11860
11861                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11862                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11863                                         iargs [2] = sp [0];
11864
11865                                         ins = mono_emit_jit_icall (cfg, mono_array_new, iargs);
11866                                 } else {
11867                                         /* Decompose later since it is needed by abcrem */
11868                                         MonoClass *array_type = mono_array_class_get (klass, 1);
11869                                         mono_class_vtable (cfg->domain, array_type);
11870                                         CHECK_TYPELOAD (array_type);
11871
11872                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
11873                                         ins->dreg = alloc_ireg_ref (cfg);
11874                                         ins->sreg1 = sp [0]->dreg;
11875                                         ins->inst_newa_class = klass;
11876                                         ins->type = STACK_OBJ;
11877                                         ins->klass = array_type;
11878                                         MONO_ADD_INS (cfg->cbb, ins);
11879                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11880                                         cfg->cbb->has_array_access = TRUE;
11881
11882                                         /* Needed so mono_emit_load_get_addr () gets called */
11883                                         mono_get_got_var (cfg);
11884                                 }
11885                         }
11886
11887                         len_ins = sp [0];
11888                         ip += 5;
11889                         *sp++ = ins;
11890                         inline_costs += 1;
11891
11892                         /* 
11893                          * we inline/optimize the initialization sequence if possible.
11894                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
11895                          * for small sizes open code the memcpy
11896                          * ensure the rva field is big enough
11897                          */
11898                         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))) {
11899                                 MonoMethod *memcpy_method = get_memcpy_method ();
11900                                 MonoInst *iargs [3];
11901                                 int add_reg = alloc_ireg_mp (cfg);
11902
11903                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, MONO_STRUCT_OFFSET (MonoArray, vector));
11904                                 if (cfg->compile_aot) {
11905                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
11906                                 } else {
11907                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
11908                                 }
11909                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
11910                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
11911                                 ip += 11;
11912                         }
11913
11914                         break;
11915                 }
11916                 case CEE_LDLEN:
11917                         CHECK_STACK (1);
11918                         --sp;
11919                         if (sp [0]->type != STACK_OBJ)
11920                                 UNVERIFIED;
11921
11922                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
11923                         ins->dreg = alloc_preg (cfg);
11924                         ins->sreg1 = sp [0]->dreg;
11925                         ins->type = STACK_I4;
11926                         /* This flag will be inherited by the decomposition */
11927                         ins->flags |= MONO_INST_FAULT;
11928                         MONO_ADD_INS (cfg->cbb, ins);
11929                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11930                         cfg->cbb->has_array_access = TRUE;
11931                         ip ++;
11932                         *sp++ = ins;
11933                         break;
11934                 case CEE_LDELEMA:
11935                         CHECK_STACK (2);
11936                         sp -= 2;
11937                         CHECK_OPSIZE (5);
11938                         if (sp [0]->type != STACK_OBJ)
11939                                 UNVERIFIED;
11940
11941                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11942
11943                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11944                         CHECK_TYPELOAD (klass);
11945                         /* we need to make sure that this array is exactly the type it needs
11946                          * to be for correctness. the wrappers are lax with their usage
11947                          * so we need to ignore them here
11948                          */
11949                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
11950                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11951                                 mini_emit_check_array_type (cfg, sp [0], array_class);
11952                                 CHECK_TYPELOAD (array_class);
11953                         }
11954
11955                         readonly = FALSE;
11956                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11957                         *sp++ = ins;
11958                         ip += 5;
11959                         break;
11960                 case CEE_LDELEM:
11961                 case CEE_LDELEM_I1:
11962                 case CEE_LDELEM_U1:
11963                 case CEE_LDELEM_I2:
11964                 case CEE_LDELEM_U2:
11965                 case CEE_LDELEM_I4:
11966                 case CEE_LDELEM_U4:
11967                 case CEE_LDELEM_I8:
11968                 case CEE_LDELEM_I:
11969                 case CEE_LDELEM_R4:
11970                 case CEE_LDELEM_R8:
11971                 case CEE_LDELEM_REF: {
11972                         MonoInst *addr;
11973
11974                         CHECK_STACK (2);
11975                         sp -= 2;
11976
11977                         if (*ip == CEE_LDELEM) {
11978                                 CHECK_OPSIZE (5);
11979                                 token = read32 (ip + 1);
11980                                 klass = mini_get_class (method, token, generic_context);
11981                                 CHECK_TYPELOAD (klass);
11982                                 mono_class_init (klass);
11983                         }
11984                         else
11985                                 klass = array_access_to_klass (*ip);
11986
11987                         if (sp [0]->type != STACK_OBJ)
11988                                 UNVERIFIED;
11989
11990                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11991
11992                         if (mini_is_gsharedvt_variable_klass (klass)) {
11993                                 // FIXME-VT: OP_ICONST optimization
11994                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11995                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11996                                 ins->opcode = OP_LOADV_MEMBASE;
11997                         } else if (sp [1]->opcode == OP_ICONST) {
11998                                 int array_reg = sp [0]->dreg;
11999                                 int index_reg = sp [1]->dreg;
12000                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
12001
12002                                 if (SIZEOF_REGISTER == 8 && COMPILE_LLVM (cfg))
12003                                         MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, index_reg);
12004
12005                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
12006                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
12007                         } else {
12008                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
12009                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
12010                         }
12011                         *sp++ = ins;
12012                         if (*ip == CEE_LDELEM)
12013                                 ip += 5;
12014                         else
12015                                 ++ip;
12016                         break;
12017                 }
12018                 case CEE_STELEM_I:
12019                 case CEE_STELEM_I1:
12020                 case CEE_STELEM_I2:
12021                 case CEE_STELEM_I4:
12022                 case CEE_STELEM_I8:
12023                 case CEE_STELEM_R4:
12024                 case CEE_STELEM_R8:
12025                 case CEE_STELEM_REF:
12026                 case CEE_STELEM: {
12027                         CHECK_STACK (3);
12028                         sp -= 3;
12029
12030                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
12031
12032                         if (*ip == CEE_STELEM) {
12033                                 CHECK_OPSIZE (5);
12034                                 token = read32 (ip + 1);
12035                                 klass = mini_get_class (method, token, generic_context);
12036                                 CHECK_TYPELOAD (klass);
12037                                 mono_class_init (klass);
12038                         }
12039                         else
12040                                 klass = array_access_to_klass (*ip);
12041
12042                         if (sp [0]->type != STACK_OBJ)
12043                                 UNVERIFIED;
12044
12045                         emit_array_store (cfg, klass, sp, TRUE);
12046
12047                         if (*ip == CEE_STELEM)
12048                                 ip += 5;
12049                         else
12050                                 ++ip;
12051                         inline_costs += 1;
12052                         break;
12053                 }
12054                 case CEE_CKFINITE: {
12055                         CHECK_STACK (1);
12056                         --sp;
12057
12058                         if (cfg->llvm_only) {
12059                                 MonoInst *iargs [1];
12060
12061                                 iargs [0] = sp [0];
12062                                 *sp++ = mono_emit_jit_icall (cfg, mono_ckfinite, iargs);
12063                         } else  {
12064                                 MONO_INST_NEW (cfg, ins, OP_CKFINITE);
12065                                 ins->sreg1 = sp [0]->dreg;
12066                                 ins->dreg = alloc_freg (cfg);
12067                                 ins->type = STACK_R8;
12068                                 MONO_ADD_INS (cfg->cbb, ins);
12069
12070                                 *sp++ = mono_decompose_opcode (cfg, ins);
12071                         }
12072
12073                         ++ip;
12074                         break;
12075                 }
12076                 case CEE_REFANYVAL: {
12077                         MonoInst *src_var, *src;
12078
12079                         int klass_reg = alloc_preg (cfg);
12080                         int dreg = alloc_preg (cfg);
12081
12082                         GSHAREDVT_FAILURE (*ip);
12083
12084                         CHECK_STACK (1);
12085                         MONO_INST_NEW (cfg, ins, *ip);
12086                         --sp;
12087                         CHECK_OPSIZE (5);
12088                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
12089                         CHECK_TYPELOAD (klass);
12090
12091                         context_used = mini_class_check_context_used (cfg, klass);
12092
12093                         // FIXME:
12094                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12095                         if (!src_var)
12096                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
12097                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
12098                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass));
12099
12100                         if (context_used) {
12101                                 MonoInst *klass_ins;
12102
12103                                 klass_ins = emit_get_rgctx_klass (cfg, context_used,
12104                                                 klass, MONO_RGCTX_INFO_KLASS);
12105
12106                                 // FIXME:
12107                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
12108                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
12109                         } else {
12110                                 mini_emit_class_check (cfg, klass_reg, klass);
12111                         }
12112                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value));
12113                         ins->type = STACK_MP;
12114                         ins->klass = klass;
12115                         *sp++ = ins;
12116                         ip += 5;
12117                         break;
12118                 }
12119                 case CEE_MKREFANY: {
12120                         MonoInst *loc, *addr;
12121
12122                         GSHAREDVT_FAILURE (*ip);
12123
12124                         CHECK_STACK (1);
12125                         MONO_INST_NEW (cfg, ins, *ip);
12126                         --sp;
12127                         CHECK_OPSIZE (5);
12128                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
12129                         CHECK_TYPELOAD (klass);
12130
12131                         context_used = mini_class_check_context_used (cfg, klass);
12132
12133                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
12134                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
12135
12136                         if (context_used) {
12137                                 MonoInst *const_ins;
12138                                 int type_reg = alloc_preg (cfg);
12139
12140                                 const_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
12141                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
12142                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
12143                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
12144                         } else if (cfg->compile_aot) {
12145                                 int const_reg = alloc_preg (cfg);
12146                                 int type_reg = alloc_preg (cfg);
12147
12148                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
12149                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
12150                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
12151                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
12152                         } else {
12153                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), &klass->byval_arg);
12154                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), klass);
12155                         }
12156                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
12157
12158                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
12159                         ins->type = STACK_VTYPE;
12160                         ins->klass = mono_defaults.typed_reference_class;
12161                         *sp++ = ins;
12162                         ip += 5;
12163                         break;
12164                 }
12165                 case CEE_LDTOKEN: {
12166                         gpointer handle;
12167                         MonoClass *handle_class;
12168
12169                         CHECK_STACK_OVF (1);
12170
12171                         CHECK_OPSIZE (5);
12172                         n = read32 (ip + 1);
12173
12174                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
12175                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
12176                                 handle = mono_method_get_wrapper_data (method, n);
12177                                 handle_class = (MonoClass *)mono_method_get_wrapper_data (method, n + 1);
12178                                 if (handle_class == mono_defaults.typehandle_class)
12179                                         handle = &((MonoClass*)handle)->byval_arg;
12180                         }
12181                         else {
12182                                 handle = mono_ldtoken_checked (image, n, &handle_class, generic_context, &cfg->error);
12183                                 CHECK_CFG_ERROR;
12184                         }
12185                         if (!handle)
12186                                 LOAD_ERROR;
12187                         mono_class_init (handle_class);
12188                         if (cfg->gshared) {
12189                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
12190                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
12191                                         /* This case handles ldtoken
12192                                            of an open type, like for
12193                                            typeof(Gen<>). */
12194                                         context_used = 0;
12195                                 } else if (handle_class == mono_defaults.typehandle_class) {
12196                                         context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type ((MonoType *)handle));
12197                                 } else if (handle_class == mono_defaults.fieldhandle_class)
12198                                         context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
12199                                 else if (handle_class == mono_defaults.methodhandle_class)
12200                                         context_used = mini_method_check_context_used (cfg, (MonoMethod *)handle);
12201                                 else
12202                                         g_assert_not_reached ();
12203                         }
12204
12205                         if ((cfg->opt & MONO_OPT_SHARED) &&
12206                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
12207                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
12208                                 MonoInst *addr, *vtvar, *iargs [3];
12209                                 int method_context_used;
12210
12211                                 method_context_used = mini_method_check_context_used (cfg, method);
12212
12213                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
12214
12215                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
12216                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
12217                                 if (method_context_used) {
12218                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
12219                                                 method, MONO_RGCTX_INFO_METHOD);
12220                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
12221                                 } else {
12222                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
12223                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
12224                                 }
12225                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12226
12227                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
12228
12229                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12230                         } else {
12231                                 if ((ip + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 5) && 
12232                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
12233                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
12234                                         (cmethod->klass == mono_defaults.systemtype_class) &&
12235                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
12236                                         MonoClass *tclass = mono_class_from_mono_type ((MonoType *)handle);
12237
12238                                         mono_class_init (tclass);
12239                                         if (context_used) {
12240                                                 ins = emit_get_rgctx_klass (cfg, context_used,
12241                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
12242                                         } else if (cfg->compile_aot) {
12243                                                 if (method->wrapper_type) {
12244                                                         mono_error_init (&error); //got to do it since there are multiple conditionals below
12245                                                         if (mono_class_get_checked (tclass->image, tclass->type_token, &error) == tclass && !generic_context) {
12246                                                                 /* Special case for static synchronized wrappers */
12247                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
12248                                                         } else {
12249                                                                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
12250                                                                 /* FIXME: n is not a normal token */
12251                                                                 DISABLE_AOT (cfg);
12252                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12253                                                         }
12254                                                 } else {
12255                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
12256                                                 }
12257                                         } else {
12258                                                 EMIT_NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, (MonoType *)handle));
12259                                         }
12260                                         ins->type = STACK_OBJ;
12261                                         ins->klass = cmethod->klass;
12262                                         ip += 5;
12263                                 } else {
12264                                         MonoInst *addr, *vtvar;
12265
12266                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
12267
12268                                         if (context_used) {
12269                                                 if (handle_class == mono_defaults.typehandle_class) {
12270                                                         ins = emit_get_rgctx_klass (cfg, context_used,
12271                                                                         mono_class_from_mono_type ((MonoType *)handle),
12272                                                                         MONO_RGCTX_INFO_TYPE);
12273                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
12274                                                         ins = emit_get_rgctx_method (cfg, context_used,
12275                                                                         (MonoMethod *)handle, MONO_RGCTX_INFO_METHOD);
12276                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
12277                                                         ins = emit_get_rgctx_field (cfg, context_used,
12278                                                                         (MonoClassField *)handle, MONO_RGCTX_INFO_CLASS_FIELD);
12279                                                 } else {
12280                                                         g_assert_not_reached ();
12281                                                 }
12282                                         } else if (cfg->compile_aot) {
12283                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n, generic_context);
12284                                         } else {
12285                                                 EMIT_NEW_PCONST (cfg, ins, handle);
12286                                         }
12287                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12288                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
12289                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12290                                 }
12291                         }
12292
12293                         *sp++ = ins;
12294                         ip += 5;
12295                         break;
12296                 }
12297                 case CEE_THROW:
12298                         CHECK_STACK (1);
12299                         MONO_INST_NEW (cfg, ins, OP_THROW);
12300                         --sp;
12301                         ins->sreg1 = sp [0]->dreg;
12302                         ip++;
12303                         cfg->cbb->out_of_line = TRUE;
12304                         MONO_ADD_INS (cfg->cbb, ins);
12305                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
12306                         MONO_ADD_INS (cfg->cbb, ins);
12307                         sp = stack_start;
12308                         
12309                         link_bblock (cfg, cfg->cbb, end_bblock);
12310                         start_new_bblock = 1;
12311                         /* This can complicate code generation for llvm since the return value might not be defined */
12312                         if (COMPILE_LLVM (cfg))
12313                                 INLINE_FAILURE ("throw");
12314                         break;
12315                 case CEE_ENDFINALLY:
12316                         /* mono_save_seq_point_info () depends on this */
12317                         if (sp != stack_start)
12318                                 emit_seq_point (cfg, method, ip, FALSE, FALSE);
12319                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
12320                         MONO_ADD_INS (cfg->cbb, ins);
12321                         ip++;
12322                         start_new_bblock = 1;
12323
12324                         /*
12325                          * Control will leave the method so empty the stack, otherwise
12326                          * the next basic block will start with a nonempty stack.
12327                          */
12328                         while (sp != stack_start) {
12329                                 sp--;
12330                         }
12331                         break;
12332                 case CEE_LEAVE:
12333                 case CEE_LEAVE_S: {
12334                         GList *handlers;
12335
12336                         if (*ip == CEE_LEAVE) {
12337                                 CHECK_OPSIZE (5);
12338                                 target = ip + 5 + (gint32)read32(ip + 1);
12339                         } else {
12340                                 CHECK_OPSIZE (2);
12341                                 target = ip + 2 + (signed char)(ip [1]);
12342                         }
12343
12344                         /* empty the stack */
12345                         while (sp != stack_start) {
12346                                 sp--;
12347                         }
12348
12349                         /* 
12350                          * If this leave statement is in a catch block, check for a
12351                          * pending exception, and rethrow it if necessary.
12352                          * We avoid doing this in runtime invoke wrappers, since those are called
12353                          * by native code which excepts the wrapper to catch all exceptions.
12354                          */
12355                         for (i = 0; i < header->num_clauses; ++i) {
12356                                 MonoExceptionClause *clause = &header->clauses [i];
12357
12358                                 /* 
12359                                  * Use <= in the final comparison to handle clauses with multiple
12360                                  * leave statements, like in bug #78024.
12361                                  * The ordering of the exception clauses guarantees that we find the
12362                                  * innermost clause.
12363                                  */
12364                                 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) {
12365                                         MonoInst *exc_ins;
12366                                         MonoBasicBlock *dont_throw;
12367
12368                                         /*
12369                                           MonoInst *load;
12370
12371                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
12372                                         */
12373
12374                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
12375
12376                                         NEW_BBLOCK (cfg, dont_throw);
12377
12378                                         /*
12379                                          * Currently, we always rethrow the abort exception, despite the 
12380                                          * fact that this is not correct. See thread6.cs for an example. 
12381                                          * But propagating the abort exception is more important than 
12382                                          * getting the sematics right.
12383                                          */
12384                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
12385                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
12386                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
12387
12388                                         MONO_START_BB (cfg, dont_throw);
12389                                 }
12390                         }
12391
12392 #ifdef ENABLE_LLVM
12393                         cfg->cbb->try_end = (intptr_t)(ip - header->code);
12394 #endif
12395
12396                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
12397                                 GList *tmp;
12398                                 MonoExceptionClause *clause;
12399
12400                                 for (tmp = handlers; tmp; tmp = tmp->next) {
12401                                         clause = (MonoExceptionClause *)tmp->data;
12402                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
12403                                         g_assert (tblock);
12404                                         link_bblock (cfg, cfg->cbb, tblock);
12405                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
12406                                         ins->inst_target_bb = tblock;
12407                                         ins->inst_eh_block = clause;
12408                                         MONO_ADD_INS (cfg->cbb, ins);
12409                                         cfg->cbb->has_call_handler = 1;
12410                                         if (COMPILE_LLVM (cfg)) {
12411                                                 MonoBasicBlock *target_bb;
12412
12413                                                 /* 
12414                                                  * Link the finally bblock with the target, since it will
12415                                                  * conceptually branch there.
12416                                                  */
12417                                                 GET_BBLOCK (cfg, tblock, cfg->cil_start + clause->handler_offset + clause->handler_len - 1);
12418                                                 GET_BBLOCK (cfg, target_bb, target);
12419                                                 link_bblock (cfg, tblock, target_bb);
12420                                         }
12421                                 }
12422                                 g_list_free (handlers);
12423                         } 
12424
12425                         MONO_INST_NEW (cfg, ins, OP_BR);
12426                         MONO_ADD_INS (cfg->cbb, ins);
12427                         GET_BBLOCK (cfg, tblock, target);
12428                         link_bblock (cfg, cfg->cbb, tblock);
12429                         ins->inst_target_bb = tblock;
12430
12431                         start_new_bblock = 1;
12432
12433                         if (*ip == CEE_LEAVE)
12434                                 ip += 5;
12435                         else
12436                                 ip += 2;
12437
12438                         break;
12439                 }
12440
12441                         /*
12442                          * Mono specific opcodes
12443                          */
12444                 case MONO_CUSTOM_PREFIX: {
12445
12446                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
12447
12448                         CHECK_OPSIZE (2);
12449                         switch (ip [1]) {
12450                         case CEE_MONO_ICALL: {
12451                                 gpointer func;
12452                                 MonoJitICallInfo *info;
12453
12454                                 token = read32 (ip + 2);
12455                                 func = mono_method_get_wrapper_data (method, token);
12456                                 info = mono_find_jit_icall_by_addr (func);
12457                                 if (!info)
12458                                         g_error ("Could not find icall address in wrapper %s", mono_method_full_name (method, 1));
12459                                 g_assert (info);
12460
12461                                 CHECK_STACK (info->sig->param_count);
12462                                 sp -= info->sig->param_count;
12463
12464                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
12465                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
12466                                         *sp++ = ins;
12467
12468                                 ip += 6;
12469                                 inline_costs += 10 * num_calls++;
12470
12471                                 break;
12472                         }
12473                         case CEE_MONO_LDPTR_CARD_TABLE:
12474                         case CEE_MONO_LDPTR_NURSERY_START:
12475                         case CEE_MONO_LDPTR_NURSERY_BITS:
12476                         case CEE_MONO_LDPTR_INT_REQ_FLAG: {
12477                                 CHECK_STACK_OVF (1);
12478
12479                                 switch (ip [1]) {
12480                                         case CEE_MONO_LDPTR_CARD_TABLE:
12481                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
12482                                                 break;
12483                                         case CEE_MONO_LDPTR_NURSERY_START:
12484                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_START, NULL);
12485                                                 break;
12486                                         case CEE_MONO_LDPTR_NURSERY_BITS:
12487                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_BITS, NULL);
12488                                                 break;
12489                                         case CEE_MONO_LDPTR_INT_REQ_FLAG:
12490                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
12491                                                 break;
12492                                 }
12493
12494                                 *sp++ = ins;
12495                                 ip += 2;
12496                                 inline_costs += 10 * num_calls++;
12497                                 break;
12498                         }
12499                         case CEE_MONO_LDPTR: {
12500                                 gpointer ptr;
12501
12502                                 CHECK_STACK_OVF (1);
12503                                 CHECK_OPSIZE (6);
12504                                 token = read32 (ip + 2);
12505
12506                                 ptr = mono_method_get_wrapper_data (method, token);
12507                                 EMIT_NEW_PCONST (cfg, ins, ptr);
12508                                 *sp++ = ins;
12509                                 ip += 6;
12510                                 inline_costs += 10 * num_calls++;
12511                                 /* Can't embed random pointers into AOT code */
12512                                 DISABLE_AOT (cfg);
12513                                 break;
12514                         }
12515                         case CEE_MONO_JIT_ICALL_ADDR: {
12516                                 MonoJitICallInfo *callinfo;
12517                                 gpointer ptr;
12518
12519                                 CHECK_STACK_OVF (1);
12520                                 CHECK_OPSIZE (6);
12521                                 token = read32 (ip + 2);
12522
12523                                 ptr = mono_method_get_wrapper_data (method, token);
12524                                 callinfo = mono_find_jit_icall_by_addr (ptr);
12525                                 g_assert (callinfo);
12526                                 EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
12527                                 *sp++ = ins;
12528                                 ip += 6;
12529                                 inline_costs += 10 * num_calls++;
12530                                 break;
12531                         }
12532                         case CEE_MONO_ICALL_ADDR: {
12533                                 MonoMethod *cmethod;
12534                                 gpointer ptr;
12535
12536                                 CHECK_STACK_OVF (1);
12537                                 CHECK_OPSIZE (6);
12538                                 token = read32 (ip + 2);
12539
12540                                 cmethod = (MonoMethod *)mono_method_get_wrapper_data (method, token);
12541
12542                                 if (cfg->compile_aot) {
12543                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
12544                                 } else {
12545                                         ptr = mono_lookup_internal_call (cmethod);
12546                                         g_assert (ptr);
12547                                         EMIT_NEW_PCONST (cfg, ins, ptr);
12548                                 }
12549                                 *sp++ = ins;
12550                                 ip += 6;
12551                                 break;
12552                         }
12553                         case CEE_MONO_VTADDR: {
12554                                 MonoInst *src_var, *src;
12555
12556                                 CHECK_STACK (1);
12557                                 --sp;
12558
12559                                 // FIXME:
12560                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12561                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
12562                                 *sp++ = src;
12563                                 ip += 2;
12564                                 break;
12565                         }
12566                         case CEE_MONO_NEWOBJ: {
12567                                 MonoInst *iargs [2];
12568
12569                                 CHECK_STACK_OVF (1);
12570                                 CHECK_OPSIZE (6);
12571                                 token = read32 (ip + 2);
12572                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12573                                 mono_class_init (klass);
12574                                 NEW_DOMAINCONST (cfg, iargs [0]);
12575                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
12576                                 NEW_CLASSCONST (cfg, iargs [1], klass);
12577                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
12578                                 *sp++ = mono_emit_jit_icall (cfg, mono_object_new, iargs);
12579                                 ip += 6;
12580                                 inline_costs += 10 * num_calls++;
12581                                 break;
12582                         }
12583                         case CEE_MONO_OBJADDR:
12584                                 CHECK_STACK (1);
12585                                 --sp;
12586                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
12587                                 ins->dreg = alloc_ireg_mp (cfg);
12588                                 ins->sreg1 = sp [0]->dreg;
12589                                 ins->type = STACK_MP;
12590                                 MONO_ADD_INS (cfg->cbb, ins);
12591                                 *sp++ = ins;
12592                                 ip += 2;
12593                                 break;
12594                         case CEE_MONO_LDNATIVEOBJ:
12595                                 /*
12596                                  * Similar to LDOBJ, but instead load the unmanaged 
12597                                  * representation of the vtype to the stack.
12598                                  */
12599                                 CHECK_STACK (1);
12600                                 CHECK_OPSIZE (6);
12601                                 --sp;
12602                                 token = read32 (ip + 2);
12603                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12604                                 g_assert (klass->valuetype);
12605                                 mono_class_init (klass);
12606
12607                                 {
12608                                         MonoInst *src, *dest, *temp;
12609
12610                                         src = sp [0];
12611                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
12612                                         temp->backend.is_pinvoke = 1;
12613                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
12614                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
12615
12616                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
12617                                         dest->type = STACK_VTYPE;
12618                                         dest->klass = klass;
12619
12620                                         *sp ++ = dest;
12621                                         ip += 6;
12622                                 }
12623                                 break;
12624                         case CEE_MONO_RETOBJ: {
12625                                 /*
12626                                  * Same as RET, but return the native representation of a vtype
12627                                  * to the caller.
12628                                  */
12629                                 g_assert (cfg->ret);
12630                                 g_assert (mono_method_signature (method)->pinvoke); 
12631                                 CHECK_STACK (1);
12632                                 --sp;
12633                                 
12634                                 CHECK_OPSIZE (6);
12635                                 token = read32 (ip + 2);    
12636                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12637
12638                                 if (!cfg->vret_addr) {
12639                                         g_assert (cfg->ret_var_is_local);
12640
12641                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
12642                                 } else {
12643                                         EMIT_NEW_RETLOADA (cfg, ins);
12644                                 }
12645                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
12646                                 
12647                                 if (sp != stack_start)
12648                                         UNVERIFIED;
12649                                 
12650                                 MONO_INST_NEW (cfg, ins, OP_BR);
12651                                 ins->inst_target_bb = end_bblock;
12652                                 MONO_ADD_INS (cfg->cbb, ins);
12653                                 link_bblock (cfg, cfg->cbb, end_bblock);
12654                                 start_new_bblock = 1;
12655                                 ip += 6;
12656                                 break;
12657                         }
12658                         case CEE_MONO_CISINST:
12659                         case CEE_MONO_CCASTCLASS: {
12660                                 int token;
12661                                 CHECK_STACK (1);
12662                                 --sp;
12663                                 CHECK_OPSIZE (6);
12664                                 token = read32 (ip + 2);
12665                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12666                                 if (ip [1] == CEE_MONO_CISINST)
12667                                         ins = handle_cisinst (cfg, klass, sp [0]);
12668                                 else
12669                                         ins = handle_ccastclass (cfg, klass, sp [0]);
12670                                 *sp++ = ins;
12671                                 ip += 6;
12672                                 break;
12673                         }
12674                         case CEE_MONO_SAVE_LMF:
12675                         case CEE_MONO_RESTORE_LMF:
12676                                 ip += 2;
12677                                 break;
12678                         case CEE_MONO_CLASSCONST:
12679                                 CHECK_STACK_OVF (1);
12680                                 CHECK_OPSIZE (6);
12681                                 token = read32 (ip + 2);
12682                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
12683                                 *sp++ = ins;
12684                                 ip += 6;
12685                                 inline_costs += 10 * num_calls++;
12686                                 break;
12687                         case CEE_MONO_NOT_TAKEN:
12688                                 cfg->cbb->out_of_line = TRUE;
12689                                 ip += 2;
12690                                 break;
12691                         case CEE_MONO_TLS: {
12692                                 MonoTlsKey key;
12693
12694                                 CHECK_STACK_OVF (1);
12695                                 CHECK_OPSIZE (6);
12696                                 key = (MonoTlsKey)read32 (ip + 2);
12697                                 g_assert (key < TLS_KEY_NUM);
12698
12699                                 ins = mono_create_tls_get (cfg, key);
12700                                 if (!ins) {
12701                                         if (cfg->compile_aot) {
12702                                                 DISABLE_AOT (cfg);
12703                                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
12704                                                 ins->dreg = alloc_preg (cfg);
12705                                                 ins->type = STACK_PTR;
12706                                         } else {
12707                                                 g_assert_not_reached ();
12708                                         }
12709                                 }
12710                                 ins->type = STACK_PTR;
12711                                 MONO_ADD_INS (cfg->cbb, ins);
12712                                 *sp++ = ins;
12713                                 ip += 6;
12714                                 break;
12715                         }
12716                         case CEE_MONO_DYN_CALL: {
12717                                 MonoCallInst *call;
12718
12719                                 /* It would be easier to call a trampoline, but that would put an
12720                                  * extra frame on the stack, confusing exception handling. So
12721                                  * implement it inline using an opcode for now.
12722                                  */
12723
12724                                 if (!cfg->dyn_call_var) {
12725                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12726                                         /* prevent it from being register allocated */
12727                                         cfg->dyn_call_var->flags |= MONO_INST_VOLATILE;
12728                                 }
12729
12730                                 /* Has to use a call inst since it local regalloc expects it */
12731                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
12732                                 ins = (MonoInst*)call;
12733                                 sp -= 2;
12734                                 ins->sreg1 = sp [0]->dreg;
12735                                 ins->sreg2 = sp [1]->dreg;
12736                                 MONO_ADD_INS (cfg->cbb, ins);
12737
12738                                 cfg->param_area = MAX (cfg->param_area, cfg->backend->dyn_call_param_area);
12739
12740                                 ip += 2;
12741                                 inline_costs += 10 * num_calls++;
12742
12743                                 break;
12744                         }
12745                         case CEE_MONO_MEMORY_BARRIER: {
12746                                 CHECK_OPSIZE (6);
12747                                 emit_memory_barrier (cfg, (int)read32 (ip + 2));
12748                                 ip += 6;
12749                                 break;
12750                         }
12751                         case CEE_MONO_JIT_ATTACH: {
12752                                 MonoInst *args [16], *domain_ins;
12753                                 MonoInst *ad_ins, *jit_tls_ins;
12754                                 MonoBasicBlock *next_bb = NULL, *call_bb = NULL;
12755
12756                                 cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12757
12758                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12759                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12760
12761                                 ad_ins = mono_get_domain_intrinsic (cfg);
12762                                 jit_tls_ins = mono_get_jit_tls_intrinsic (cfg);
12763
12764                                 if (cfg->backend->have_tls_get && ad_ins && jit_tls_ins) {
12765                                         NEW_BBLOCK (cfg, next_bb);
12766                                         NEW_BBLOCK (cfg, call_bb);
12767
12768                                         if (cfg->compile_aot) {
12769                                                 /* AOT code is only used in the root domain */
12770                                                 EMIT_NEW_PCONST (cfg, domain_ins, NULL);
12771                                         } else {
12772                                                 EMIT_NEW_PCONST (cfg, domain_ins, cfg->domain);
12773                                         }
12774                                         MONO_ADD_INS (cfg->cbb, ad_ins);
12775                                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, ad_ins->dreg, domain_ins->dreg);
12776                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, call_bb);
12777
12778                                         MONO_ADD_INS (cfg->cbb, jit_tls_ins);
12779                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, jit_tls_ins->dreg, 0);
12780                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, call_bb);
12781
12782                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, next_bb);
12783                                         MONO_START_BB (cfg, call_bb);
12784                                 }
12785
12786                                 if (cfg->compile_aot) {
12787                                         /* AOT code is only used in the root domain */
12788                                         EMIT_NEW_PCONST (cfg, args [0], NULL);
12789                                 } else {
12790                                         EMIT_NEW_PCONST (cfg, args [0], cfg->domain);
12791                                 }
12792                                 ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
12793                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12794
12795                                 if (next_bb)
12796                                         MONO_START_BB (cfg, next_bb);
12797                                 ip += 2;
12798                                 break;
12799                         }
12800                         case CEE_MONO_JIT_DETACH: {
12801                                 MonoInst *args [16];
12802
12803                                 /* Restore the original domain */
12804                                 dreg = alloc_ireg (cfg);
12805                                 EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->orig_domain_var->dreg);
12806                                 mono_emit_jit_icall (cfg, mono_jit_set_domain, args);
12807                                 ip += 2;
12808                                 break;
12809                         }
12810                         case CEE_MONO_CALLI_EXTRA_ARG: {
12811                                 MonoInst *addr;
12812                                 MonoMethodSignature *fsig;
12813                                 MonoInst *arg;
12814
12815                                 /*
12816                                  * This is the same as CEE_CALLI, but passes an additional argument
12817                                  * to the called method in llvmonly mode.
12818                                  * This is only used by delegate invoke wrappers to call the
12819                                  * actual delegate method.
12820                                  */
12821                                 g_assert (method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE);
12822
12823                                 CHECK_OPSIZE (6);
12824                                 token = read32 (ip + 2);
12825
12826                                 ins = NULL;
12827
12828                                 cmethod = NULL;
12829                                 CHECK_STACK (1);
12830                                 --sp;
12831                                 addr = *sp;
12832                                 fsig = mini_get_signature (method, token, generic_context);
12833
12834                                 if (cfg->llvm_only)
12835                                         cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, fsig);
12836
12837                                 n = fsig->param_count + fsig->hasthis + 1;
12838
12839                                 CHECK_STACK (n);
12840
12841                                 sp -= n;
12842                                 arg = sp [n - 1];
12843
12844                                 if (cfg->llvm_only) {
12845                                         /*
12846                                          * The lowest bit of 'arg' determines whenever the callee uses the gsharedvt
12847                                          * cconv. This is set by mono_init_delegate ().
12848                                          */
12849                                         if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig)) {
12850                                                 MonoInst *callee = addr;
12851                                                 MonoInst *call, *localloc_ins;
12852                                                 MonoBasicBlock *is_gsharedvt_bb, *end_bb;
12853                                                 int low_bit_reg = alloc_preg (cfg);
12854
12855                                                 NEW_BBLOCK (cfg, is_gsharedvt_bb);
12856                                                 NEW_BBLOCK (cfg, end_bb);
12857
12858                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, low_bit_reg, arg->dreg, 1);
12859                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_bit_reg, 0);
12860                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_gsharedvt_bb);
12861
12862                                                 /* Normal case: callee uses a normal cconv, have to add an out wrapper */
12863                                                 addr = emit_get_rgctx_sig (cfg, context_used,
12864                                                                                                    fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
12865                                                 /*
12866                                                  * ADDR points to a gsharedvt-out wrapper, have to pass <callee, arg> as an extra arg.
12867                                                  */
12868                                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
12869                                                 ins->dreg = alloc_preg (cfg);
12870                                                 ins->inst_imm = 2 * SIZEOF_VOID_P;
12871                                                 MONO_ADD_INS (cfg->cbb, ins);
12872                                                 localloc_ins = ins;
12873                                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12874                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, 0, callee->dreg);
12875                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, SIZEOF_VOID_P, arg->dreg);
12876
12877                                                 call = emit_extra_arg_calli (cfg, fsig, sp, localloc_ins->dreg, addr);
12878                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12879
12880                                                 /* Gsharedvt case: callee uses a gsharedvt cconv, no conversion is needed */
12881                                                 MONO_START_BB (cfg, is_gsharedvt_bb);
12882                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PXOR_IMM, arg->dreg, arg->dreg, 1);
12883                                                 ins = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
12884                                                 ins->dreg = call->dreg;
12885
12886                                                 MONO_START_BB (cfg, end_bb);
12887                                         } else {
12888                                                 /* Caller uses a normal calling conv */
12889
12890                                                 MonoInst *callee = addr;
12891                                                 MonoInst *call, *localloc_ins;
12892                                                 MonoBasicBlock *is_gsharedvt_bb, *end_bb;
12893                                                 int low_bit_reg = alloc_preg (cfg);
12894
12895                                                 NEW_BBLOCK (cfg, is_gsharedvt_bb);
12896                                                 NEW_BBLOCK (cfg, end_bb);
12897
12898                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, low_bit_reg, arg->dreg, 1);
12899                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_bit_reg, 0);
12900                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_gsharedvt_bb);
12901
12902                                                 /* Normal case: callee uses a normal cconv, no conversion is needed */
12903                                                 call = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
12904                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12905                                                 /* Gsharedvt case: callee uses a gsharedvt cconv, have to add an in wrapper */
12906                                                 MONO_START_BB (cfg, is_gsharedvt_bb);
12907                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PXOR_IMM, arg->dreg, arg->dreg, 1);
12908                                                 NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER, fsig);
12909                                                 MONO_ADD_INS (cfg->cbb, addr);
12910                                                 /*
12911                                                  * ADDR points to a gsharedvt-in wrapper, have to pass <callee, arg> as an extra arg.
12912                                                  */
12913                                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
12914                                                 ins->dreg = alloc_preg (cfg);
12915                                                 ins->inst_imm = 2 * SIZEOF_VOID_P;
12916                                                 MONO_ADD_INS (cfg->cbb, ins);
12917                                                 localloc_ins = ins;
12918                                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12919                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, 0, callee->dreg);
12920                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, SIZEOF_VOID_P, arg->dreg);
12921
12922                                                 ins = emit_extra_arg_calli (cfg, fsig, sp, localloc_ins->dreg, addr);
12923                                                 ins->dreg = call->dreg;
12924                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12925
12926                                                 MONO_START_BB (cfg, end_bb);
12927                                         }
12928                                 } else {
12929                                         /* Same as CEE_CALLI */
12930                                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
12931                                                 /*
12932                                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
12933                                                  */
12934                                                 MonoInst *callee = addr;
12935
12936                                                 addr = emit_get_rgctx_sig (cfg, context_used,
12937                                                                                                    fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
12938                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
12939                                         } else {
12940                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
12941                                         }
12942                                 }
12943
12944                                 if (!MONO_TYPE_IS_VOID (fsig->ret))
12945                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
12946
12947                                 CHECK_CFG_EXCEPTION;
12948
12949                                 ip += 6;
12950                                 ins_flag = 0;
12951                                 constrained_class = NULL;
12952                                 break;
12953                         }
12954                         default:
12955                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
12956                                 break;
12957                         }
12958                         break;
12959                 }
12960
12961                 case CEE_PREFIX1: {
12962                         CHECK_OPSIZE (2);
12963                         switch (ip [1]) {
12964                         case CEE_ARGLIST: {
12965                                 /* somewhat similar to LDTOKEN */
12966                                 MonoInst *addr, *vtvar;
12967                                 CHECK_STACK_OVF (1);
12968                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
12969
12970                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12971                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
12972
12973                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12974                                 ins->type = STACK_VTYPE;
12975                                 ins->klass = mono_defaults.argumenthandle_class;
12976                                 *sp++ = ins;
12977                                 ip += 2;
12978                                 break;
12979                         }
12980                         case CEE_CEQ:
12981                         case CEE_CGT:
12982                         case CEE_CGT_UN:
12983                         case CEE_CLT:
12984                         case CEE_CLT_UN: {
12985                                 MonoInst *cmp, *arg1, *arg2;
12986
12987                                 CHECK_STACK (2);
12988                                 sp -= 2;
12989                                 arg1 = sp [0];
12990                                 arg2 = sp [1];
12991
12992                                 /*
12993                                  * The following transforms:
12994                                  *    CEE_CEQ    into OP_CEQ
12995                                  *    CEE_CGT    into OP_CGT
12996                                  *    CEE_CGT_UN into OP_CGT_UN
12997                                  *    CEE_CLT    into OP_CLT
12998                                  *    CEE_CLT_UN into OP_CLT_UN
12999                                  */
13000                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
13001
13002                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
13003                                 cmp->sreg1 = arg1->dreg;
13004                                 cmp->sreg2 = arg2->dreg;
13005                                 type_from_op (cfg, cmp, arg1, arg2);
13006                                 CHECK_TYPE (cmp);
13007                                 add_widen_op (cfg, cmp, &arg1, &arg2);
13008                                 if ((arg1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((arg1->type == STACK_PTR) || (arg1->type == STACK_OBJ) || (arg1->type == STACK_MP))))
13009                                         cmp->opcode = OP_LCOMPARE;
13010                                 else if (arg1->type == STACK_R4)
13011                                         cmp->opcode = OP_RCOMPARE;
13012                                 else if (arg1->type == STACK_R8)
13013                                         cmp->opcode = OP_FCOMPARE;
13014                                 else
13015                                         cmp->opcode = OP_ICOMPARE;
13016                                 MONO_ADD_INS (cfg->cbb, cmp);
13017                                 ins->type = STACK_I4;
13018                                 ins->dreg = alloc_dreg (cfg, (MonoStackType)ins->type);
13019                                 type_from_op (cfg, ins, arg1, arg2);
13020
13021                                 if (cmp->opcode == OP_FCOMPARE || cmp->opcode == OP_RCOMPARE) {
13022                                         /*
13023                                          * The backends expect the fceq opcodes to do the
13024                                          * comparison too.
13025                                          */
13026                                         ins->sreg1 = cmp->sreg1;
13027                                         ins->sreg2 = cmp->sreg2;
13028                                         NULLIFY_INS (cmp);
13029                                 }
13030                                 MONO_ADD_INS (cfg->cbb, ins);
13031                                 *sp++ = ins;
13032                                 ip += 2;
13033                                 break;
13034                         }
13035                         case CEE_LDFTN: {
13036                                 MonoInst *argconst;
13037                                 MonoMethod *cil_method;
13038
13039                                 CHECK_STACK_OVF (1);
13040                                 CHECK_OPSIZE (6);
13041                                 n = read32 (ip + 2);
13042                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
13043                                 if (!cmethod || mono_loader_get_last_error ())
13044                                         LOAD_ERROR;
13045                                 mono_class_init (cmethod->klass);
13046
13047                                 mono_save_token_info (cfg, image, n, cmethod);
13048
13049                                 context_used = mini_method_check_context_used (cfg, cmethod);
13050
13051                                 cil_method = cmethod;
13052                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
13053                                         METHOD_ACCESS_FAILURE (method, cil_method);
13054
13055                                 if (mono_security_core_clr_enabled ())
13056                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
13057
13058                                 /* 
13059                                  * Optimize the common case of ldftn+delegate creation
13060                                  */
13061                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
13062                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
13063                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
13064                                                 MonoInst *target_ins, *handle_ins;
13065                                                 MonoMethod *invoke;
13066                                                 int invoke_context_used;
13067
13068                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
13069                                                 if (!invoke || !mono_method_signature (invoke))
13070                                                         LOAD_ERROR;
13071
13072                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
13073
13074                                                 target_ins = sp [-1];
13075
13076                                                 if (mono_security_core_clr_enabled ())
13077                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
13078
13079                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
13080                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
13081                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
13082                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
13083                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
13084                                                         }
13085                                                 }
13086
13087                                                 /* FIXME: SGEN support */
13088                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
13089                                                         ip += 6;
13090                                                         if (cfg->verbose_level > 3)
13091                                                                 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));
13092                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, FALSE))) {
13093                                                                 sp --;
13094                                                                 *sp = handle_ins;
13095                                                                 CHECK_CFG_EXCEPTION;
13096                                                                 ip += 5;
13097                                                                 sp ++;
13098                                                                 break;
13099                                                         }
13100                                                         ip -= 6;
13101                                                 }
13102                                         }
13103                                 }
13104
13105                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
13106                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
13107                                 *sp++ = ins;
13108                                 
13109                                 ip += 6;
13110                                 inline_costs += 10 * num_calls++;
13111                                 break;
13112                         }
13113                         case CEE_LDVIRTFTN: {
13114                                 MonoInst *args [2];
13115
13116                                 CHECK_STACK (1);
13117                                 CHECK_OPSIZE (6);
13118                                 n = read32 (ip + 2);
13119                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
13120                                 if (!cmethod || mono_loader_get_last_error ())
13121                                         LOAD_ERROR;
13122                                 mono_class_init (cmethod->klass);
13123  
13124                                 context_used = mini_method_check_context_used (cfg, cmethod);
13125
13126                                 if (mono_security_core_clr_enabled ())
13127                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
13128
13129                                 /*
13130                                  * Optimize the common case of ldvirtftn+delegate creation
13131                                  */
13132                                 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)) {
13133                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
13134                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
13135                                                 MonoInst *target_ins, *handle_ins;
13136                                                 MonoMethod *invoke;
13137                                                 int invoke_context_used;
13138                                                 gboolean is_virtual = cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL;
13139
13140                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
13141                                                 if (!invoke || !mono_method_signature (invoke))
13142                                                         LOAD_ERROR;
13143
13144                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
13145
13146                                                 target_ins = sp [-1];
13147
13148                                                 if (mono_security_core_clr_enabled ())
13149                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
13150
13151                                                 /* FIXME: SGEN support */
13152                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
13153                                                         ip += 6;
13154                                                         if (cfg->verbose_level > 3)
13155                                                                 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));
13156                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, is_virtual))) {
13157                                                                 sp -= 2;
13158                                                                 *sp = handle_ins;
13159                                                                 CHECK_CFG_EXCEPTION;
13160                                                                 ip += 5;
13161                                                                 sp ++;
13162                                                                 break;
13163                                                         }
13164                                                         ip -= 6;
13165                                                 }
13166                                         }
13167                                 }
13168
13169                                 --sp;
13170                                 args [0] = *sp;
13171
13172                                 args [1] = emit_get_rgctx_method (cfg, context_used,
13173                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
13174
13175                                 if (context_used)
13176                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
13177                                 else
13178                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
13179
13180                                 ip += 6;
13181                                 inline_costs += 10 * num_calls++;
13182                                 break;
13183                         }
13184                         case CEE_LDARG:
13185                                 CHECK_STACK_OVF (1);
13186                                 CHECK_OPSIZE (4);
13187                                 n = read16 (ip + 2);
13188                                 CHECK_ARG (n);
13189                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
13190                                 *sp++ = ins;
13191                                 ip += 4;
13192                                 break;
13193                         case CEE_LDARGA:
13194                                 CHECK_STACK_OVF (1);
13195                                 CHECK_OPSIZE (4);
13196                                 n = read16 (ip + 2);
13197                                 CHECK_ARG (n);
13198                                 NEW_ARGLOADA (cfg, ins, n);
13199                                 MONO_ADD_INS (cfg->cbb, ins);
13200                                 *sp++ = ins;
13201                                 ip += 4;
13202                                 break;
13203                         case CEE_STARG:
13204                                 CHECK_STACK (1);
13205                                 --sp;
13206                                 CHECK_OPSIZE (4);
13207                                 n = read16 (ip + 2);
13208                                 CHECK_ARG (n);
13209                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
13210                                         UNVERIFIED;
13211                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
13212                                 ip += 4;
13213                                 break;
13214                         case CEE_LDLOC:
13215                                 CHECK_STACK_OVF (1);
13216                                 CHECK_OPSIZE (4);
13217                                 n = read16 (ip + 2);
13218                                 CHECK_LOCAL (n);
13219                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
13220                                 *sp++ = ins;
13221                                 ip += 4;
13222                                 break;
13223                         case CEE_LDLOCA: {
13224                                 unsigned char *tmp_ip;
13225                                 CHECK_STACK_OVF (1);
13226                                 CHECK_OPSIZE (4);
13227                                 n = read16 (ip + 2);
13228                                 CHECK_LOCAL (n);
13229
13230                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
13231                                         ip = tmp_ip;
13232                                         inline_costs += 1;
13233                                         break;
13234                                 }                       
13235                                 
13236                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
13237                                 *sp++ = ins;
13238                                 ip += 4;
13239                                 break;
13240                         }
13241                         case CEE_STLOC:
13242                                 CHECK_STACK (1);
13243                                 --sp;
13244                                 CHECK_OPSIZE (4);
13245                                 n = read16 (ip + 2);
13246                                 CHECK_LOCAL (n);
13247                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
13248                                         UNVERIFIED;
13249                                 emit_stloc_ir (cfg, sp, header, n);
13250                                 ip += 4;
13251                                 inline_costs += 1;
13252                                 break;
13253                         case CEE_LOCALLOC:
13254                                 CHECK_STACK (1);
13255                                 --sp;
13256                                 if (sp != stack_start) 
13257                                         UNVERIFIED;
13258                                 if (cfg->method != method) 
13259                                         /* 
13260                                          * Inlining this into a loop in a parent could lead to 
13261                                          * stack overflows which is different behavior than the
13262                                          * non-inlined case, thus disable inlining in this case.
13263                                          */
13264                                         INLINE_FAILURE("localloc");
13265
13266                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
13267                                 ins->dreg = alloc_preg (cfg);
13268                                 ins->sreg1 = sp [0]->dreg;
13269                                 ins->type = STACK_PTR;
13270                                 MONO_ADD_INS (cfg->cbb, ins);
13271
13272                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
13273                                 if (init_locals)
13274                                         ins->flags |= MONO_INST_INIT;
13275
13276                                 *sp++ = ins;
13277                                 ip += 2;
13278                                 break;
13279                         case CEE_ENDFILTER: {
13280                                 MonoExceptionClause *clause, *nearest;
13281                                 int cc;
13282
13283                                 CHECK_STACK (1);
13284                                 --sp;
13285                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
13286                                         UNVERIFIED;
13287                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
13288                                 ins->sreg1 = (*sp)->dreg;
13289                                 MONO_ADD_INS (cfg->cbb, ins);
13290                                 start_new_bblock = 1;
13291                                 ip += 2;
13292
13293                                 nearest = NULL;
13294                                 for (cc = 0; cc < header->num_clauses; ++cc) {
13295                                         clause = &header->clauses [cc];
13296                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
13297                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
13298                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset)))
13299                                                 nearest = clause;
13300                                 }
13301                                 g_assert (nearest);
13302                                 if ((ip - header->code) != nearest->handler_offset)
13303                                         UNVERIFIED;
13304
13305                                 break;
13306                         }
13307                         case CEE_UNALIGNED_:
13308                                 ins_flag |= MONO_INST_UNALIGNED;
13309                                 /* FIXME: record alignment? we can assume 1 for now */
13310                                 CHECK_OPSIZE (3);
13311                                 ip += 3;
13312                                 break;
13313                         case CEE_VOLATILE_:
13314                                 ins_flag |= MONO_INST_VOLATILE;
13315                                 ip += 2;
13316                                 break;
13317                         case CEE_TAIL_:
13318                                 ins_flag   |= MONO_INST_TAILCALL;
13319                                 cfg->flags |= MONO_CFG_HAS_TAIL;
13320                                 /* Can't inline tail calls at this time */
13321                                 inline_costs += 100000;
13322                                 ip += 2;
13323                                 break;
13324                         case CEE_INITOBJ:
13325                                 CHECK_STACK (1);
13326                                 --sp;
13327                                 CHECK_OPSIZE (6);
13328                                 token = read32 (ip + 2);
13329                                 klass = mini_get_class (method, token, generic_context);
13330                                 CHECK_TYPELOAD (klass);
13331                                 if (generic_class_is_reference_type (cfg, klass))
13332                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
13333                                 else
13334                                         mini_emit_initobj (cfg, *sp, NULL, klass);
13335                                 ip += 6;
13336                                 inline_costs += 1;
13337                                 break;
13338                         case CEE_CONSTRAINED_:
13339                                 CHECK_OPSIZE (6);
13340                                 token = read32 (ip + 2);
13341                                 constrained_class = mini_get_class (method, token, generic_context);
13342                                 CHECK_TYPELOAD (constrained_class);
13343                                 ip += 6;
13344                                 break;
13345                         case CEE_CPBLK:
13346                         case CEE_INITBLK: {
13347                                 MonoInst *iargs [3];
13348                                 CHECK_STACK (3);
13349                                 sp -= 3;
13350
13351                                 /* Skip optimized paths for volatile operations. */
13352                                 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)) {
13353                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
13354                                 } 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)) {
13355                                         /* emit_memset only works when val == 0 */
13356                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
13357                                 } else {
13358                                         MonoInst *call;
13359                                         iargs [0] = sp [0];
13360                                         iargs [1] = sp [1];
13361                                         iargs [2] = sp [2];
13362                                         if (ip [1] == CEE_CPBLK) {
13363                                                 /*
13364                                                  * FIXME: It's unclear whether we should be emitting both the acquire
13365                                                  * and release barriers for cpblk. It is technically both a load and
13366                                                  * store operation, so it seems like that's the sensible thing to do.
13367                                                  *
13368                                                  * FIXME: We emit full barriers on both sides of the operation for
13369                                                  * simplicity. We should have a separate atomic memcpy method instead.
13370                                                  */
13371                                                 MonoMethod *memcpy_method = get_memcpy_method ();
13372
13373                                                 if (ins_flag & MONO_INST_VOLATILE)
13374                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
13375
13376                                                 call = mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
13377                                                 call->flags |= ins_flag;
13378
13379                                                 if (ins_flag & MONO_INST_VOLATILE)
13380                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
13381                                         } else {
13382                                                 MonoMethod *memset_method = get_memset_method ();
13383                                                 if (ins_flag & MONO_INST_VOLATILE) {
13384                                                         /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
13385                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
13386                                                 }
13387                                                 call = mono_emit_method_call (cfg, memset_method, iargs, NULL);
13388                                                 call->flags |= ins_flag;
13389                                         }
13390                                 }
13391                                 ip += 2;
13392                                 ins_flag = 0;
13393                                 inline_costs += 1;
13394                                 break;
13395                         }
13396                         case CEE_NO_:
13397                                 CHECK_OPSIZE (3);
13398                                 if (ip [2] & 0x1)
13399                                         ins_flag |= MONO_INST_NOTYPECHECK;
13400                                 if (ip [2] & 0x2)
13401                                         ins_flag |= MONO_INST_NORANGECHECK;
13402                                 /* we ignore the no-nullcheck for now since we
13403                                  * really do it explicitly only when doing callvirt->call
13404                                  */
13405                                 ip += 3;
13406                                 break;
13407                         case CEE_RETHROW: {
13408                                 MonoInst *load;
13409                                 int handler_offset = -1;
13410
13411                                 for (i = 0; i < header->num_clauses; ++i) {
13412                                         MonoExceptionClause *clause = &header->clauses [i];
13413                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
13414                                                 handler_offset = clause->handler_offset;
13415                                                 break;
13416                                         }
13417                                 }
13418
13419                                 cfg->cbb->flags |= BB_EXCEPTION_UNSAFE;
13420
13421                                 if (handler_offset == -1)
13422                                         UNVERIFIED;
13423
13424                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
13425                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
13426                                 ins->sreg1 = load->dreg;
13427                                 MONO_ADD_INS (cfg->cbb, ins);
13428
13429                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
13430                                 MONO_ADD_INS (cfg->cbb, ins);
13431
13432                                 sp = stack_start;
13433                                 link_bblock (cfg, cfg->cbb, end_bblock);
13434                                 start_new_bblock = 1;
13435                                 ip += 2;
13436                                 break;
13437                         }
13438                         case CEE_SIZEOF: {
13439                                 guint32 val;
13440                                 int ialign;
13441
13442                                 CHECK_STACK_OVF (1);
13443                                 CHECK_OPSIZE (6);
13444                                 token = read32 (ip + 2);
13445                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !image_is_dynamic (method->klass->image) && !generic_context) {
13446                                         MonoType *type = mono_type_create_from_typespec_checked (image, token, &cfg->error);
13447                                         CHECK_CFG_ERROR;
13448
13449                                         val = mono_type_size (type, &ialign);
13450                                 } else {
13451                                         MonoClass *klass = mini_get_class (method, token, generic_context);
13452                                         CHECK_TYPELOAD (klass);
13453
13454                                         val = mono_type_size (&klass->byval_arg, &ialign);
13455
13456                                         if (mini_is_gsharedvt_klass (klass))
13457                                                 GSHAREDVT_FAILURE (*ip);
13458                                 }
13459                                 EMIT_NEW_ICONST (cfg, ins, val);
13460                                 *sp++= ins;
13461                                 ip += 6;
13462                                 break;
13463                         }
13464                         case CEE_REFANYTYPE: {
13465                                 MonoInst *src_var, *src;
13466
13467                                 GSHAREDVT_FAILURE (*ip);
13468
13469                                 CHECK_STACK (1);
13470                                 --sp;
13471
13472                                 // FIXME:
13473                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
13474                                 if (!src_var)
13475                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
13476                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
13477                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type));
13478                                 *sp++ = ins;
13479                                 ip += 2;
13480                                 break;
13481                         }
13482                         case CEE_READONLY_:
13483                                 readonly = TRUE;
13484                                 ip += 2;
13485                                 break;
13486
13487                         case CEE_UNUSED56:
13488                         case CEE_UNUSED57:
13489                         case CEE_UNUSED70:
13490                         case CEE_UNUSED:
13491                         case CEE_UNUSED99:
13492                                 UNVERIFIED;
13493                                 
13494                         default:
13495                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
13496                                 UNVERIFIED;
13497                         }
13498                         break;
13499                 }
13500                 case CEE_UNUSED58:
13501                 case CEE_UNUSED1:
13502                         UNVERIFIED;
13503
13504                 default:
13505                         g_warning ("opcode 0x%02x not handled", *ip);
13506                         UNVERIFIED;
13507                 }
13508         }
13509         if (start_new_bblock != 1)
13510                 UNVERIFIED;
13511
13512         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
13513         if (cfg->cbb->next_bb) {
13514                 /* This could already be set because of inlining, #693905 */
13515                 MonoBasicBlock *bb = cfg->cbb;
13516
13517                 while (bb->next_bb)
13518                         bb = bb->next_bb;
13519                 bb->next_bb = end_bblock;
13520         } else {
13521                 cfg->cbb->next_bb = end_bblock;
13522         }
13523
13524         if (cfg->method == method && cfg->domainvar) {
13525                 MonoInst *store;
13526                 MonoInst *get_domain;
13527
13528                 cfg->cbb = init_localsbb;
13529
13530                 if ((get_domain = mono_get_domain_intrinsic (cfg))) {
13531                         MONO_ADD_INS (cfg->cbb, get_domain);
13532                 } else {
13533                         get_domain = mono_emit_jit_icall (cfg, mono_domain_get, NULL);
13534                 }
13535                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
13536                 MONO_ADD_INS (cfg->cbb, store);
13537         }
13538
13539 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
13540         if (cfg->compile_aot)
13541                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
13542                 mono_get_got_var (cfg);
13543 #endif
13544
13545         if (cfg->method == method && cfg->got_var)
13546                 mono_emit_load_got_addr (cfg);
13547
13548         if (init_localsbb) {
13549                 cfg->cbb = init_localsbb;
13550                 cfg->ip = NULL;
13551                 for (i = 0; i < header->num_locals; ++i) {
13552                         emit_init_local (cfg, i, header->locals [i], init_locals);
13553                 }
13554         }
13555
13556         if (cfg->init_ref_vars && cfg->method == method) {
13557                 /* Emit initialization for ref vars */
13558                 // FIXME: Avoid duplication initialization for IL locals.
13559                 for (i = 0; i < cfg->num_varinfo; ++i) {
13560                         MonoInst *ins = cfg->varinfo [i];
13561
13562                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
13563                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
13564                 }
13565         }
13566
13567         if (cfg->lmf_var && cfg->method == method && !cfg->llvm_only) {
13568                 cfg->cbb = init_localsbb;
13569                 emit_push_lmf (cfg);
13570         }
13571
13572         cfg->cbb = init_localsbb;
13573         emit_instrumentation_call (cfg, mono_profiler_method_enter);
13574
13575         if (seq_points) {
13576                 MonoBasicBlock *bb;
13577
13578                 /*
13579                  * Make seq points at backward branch targets interruptable.
13580                  */
13581                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
13582                         if (bb->code && bb->in_count > 1 && bb->code->opcode == OP_SEQ_POINT)
13583                                 bb->code->flags |= MONO_INST_SINGLE_STEP_LOC;
13584         }
13585
13586         /* Add a sequence point for method entry/exit events */
13587         if (seq_points && cfg->gen_sdb_seq_points) {
13588                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
13589                 MONO_ADD_INS (init_localsbb, ins);
13590                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
13591                 MONO_ADD_INS (cfg->bb_exit, ins);
13592         }
13593
13594         /*
13595          * Add seq points for IL offsets which have line number info, but wasn't generated a seq point during JITting because
13596          * the code they refer to was dead (#11880).
13597          */
13598         if (sym_seq_points) {
13599                 for (i = 0; i < header->code_size; ++i) {
13600                         if (mono_bitset_test_fast (seq_point_locs, i) && !mono_bitset_test_fast (seq_point_set_locs, i)) {
13601                                 MonoInst *ins;
13602
13603                                 NEW_SEQ_POINT (cfg, ins, i, FALSE);
13604                                 mono_add_seq_point (cfg, NULL, ins, SEQ_POINT_NATIVE_OFFSET_DEAD_CODE);
13605                         }
13606                 }
13607         }
13608
13609         cfg->ip = NULL;
13610
13611         if (cfg->method == method) {
13612                 MonoBasicBlock *bb;
13613                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13614                         bb->region = mono_find_block_region (cfg, bb->real_offset);
13615                         if (cfg->spvars)
13616                                 mono_create_spvar_for_region (cfg, bb->region);
13617                         if (cfg->verbose_level > 2)
13618                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
13619                 }
13620         }
13621
13622         if (inline_costs < 0) {
13623                 char *mname;
13624
13625                 /* Method is too large */
13626                 mname = mono_method_full_name (method, TRUE);
13627                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
13628                 cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
13629                 g_free (mname);
13630         }
13631
13632         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
13633                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
13634
13635         goto cleanup;
13636
13637 mono_error_exit:
13638         g_assert (!mono_error_ok (&cfg->error));
13639         goto cleanup;
13640  
13641  exception_exit:
13642         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
13643         goto cleanup;
13644
13645  unverified:
13646         set_exception_type_from_invalid_il (cfg, method, ip);
13647         goto cleanup;
13648
13649  cleanup:
13650         g_slist_free (class_inits);
13651         mono_basic_block_free (original_bb);
13652         cfg->dont_inline = g_list_remove (cfg->dont_inline, method);
13653         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
13654         if (cfg->exception_type)
13655                 return -1;
13656         else
13657                 return inline_costs;
13658 }
13659
13660 static int
13661 store_membase_reg_to_store_membase_imm (int opcode)
13662 {
13663         switch (opcode) {
13664         case OP_STORE_MEMBASE_REG:
13665                 return OP_STORE_MEMBASE_IMM;
13666         case OP_STOREI1_MEMBASE_REG:
13667                 return OP_STOREI1_MEMBASE_IMM;
13668         case OP_STOREI2_MEMBASE_REG:
13669                 return OP_STOREI2_MEMBASE_IMM;
13670         case OP_STOREI4_MEMBASE_REG:
13671                 return OP_STOREI4_MEMBASE_IMM;
13672         case OP_STOREI8_MEMBASE_REG:
13673                 return OP_STOREI8_MEMBASE_IMM;
13674         default:
13675                 g_assert_not_reached ();
13676         }
13677
13678         return -1;
13679 }               
13680
13681 int
13682 mono_op_to_op_imm (int opcode)
13683 {
13684         switch (opcode) {
13685         case OP_IADD:
13686                 return OP_IADD_IMM;
13687         case OP_ISUB:
13688                 return OP_ISUB_IMM;
13689         case OP_IDIV:
13690                 return OP_IDIV_IMM;
13691         case OP_IDIV_UN:
13692                 return OP_IDIV_UN_IMM;
13693         case OP_IREM:
13694                 return OP_IREM_IMM;
13695         case OP_IREM_UN:
13696                 return OP_IREM_UN_IMM;
13697         case OP_IMUL:
13698                 return OP_IMUL_IMM;
13699         case OP_IAND:
13700                 return OP_IAND_IMM;
13701         case OP_IOR:
13702                 return OP_IOR_IMM;
13703         case OP_IXOR:
13704                 return OP_IXOR_IMM;
13705         case OP_ISHL:
13706                 return OP_ISHL_IMM;
13707         case OP_ISHR:
13708                 return OP_ISHR_IMM;
13709         case OP_ISHR_UN:
13710                 return OP_ISHR_UN_IMM;
13711
13712         case OP_LADD:
13713                 return OP_LADD_IMM;
13714         case OP_LSUB:
13715                 return OP_LSUB_IMM;
13716         case OP_LAND:
13717                 return OP_LAND_IMM;
13718         case OP_LOR:
13719                 return OP_LOR_IMM;
13720         case OP_LXOR:
13721                 return OP_LXOR_IMM;
13722         case OP_LSHL:
13723                 return OP_LSHL_IMM;
13724         case OP_LSHR:
13725                 return OP_LSHR_IMM;
13726         case OP_LSHR_UN:
13727                 return OP_LSHR_UN_IMM;
13728 #if SIZEOF_REGISTER == 8
13729         case OP_LREM:
13730                 return OP_LREM_IMM;
13731 #endif
13732
13733         case OP_COMPARE:
13734                 return OP_COMPARE_IMM;
13735         case OP_ICOMPARE:
13736                 return OP_ICOMPARE_IMM;
13737         case OP_LCOMPARE:
13738                 return OP_LCOMPARE_IMM;
13739
13740         case OP_STORE_MEMBASE_REG:
13741                 return OP_STORE_MEMBASE_IMM;
13742         case OP_STOREI1_MEMBASE_REG:
13743                 return OP_STOREI1_MEMBASE_IMM;
13744         case OP_STOREI2_MEMBASE_REG:
13745                 return OP_STOREI2_MEMBASE_IMM;
13746         case OP_STOREI4_MEMBASE_REG:
13747                 return OP_STOREI4_MEMBASE_IMM;
13748
13749 #if defined(TARGET_X86) || defined (TARGET_AMD64)
13750         case OP_X86_PUSH:
13751                 return OP_X86_PUSH_IMM;
13752         case OP_X86_COMPARE_MEMBASE_REG:
13753                 return OP_X86_COMPARE_MEMBASE_IMM;
13754 #endif
13755 #if defined(TARGET_AMD64)
13756         case OP_AMD64_ICOMPARE_MEMBASE_REG:
13757                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13758 #endif
13759         case OP_VOIDCALL_REG:
13760                 return OP_VOIDCALL;
13761         case OP_CALL_REG:
13762                 return OP_CALL;
13763         case OP_LCALL_REG:
13764                 return OP_LCALL;
13765         case OP_FCALL_REG:
13766                 return OP_FCALL;
13767         case OP_LOCALLOC:
13768                 return OP_LOCALLOC_IMM;
13769         }
13770
13771         return -1;
13772 }
13773
13774 static int
13775 ldind_to_load_membase (int opcode)
13776 {
13777         switch (opcode) {
13778         case CEE_LDIND_I1:
13779                 return OP_LOADI1_MEMBASE;
13780         case CEE_LDIND_U1:
13781                 return OP_LOADU1_MEMBASE;
13782         case CEE_LDIND_I2:
13783                 return OP_LOADI2_MEMBASE;
13784         case CEE_LDIND_U2:
13785                 return OP_LOADU2_MEMBASE;
13786         case CEE_LDIND_I4:
13787                 return OP_LOADI4_MEMBASE;
13788         case CEE_LDIND_U4:
13789                 return OP_LOADU4_MEMBASE;
13790         case CEE_LDIND_I:
13791                 return OP_LOAD_MEMBASE;
13792         case CEE_LDIND_REF:
13793                 return OP_LOAD_MEMBASE;
13794         case CEE_LDIND_I8:
13795                 return OP_LOADI8_MEMBASE;
13796         case CEE_LDIND_R4:
13797                 return OP_LOADR4_MEMBASE;
13798         case CEE_LDIND_R8:
13799                 return OP_LOADR8_MEMBASE;
13800         default:
13801                 g_assert_not_reached ();
13802         }
13803
13804         return -1;
13805 }
13806
13807 static int
13808 stind_to_store_membase (int opcode)
13809 {
13810         switch (opcode) {
13811         case CEE_STIND_I1:
13812                 return OP_STOREI1_MEMBASE_REG;
13813         case CEE_STIND_I2:
13814                 return OP_STOREI2_MEMBASE_REG;
13815         case CEE_STIND_I4:
13816                 return OP_STOREI4_MEMBASE_REG;
13817         case CEE_STIND_I:
13818         case CEE_STIND_REF:
13819                 return OP_STORE_MEMBASE_REG;
13820         case CEE_STIND_I8:
13821                 return OP_STOREI8_MEMBASE_REG;
13822         case CEE_STIND_R4:
13823                 return OP_STORER4_MEMBASE_REG;
13824         case CEE_STIND_R8:
13825                 return OP_STORER8_MEMBASE_REG;
13826         default:
13827                 g_assert_not_reached ();
13828         }
13829
13830         return -1;
13831 }
13832
13833 int
13834 mono_load_membase_to_load_mem (int opcode)
13835 {
13836         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
13837 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13838         switch (opcode) {
13839         case OP_LOAD_MEMBASE:
13840                 return OP_LOAD_MEM;
13841         case OP_LOADU1_MEMBASE:
13842                 return OP_LOADU1_MEM;
13843         case OP_LOADU2_MEMBASE:
13844                 return OP_LOADU2_MEM;
13845         case OP_LOADI4_MEMBASE:
13846                 return OP_LOADI4_MEM;
13847         case OP_LOADU4_MEMBASE:
13848                 return OP_LOADU4_MEM;
13849 #if SIZEOF_REGISTER == 8
13850         case OP_LOADI8_MEMBASE:
13851                 return OP_LOADI8_MEM;
13852 #endif
13853         }
13854 #endif
13855
13856         return -1;
13857 }
13858
13859 static inline int
13860 op_to_op_dest_membase (int store_opcode, int opcode)
13861 {
13862 #if defined(TARGET_X86)
13863         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
13864                 return -1;
13865
13866         switch (opcode) {
13867         case OP_IADD:
13868                 return OP_X86_ADD_MEMBASE_REG;
13869         case OP_ISUB:
13870                 return OP_X86_SUB_MEMBASE_REG;
13871         case OP_IAND:
13872                 return OP_X86_AND_MEMBASE_REG;
13873         case OP_IOR:
13874                 return OP_X86_OR_MEMBASE_REG;
13875         case OP_IXOR:
13876                 return OP_X86_XOR_MEMBASE_REG;
13877         case OP_ADD_IMM:
13878         case OP_IADD_IMM:
13879                 return OP_X86_ADD_MEMBASE_IMM;
13880         case OP_SUB_IMM:
13881         case OP_ISUB_IMM:
13882                 return OP_X86_SUB_MEMBASE_IMM;
13883         case OP_AND_IMM:
13884         case OP_IAND_IMM:
13885                 return OP_X86_AND_MEMBASE_IMM;
13886         case OP_OR_IMM:
13887         case OP_IOR_IMM:
13888                 return OP_X86_OR_MEMBASE_IMM;
13889         case OP_XOR_IMM:
13890         case OP_IXOR_IMM:
13891                 return OP_X86_XOR_MEMBASE_IMM;
13892         case OP_MOVE:
13893                 return OP_NOP;
13894         }
13895 #endif
13896
13897 #if defined(TARGET_AMD64)
13898         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
13899                 return -1;
13900
13901         switch (opcode) {
13902         case OP_IADD:
13903                 return OP_X86_ADD_MEMBASE_REG;
13904         case OP_ISUB:
13905                 return OP_X86_SUB_MEMBASE_REG;
13906         case OP_IAND:
13907                 return OP_X86_AND_MEMBASE_REG;
13908         case OP_IOR:
13909                 return OP_X86_OR_MEMBASE_REG;
13910         case OP_IXOR:
13911                 return OP_X86_XOR_MEMBASE_REG;
13912         case OP_IADD_IMM:
13913                 return OP_X86_ADD_MEMBASE_IMM;
13914         case OP_ISUB_IMM:
13915                 return OP_X86_SUB_MEMBASE_IMM;
13916         case OP_IAND_IMM:
13917                 return OP_X86_AND_MEMBASE_IMM;
13918         case OP_IOR_IMM:
13919                 return OP_X86_OR_MEMBASE_IMM;
13920         case OP_IXOR_IMM:
13921                 return OP_X86_XOR_MEMBASE_IMM;
13922         case OP_LADD:
13923                 return OP_AMD64_ADD_MEMBASE_REG;
13924         case OP_LSUB:
13925                 return OP_AMD64_SUB_MEMBASE_REG;
13926         case OP_LAND:
13927                 return OP_AMD64_AND_MEMBASE_REG;
13928         case OP_LOR:
13929                 return OP_AMD64_OR_MEMBASE_REG;
13930         case OP_LXOR:
13931                 return OP_AMD64_XOR_MEMBASE_REG;
13932         case OP_ADD_IMM:
13933         case OP_LADD_IMM:
13934                 return OP_AMD64_ADD_MEMBASE_IMM;
13935         case OP_SUB_IMM:
13936         case OP_LSUB_IMM:
13937                 return OP_AMD64_SUB_MEMBASE_IMM;
13938         case OP_AND_IMM:
13939         case OP_LAND_IMM:
13940                 return OP_AMD64_AND_MEMBASE_IMM;
13941         case OP_OR_IMM:
13942         case OP_LOR_IMM:
13943                 return OP_AMD64_OR_MEMBASE_IMM;
13944         case OP_XOR_IMM:
13945         case OP_LXOR_IMM:
13946                 return OP_AMD64_XOR_MEMBASE_IMM;
13947         case OP_MOVE:
13948                 return OP_NOP;
13949         }
13950 #endif
13951
13952         return -1;
13953 }
13954
13955 static inline int
13956 op_to_op_store_membase (int store_opcode, int opcode)
13957 {
13958 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13959         switch (opcode) {
13960         case OP_ICEQ:
13961                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13962                         return OP_X86_SETEQ_MEMBASE;
13963         case OP_CNE:
13964                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13965                         return OP_X86_SETNE_MEMBASE;
13966         }
13967 #endif
13968
13969         return -1;
13970 }
13971
13972 static inline int
13973 op_to_op_src1_membase (MonoCompile *cfg, int load_opcode, int opcode)
13974 {
13975 #ifdef TARGET_X86
13976         /* FIXME: This has sign extension issues */
13977         /*
13978         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13979                 return OP_X86_COMPARE_MEMBASE8_IMM;
13980         */
13981
13982         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13983                 return -1;
13984
13985         switch (opcode) {
13986         case OP_X86_PUSH:
13987                 return OP_X86_PUSH_MEMBASE;
13988         case OP_COMPARE_IMM:
13989         case OP_ICOMPARE_IMM:
13990                 return OP_X86_COMPARE_MEMBASE_IMM;
13991         case OP_COMPARE:
13992         case OP_ICOMPARE:
13993                 return OP_X86_COMPARE_MEMBASE_REG;
13994         }
13995 #endif
13996
13997 #ifdef TARGET_AMD64
13998         /* FIXME: This has sign extension issues */
13999         /*
14000         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
14001                 return OP_X86_COMPARE_MEMBASE8_IMM;
14002         */
14003
14004         switch (opcode) {
14005         case OP_X86_PUSH:
14006                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
14007                         return OP_X86_PUSH_MEMBASE;
14008                 break;
14009                 /* FIXME: This only works for 32 bit immediates
14010         case OP_COMPARE_IMM:
14011         case OP_LCOMPARE_IMM:
14012                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
14013                         return OP_AMD64_COMPARE_MEMBASE_IMM;
14014                 */
14015         case OP_ICOMPARE_IMM:
14016                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
14017                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
14018                 break;
14019         case OP_COMPARE:
14020         case OP_LCOMPARE:
14021                 if (cfg->backend->ilp32 && load_opcode == OP_LOAD_MEMBASE)
14022                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
14023                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
14024                         return OP_AMD64_COMPARE_MEMBASE_REG;
14025                 break;
14026         case OP_ICOMPARE:
14027                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
14028                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
14029                 break;
14030         }
14031 #endif
14032
14033         return -1;
14034 }
14035
14036 static inline int
14037 op_to_op_src2_membase (MonoCompile *cfg, int load_opcode, int opcode)
14038 {
14039 #ifdef TARGET_X86
14040         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
14041                 return -1;
14042         
14043         switch (opcode) {
14044         case OP_COMPARE:
14045         case OP_ICOMPARE:
14046                 return OP_X86_COMPARE_REG_MEMBASE;
14047         case OP_IADD:
14048                 return OP_X86_ADD_REG_MEMBASE;
14049         case OP_ISUB:
14050                 return OP_X86_SUB_REG_MEMBASE;
14051         case OP_IAND:
14052                 return OP_X86_AND_REG_MEMBASE;
14053         case OP_IOR:
14054                 return OP_X86_OR_REG_MEMBASE;
14055         case OP_IXOR:
14056                 return OP_X86_XOR_REG_MEMBASE;
14057         }
14058 #endif
14059
14060 #ifdef TARGET_AMD64
14061         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && cfg->backend->ilp32)) {
14062                 switch (opcode) {
14063                 case OP_ICOMPARE:
14064                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
14065                 case OP_IADD:
14066                         return OP_X86_ADD_REG_MEMBASE;
14067                 case OP_ISUB:
14068                         return OP_X86_SUB_REG_MEMBASE;
14069                 case OP_IAND:
14070                         return OP_X86_AND_REG_MEMBASE;
14071                 case OP_IOR:
14072                         return OP_X86_OR_REG_MEMBASE;
14073                 case OP_IXOR:
14074                         return OP_X86_XOR_REG_MEMBASE;
14075                 }
14076         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32)) {
14077                 switch (opcode) {
14078                 case OP_COMPARE:
14079                 case OP_LCOMPARE:
14080                         return OP_AMD64_COMPARE_REG_MEMBASE;
14081                 case OP_LADD:
14082                         return OP_AMD64_ADD_REG_MEMBASE;
14083                 case OP_LSUB:
14084                         return OP_AMD64_SUB_REG_MEMBASE;
14085                 case OP_LAND:
14086                         return OP_AMD64_AND_REG_MEMBASE;
14087                 case OP_LOR:
14088                         return OP_AMD64_OR_REG_MEMBASE;
14089                 case OP_LXOR:
14090                         return OP_AMD64_XOR_REG_MEMBASE;
14091                 }
14092         }
14093 #endif
14094
14095         return -1;
14096 }
14097
14098 int
14099 mono_op_to_op_imm_noemul (int opcode)
14100 {
14101         switch (opcode) {
14102 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
14103         case OP_LSHR:
14104         case OP_LSHL:
14105         case OP_LSHR_UN:
14106                 return -1;
14107 #endif
14108 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
14109         case OP_IDIV:
14110         case OP_IDIV_UN:
14111         case OP_IREM:
14112         case OP_IREM_UN:
14113                 return -1;
14114 #endif
14115 #if defined(MONO_ARCH_EMULATE_MUL_DIV)
14116         case OP_IMUL:
14117                 return -1;
14118 #endif
14119         default:
14120                 return mono_op_to_op_imm (opcode);
14121         }
14122 }
14123
14124 /**
14125  * mono_handle_global_vregs:
14126  *
14127  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
14128  * for them.
14129  */
14130 void
14131 mono_handle_global_vregs (MonoCompile *cfg)
14132 {
14133         gint32 *vreg_to_bb;
14134         MonoBasicBlock *bb;
14135         int i, pos;
14136
14137         vreg_to_bb = (gint32 *)mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
14138
14139 #ifdef MONO_ARCH_SIMD_INTRINSICS
14140         if (cfg->uses_simd_intrinsics)
14141                 mono_simd_simplify_indirection (cfg);
14142 #endif
14143
14144         /* Find local vregs used in more than one bb */
14145         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
14146                 MonoInst *ins = bb->code;       
14147                 int block_num = bb->block_num;
14148
14149                 if (cfg->verbose_level > 2)
14150                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
14151
14152                 cfg->cbb = bb;
14153                 for (; ins; ins = ins->next) {
14154                         const char *spec = INS_INFO (ins->opcode);
14155                         int regtype = 0, regindex;
14156                         gint32 prev_bb;
14157
14158                         if (G_UNLIKELY (cfg->verbose_level > 2))
14159                                 mono_print_ins (ins);
14160
14161                         g_assert (ins->opcode >= MONO_CEE_LAST);
14162
14163                         for (regindex = 0; regindex < 4; regindex ++) {
14164                                 int vreg = 0;
14165
14166                                 if (regindex == 0) {
14167                                         regtype = spec [MONO_INST_DEST];
14168                                         if (regtype == ' ')
14169                                                 continue;
14170                                         vreg = ins->dreg;
14171                                 } else if (regindex == 1) {
14172                                         regtype = spec [MONO_INST_SRC1];
14173                                         if (regtype == ' ')
14174                                                 continue;
14175                                         vreg = ins->sreg1;
14176                                 } else if (regindex == 2) {
14177                                         regtype = spec [MONO_INST_SRC2];
14178                                         if (regtype == ' ')
14179                                                 continue;
14180                                         vreg = ins->sreg2;
14181                                 } else if (regindex == 3) {
14182                                         regtype = spec [MONO_INST_SRC3];
14183                                         if (regtype == ' ')
14184                                                 continue;
14185                                         vreg = ins->sreg3;
14186                                 }
14187
14188 #if SIZEOF_REGISTER == 4
14189                                 /* In the LLVM case, the long opcodes are not decomposed */
14190                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
14191                                         /*
14192                                          * Since some instructions reference the original long vreg,
14193                                          * and some reference the two component vregs, it is quite hard
14194                                          * to determine when it needs to be global. So be conservative.
14195                                          */
14196                                         if (!get_vreg_to_inst (cfg, vreg)) {
14197                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
14198
14199                                                 if (cfg->verbose_level > 2)
14200                                                         printf ("LONG VREG R%d made global.\n", vreg);
14201                                         }
14202
14203                                         /*
14204                                          * Make the component vregs volatile since the optimizations can
14205                                          * get confused otherwise.
14206                                          */
14207                                         get_vreg_to_inst (cfg, MONO_LVREG_LS (vreg))->flags |= MONO_INST_VOLATILE;
14208                                         get_vreg_to_inst (cfg, MONO_LVREG_MS (vreg))->flags |= MONO_INST_VOLATILE;
14209                                 }
14210 #endif
14211
14212                                 g_assert (vreg != -1);
14213
14214                                 prev_bb = vreg_to_bb [vreg];
14215                                 if (prev_bb == 0) {
14216                                         /* 0 is a valid block num */
14217                                         vreg_to_bb [vreg] = block_num + 1;
14218                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
14219                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
14220                                                 continue;
14221
14222                                         if (!get_vreg_to_inst (cfg, vreg)) {
14223                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14224                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
14225
14226                                                 switch (regtype) {
14227                                                 case 'i':
14228                                                         if (vreg_is_ref (cfg, vreg))
14229                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg);
14230                                                         else
14231                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
14232                                                         break;
14233                                                 case 'l':
14234                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
14235                                                         break;
14236                                                 case 'f':
14237                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
14238                                                         break;
14239                                                 case 'v':
14240                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
14241                                                         break;
14242                                                 default:
14243                                                         g_assert_not_reached ();
14244                                                 }
14245                                         }
14246
14247                                         /* Flag as having been used in more than one bb */
14248                                         vreg_to_bb [vreg] = -1;
14249                                 }
14250                         }
14251                 }
14252         }
14253
14254         /* If a variable is used in only one bblock, convert it into a local vreg */
14255         for (i = 0; i < cfg->num_varinfo; i++) {
14256                 MonoInst *var = cfg->varinfo [i];
14257                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
14258
14259                 switch (var->type) {
14260                 case STACK_I4:
14261                 case STACK_OBJ:
14262                 case STACK_PTR:
14263                 case STACK_MP:
14264                 case STACK_VTYPE:
14265 #if SIZEOF_REGISTER == 8
14266                 case STACK_I8:
14267 #endif
14268 #if !defined(TARGET_X86)
14269                 /* Enabling this screws up the fp stack on x86 */
14270                 case STACK_R8:
14271 #endif
14272                         if (mono_arch_is_soft_float ())
14273                                 break;
14274
14275                         /*
14276                         if (var->type == STACK_VTYPE && cfg->gsharedvt && mini_is_gsharedvt_variable_type (var->inst_vtype))
14277                                 break;
14278                         */
14279
14280                         /* Arguments are implicitly global */
14281                         /* Putting R4 vars into registers doesn't work currently */
14282                         /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
14283                         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) {
14284                                 /* 
14285                                  * Make that the variable's liveness interval doesn't contain a call, since
14286                                  * that would cause the lvreg to be spilled, making the whole optimization
14287                                  * useless.
14288                                  */
14289                                 /* This is too slow for JIT compilation */
14290 #if 0
14291                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
14292                                         MonoInst *ins;
14293                                         int def_index, call_index, ins_index;
14294                                         gboolean spilled = FALSE;
14295
14296                                         def_index = -1;
14297                                         call_index = -1;
14298                                         ins_index = 0;
14299                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
14300                                                 const char *spec = INS_INFO (ins->opcode);
14301
14302                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
14303                                                         def_index = ins_index;
14304
14305                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
14306                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
14307                                                         if (call_index > def_index) {
14308                                                                 spilled = TRUE;
14309                                                                 break;
14310                                                         }
14311                                                 }
14312
14313                                                 if (MONO_IS_CALL (ins))
14314                                                         call_index = ins_index;
14315
14316                                                 ins_index ++;
14317                                         }
14318
14319                                         if (spilled)
14320                                                 break;
14321                                 }
14322 #endif
14323
14324                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14325                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
14326                                 var->flags |= MONO_INST_IS_DEAD;
14327                                 cfg->vreg_to_inst [var->dreg] = NULL;
14328                         }
14329                         break;
14330                 }
14331         }
14332
14333         /* 
14334          * Compress the varinfo and vars tables so the liveness computation is faster and
14335          * takes up less space.
14336          */
14337         pos = 0;
14338         for (i = 0; i < cfg->num_varinfo; ++i) {
14339                 MonoInst *var = cfg->varinfo [i];
14340                 if (pos < i && cfg->locals_start == i)
14341                         cfg->locals_start = pos;
14342                 if (!(var->flags & MONO_INST_IS_DEAD)) {
14343                         if (pos < i) {
14344                                 cfg->varinfo [pos] = cfg->varinfo [i];
14345                                 cfg->varinfo [pos]->inst_c0 = pos;
14346                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
14347                                 cfg->vars [pos].idx = pos;
14348 #if SIZEOF_REGISTER == 4
14349                                 if (cfg->varinfo [pos]->type == STACK_I8) {
14350                                         /* Modify the two component vars too */
14351                                         MonoInst *var1;
14352
14353                                         var1 = get_vreg_to_inst (cfg, MONO_LVREG_LS (cfg->varinfo [pos]->dreg));
14354                                         var1->inst_c0 = pos;
14355                                         var1 = get_vreg_to_inst (cfg, MONO_LVREG_MS (cfg->varinfo [pos]->dreg));
14356                                         var1->inst_c0 = pos;
14357                                 }
14358 #endif
14359                         }
14360                         pos ++;
14361                 }
14362         }
14363         cfg->num_varinfo = pos;
14364         if (cfg->locals_start > cfg->num_varinfo)
14365                 cfg->locals_start = cfg->num_varinfo;
14366 }
14367
14368 /*
14369  * mono_allocate_gsharedvt_vars:
14370  *
14371  *   Allocate variables with gsharedvt types to entries in the MonoGSharedVtMethodRuntimeInfo.entries array.
14372  * Initialize cfg->gsharedvt_vreg_to_idx with the mapping between vregs and indexes.
14373  */
14374 void
14375 mono_allocate_gsharedvt_vars (MonoCompile *cfg)
14376 {
14377         int i;
14378
14379         cfg->gsharedvt_vreg_to_idx = (int *)mono_mempool_alloc0 (cfg->mempool, sizeof (int) * cfg->next_vreg);
14380
14381         for (i = 0; i < cfg->num_varinfo; ++i) {
14382                 MonoInst *ins = cfg->varinfo [i];
14383                 int idx;
14384
14385                 if (mini_is_gsharedvt_variable_type (ins->inst_vtype)) {
14386                         if (i >= cfg->locals_start) {
14387                                 /* Local */
14388                                 idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
14389                                 cfg->gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
14390                                 ins->opcode = OP_GSHAREDVT_LOCAL;
14391                                 ins->inst_imm = idx;
14392                         } else {
14393                                 /* Arg */
14394                                 cfg->gsharedvt_vreg_to_idx [ins->dreg] = -1;
14395                                 ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
14396                         }
14397                 }
14398         }
14399 }
14400
14401 /**
14402  * mono_spill_global_vars:
14403  *
14404  *   Generate spill code for variables which are not allocated to registers, 
14405  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
14406  * code is generated which could be optimized by the local optimization passes.
14407  */
14408 void
14409 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
14410 {
14411         MonoBasicBlock *bb;
14412         char spec2 [16];
14413         int orig_next_vreg;
14414         guint32 *vreg_to_lvreg;
14415         guint32 *lvregs;
14416         guint32 i, lvregs_len;
14417         gboolean dest_has_lvreg = FALSE;
14418         MonoStackType stacktypes [128];
14419         MonoInst **live_range_start, **live_range_end;
14420         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
14421
14422         *need_local_opts = FALSE;
14423
14424         memset (spec2, 0, sizeof (spec2));
14425
14426         /* FIXME: Move this function to mini.c */
14427         stacktypes ['i'] = STACK_PTR;
14428         stacktypes ['l'] = STACK_I8;
14429         stacktypes ['f'] = STACK_R8;
14430 #ifdef MONO_ARCH_SIMD_INTRINSICS
14431         stacktypes ['x'] = STACK_VTYPE;
14432 #endif
14433
14434 #if SIZEOF_REGISTER == 4
14435         /* Create MonoInsts for longs */
14436         for (i = 0; i < cfg->num_varinfo; i++) {
14437                 MonoInst *ins = cfg->varinfo [i];
14438
14439                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
14440                         switch (ins->type) {
14441                         case STACK_R8:
14442                         case STACK_I8: {
14443                                 MonoInst *tree;
14444
14445                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
14446                                         break;
14447
14448                                 g_assert (ins->opcode == OP_REGOFFSET);
14449
14450                                 tree = get_vreg_to_inst (cfg, MONO_LVREG_LS (ins->dreg));
14451                                 g_assert (tree);
14452                                 tree->opcode = OP_REGOFFSET;
14453                                 tree->inst_basereg = ins->inst_basereg;
14454                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
14455
14456                                 tree = get_vreg_to_inst (cfg, MONO_LVREG_MS (ins->dreg));
14457                                 g_assert (tree);
14458                                 tree->opcode = OP_REGOFFSET;
14459                                 tree->inst_basereg = ins->inst_basereg;
14460                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
14461                                 break;
14462                         }
14463                         default:
14464                                 break;
14465                         }
14466                 }
14467         }
14468 #endif
14469
14470         if (cfg->compute_gc_maps) {
14471                 /* registers need liveness info even for !non refs */
14472                 for (i = 0; i < cfg->num_varinfo; i++) {
14473                         MonoInst *ins = cfg->varinfo [i];
14474
14475                         if (ins->opcode == OP_REGVAR)
14476                                 ins->flags |= MONO_INST_GC_TRACK;
14477                 }
14478         }
14479                 
14480         /* FIXME: widening and truncation */
14481
14482         /*
14483          * As an optimization, when a variable allocated to the stack is first loaded into 
14484          * an lvreg, we will remember the lvreg and use it the next time instead of loading
14485          * the variable again.
14486          */
14487         orig_next_vreg = cfg->next_vreg;
14488         vreg_to_lvreg = (guint32 *)mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
14489         lvregs = (guint32 *)mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
14490         lvregs_len = 0;
14491
14492         /* 
14493          * These arrays contain the first and last instructions accessing a given
14494          * variable.
14495          * Since we emit bblocks in the same order we process them here, and we
14496          * don't split live ranges, these will precisely describe the live range of
14497          * the variable, i.e. the instruction range where a valid value can be found
14498          * in the variables location.
14499          * The live range is computed using the liveness info computed by the liveness pass.
14500          * We can't use vmv->range, since that is an abstract live range, and we need
14501          * one which is instruction precise.
14502          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
14503          */
14504         /* FIXME: Only do this if debugging info is requested */
14505         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
14506         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
14507         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
14508         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
14509         
14510         /* Add spill loads/stores */
14511         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
14512                 MonoInst *ins;
14513
14514                 if (cfg->verbose_level > 2)
14515                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
14516
14517                 /* Clear vreg_to_lvreg array */
14518                 for (i = 0; i < lvregs_len; i++)
14519                         vreg_to_lvreg [lvregs [i]] = 0;
14520                 lvregs_len = 0;
14521
14522                 cfg->cbb = bb;
14523                 MONO_BB_FOR_EACH_INS (bb, ins) {
14524                         const char *spec = INS_INFO (ins->opcode);
14525                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
14526                         gboolean store, no_lvreg;
14527                         int sregs [MONO_MAX_SRC_REGS];
14528
14529                         if (G_UNLIKELY (cfg->verbose_level > 2))
14530                                 mono_print_ins (ins);
14531
14532                         if (ins->opcode == OP_NOP)
14533                                 continue;
14534
14535                         /* 
14536                          * We handle LDADDR here as well, since it can only be decomposed
14537                          * when variable addresses are known.
14538                          */
14539                         if (ins->opcode == OP_LDADDR) {
14540                                 MonoInst *var = (MonoInst *)ins->inst_p0;
14541
14542                                 if (var->opcode == OP_VTARG_ADDR) {
14543                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
14544                                         MonoInst *vtaddr = var->inst_left;
14545                                         if (vtaddr->opcode == OP_REGVAR) {
14546                                                 ins->opcode = OP_MOVE;
14547                                                 ins->sreg1 = vtaddr->dreg;
14548                                         }
14549                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
14550                                                 ins->opcode = OP_LOAD_MEMBASE;
14551                                                 ins->inst_basereg = vtaddr->inst_basereg;
14552                                                 ins->inst_offset = vtaddr->inst_offset;
14553                                         } else
14554                                                 NOT_IMPLEMENTED;
14555                                 } else if (cfg->gsharedvt && cfg->gsharedvt_vreg_to_idx [var->dreg] < 0) {
14556                                         /* gsharedvt arg passed by ref */
14557                                         g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
14558
14559                                         ins->opcode = OP_LOAD_MEMBASE;
14560                                         ins->inst_basereg = var->inst_basereg;
14561                                         ins->inst_offset = var->inst_offset;
14562                                 } else if (cfg->gsharedvt && cfg->gsharedvt_vreg_to_idx [var->dreg]) {
14563                                         MonoInst *load, *load2, *load3;
14564                                         int idx = cfg->gsharedvt_vreg_to_idx [var->dreg] - 1;
14565                                         int reg1, reg2, reg3;
14566                                         MonoInst *info_var = cfg->gsharedvt_info_var;
14567                                         MonoInst *locals_var = cfg->gsharedvt_locals_var;
14568
14569                                         /*
14570                                          * gsharedvt local.
14571                                          * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
14572                                          */
14573
14574                                         g_assert (var->opcode == OP_GSHAREDVT_LOCAL);
14575
14576                                         g_assert (info_var);
14577                                         g_assert (locals_var);
14578
14579                                         /* Mark the instruction used to compute the locals var as used */
14580                                         cfg->gsharedvt_locals_var_ins = NULL;
14581
14582                                         /* Load the offset */
14583                                         if (info_var->opcode == OP_REGOFFSET) {
14584                                                 reg1 = alloc_ireg (cfg);
14585                                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, reg1, info_var->inst_basereg, info_var->inst_offset);
14586                                         } else if (info_var->opcode == OP_REGVAR) {
14587                                                 load = NULL;
14588                                                 reg1 = info_var->dreg;
14589                                         } else {
14590                                                 g_assert_not_reached ();
14591                                         }
14592                                         reg2 = alloc_ireg (cfg);
14593                                         NEW_LOAD_MEMBASE (cfg, load2, OP_LOADI4_MEMBASE, reg2, reg1, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
14594                                         /* Load the locals area address */
14595                                         reg3 = alloc_ireg (cfg);
14596                                         if (locals_var->opcode == OP_REGOFFSET) {
14597                                                 NEW_LOAD_MEMBASE (cfg, load3, OP_LOAD_MEMBASE, reg3, locals_var->inst_basereg, locals_var->inst_offset);
14598                                         } else if (locals_var->opcode == OP_REGVAR) {
14599                                                 NEW_UNALU (cfg, load3, OP_MOVE, reg3, locals_var->dreg);
14600                                         } else {
14601                                                 g_assert_not_reached ();
14602                                         }
14603                                         /* Compute the address */
14604                                         ins->opcode = OP_PADD;
14605                                         ins->sreg1 = reg3;
14606                                         ins->sreg2 = reg2;
14607
14608                                         mono_bblock_insert_before_ins (bb, ins, load3);
14609                                         mono_bblock_insert_before_ins (bb, load3, load2);
14610                                         if (load)
14611                                                 mono_bblock_insert_before_ins (bb, load2, load);
14612                                 } else {
14613                                         g_assert (var->opcode == OP_REGOFFSET);
14614
14615                                         ins->opcode = OP_ADD_IMM;
14616                                         ins->sreg1 = var->inst_basereg;
14617                                         ins->inst_imm = var->inst_offset;
14618                                 }
14619
14620                                 *need_local_opts = TRUE;
14621                                 spec = INS_INFO (ins->opcode);
14622                         }
14623
14624                         if (ins->opcode < MONO_CEE_LAST) {
14625                                 mono_print_ins (ins);
14626                                 g_assert_not_reached ();
14627                         }
14628
14629                         /*
14630                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
14631                          * src register.
14632                          * FIXME:
14633                          */
14634                         if (MONO_IS_STORE_MEMBASE (ins)) {
14635                                 tmp_reg = ins->dreg;
14636                                 ins->dreg = ins->sreg2;
14637                                 ins->sreg2 = tmp_reg;
14638                                 store = TRUE;
14639
14640                                 spec2 [MONO_INST_DEST] = ' ';
14641                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14642                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14643                                 spec2 [MONO_INST_SRC3] = ' ';
14644                                 spec = spec2;
14645                         } else if (MONO_IS_STORE_MEMINDEX (ins))
14646                                 g_assert_not_reached ();
14647                         else
14648                                 store = FALSE;
14649                         no_lvreg = FALSE;
14650
14651                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
14652                                 printf ("\t %.3s %d", spec, ins->dreg);
14653                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
14654                                 for (srcindex = 0; srcindex < num_sregs; ++srcindex)
14655                                         printf (" %d", sregs [srcindex]);
14656                                 printf ("\n");
14657                         }
14658
14659                         /***************/
14660                         /*    DREG     */
14661                         /***************/
14662                         regtype = spec [MONO_INST_DEST];
14663                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
14664                         prev_dreg = -1;
14665
14666                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
14667                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
14668                                 MonoInst *store_ins;
14669                                 int store_opcode;
14670                                 MonoInst *def_ins = ins;
14671                                 int dreg = ins->dreg; /* The original vreg */
14672
14673                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
14674
14675                                 if (var->opcode == OP_REGVAR) {
14676                                         ins->dreg = var->dreg;
14677                                 } 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)) {
14678                                         /* 
14679                                          * Instead of emitting a load+store, use a _membase opcode.
14680                                          */
14681                                         g_assert (var->opcode == OP_REGOFFSET);
14682                                         if (ins->opcode == OP_MOVE) {
14683                                                 NULLIFY_INS (ins);
14684                                                 def_ins = NULL;
14685                                         } else {
14686                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
14687                                                 ins->inst_basereg = var->inst_basereg;
14688                                                 ins->inst_offset = var->inst_offset;
14689                                                 ins->dreg = -1;
14690                                         }
14691                                         spec = INS_INFO (ins->opcode);
14692                                 } else {
14693                                         guint32 lvreg;
14694
14695                                         g_assert (var->opcode == OP_REGOFFSET);
14696
14697                                         prev_dreg = ins->dreg;
14698
14699                                         /* Invalidate any previous lvreg for this vreg */
14700                                         vreg_to_lvreg [ins->dreg] = 0;
14701
14702                                         lvreg = 0;
14703
14704                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
14705                                                 regtype = 'l';
14706                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
14707                                         }
14708
14709                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
14710
14711 #if SIZEOF_REGISTER != 8
14712                                         if (regtype == 'l') {
14713                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET, MONO_LVREG_LS (ins->dreg));
14714                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14715                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET, MONO_LVREG_MS (ins->dreg));
14716                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14717                                                 def_ins = store_ins;
14718                                         }
14719                                         else
14720 #endif
14721                                         {
14722                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
14723
14724                                                 /* Try to fuse the store into the instruction itself */
14725                                                 /* FIXME: Add more instructions */
14726                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
14727                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
14728                                                         ins->inst_imm = ins->inst_c0;
14729                                                         ins->inst_destbasereg = var->inst_basereg;
14730                                                         ins->inst_offset = var->inst_offset;
14731                                                         spec = INS_INFO (ins->opcode);
14732                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE) || (ins->opcode == OP_RMOVE))) {
14733                                                         ins->opcode = store_opcode;
14734                                                         ins->inst_destbasereg = var->inst_basereg;
14735                                                         ins->inst_offset = var->inst_offset;
14736
14737                                                         no_lvreg = TRUE;
14738
14739                                                         tmp_reg = ins->dreg;
14740                                                         ins->dreg = ins->sreg2;
14741                                                         ins->sreg2 = tmp_reg;
14742                                                         store = TRUE;
14743
14744                                                         spec2 [MONO_INST_DEST] = ' ';
14745                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14746                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14747                                                         spec2 [MONO_INST_SRC3] = ' ';
14748                                                         spec = spec2;
14749                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
14750                                                         // FIXME: The backends expect the base reg to be in inst_basereg
14751                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
14752                                                         ins->dreg = -1;
14753                                                         ins->inst_basereg = var->inst_basereg;
14754                                                         ins->inst_offset = var->inst_offset;
14755                                                         spec = INS_INFO (ins->opcode);
14756                                                 } else {
14757                                                         /* printf ("INS: "); mono_print_ins (ins); */
14758                                                         /* Create a store instruction */
14759                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
14760
14761                                                         /* Insert it after the instruction */
14762                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
14763
14764                                                         def_ins = store_ins;
14765
14766                                                         /* 
14767                                                          * We can't assign ins->dreg to var->dreg here, since the
14768                                                          * sregs could use it. So set a flag, and do it after
14769                                                          * the sregs.
14770                                                          */
14771                                                         if ((!cfg->backend->use_fpstack || ((store_opcode != OP_STORER8_MEMBASE_REG) && (store_opcode != OP_STORER4_MEMBASE_REG))) && !((var)->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT)))
14772                                                                 dest_has_lvreg = TRUE;
14773                                                 }
14774                                         }
14775                                 }
14776
14777                                 if (def_ins && !live_range_start [dreg]) {
14778                                         live_range_start [dreg] = def_ins;
14779                                         live_range_start_bb [dreg] = bb;
14780                                 }
14781
14782                                 if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) {
14783                                         MonoInst *tmp;
14784
14785                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
14786                                         tmp->inst_c1 = dreg;
14787                                         mono_bblock_insert_after_ins (bb, def_ins, tmp);
14788                                 }
14789                         }
14790
14791                         /************/
14792                         /*  SREGS   */
14793                         /************/
14794                         num_sregs = mono_inst_get_src_registers (ins, sregs);
14795                         for (srcindex = 0; srcindex < 3; ++srcindex) {
14796                                 regtype = spec [MONO_INST_SRC1 + srcindex];
14797                                 sreg = sregs [srcindex];
14798
14799                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
14800                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
14801                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
14802                                         MonoInst *use_ins = ins;
14803                                         MonoInst *load_ins;
14804                                         guint32 load_opcode;
14805
14806                                         if (var->opcode == OP_REGVAR) {
14807                                                 sregs [srcindex] = var->dreg;
14808                                                 //mono_inst_set_src_registers (ins, sregs);
14809                                                 live_range_end [sreg] = use_ins;
14810                                                 live_range_end_bb [sreg] = bb;
14811
14812                                                 if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14813                                                         MonoInst *tmp;
14814
14815                                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14816                                                         /* var->dreg is a hreg */
14817                                                         tmp->inst_c1 = sreg;
14818                                                         mono_bblock_insert_after_ins (bb, ins, tmp);
14819                                                 }
14820
14821                                                 continue;
14822                                         }
14823
14824                                         g_assert (var->opcode == OP_REGOFFSET);
14825                                                 
14826                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
14827
14828                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
14829
14830                                         if (vreg_to_lvreg [sreg]) {
14831                                                 g_assert (vreg_to_lvreg [sreg] != -1);
14832
14833                                                 /* The variable is already loaded to an lvreg */
14834                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14835                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
14836                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
14837                                                 //mono_inst_set_src_registers (ins, sregs);
14838                                                 continue;
14839                                         }
14840
14841                                         /* Try to fuse the load into the instruction */
14842                                         if ((srcindex == 0) && (op_to_op_src1_membase (cfg, load_opcode, ins->opcode) != -1)) {
14843                                                 ins->opcode = op_to_op_src1_membase (cfg, load_opcode, ins->opcode);
14844                                                 sregs [0] = var->inst_basereg;
14845                                                 //mono_inst_set_src_registers (ins, sregs);
14846                                                 ins->inst_offset = var->inst_offset;
14847                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (cfg, load_opcode, ins->opcode) != -1)) {
14848                                                 ins->opcode = op_to_op_src2_membase (cfg, load_opcode, ins->opcode);
14849                                                 sregs [1] = var->inst_basereg;
14850                                                 //mono_inst_set_src_registers (ins, sregs);
14851                                                 ins->inst_offset = var->inst_offset;
14852                                         } else {
14853                                                 if (MONO_IS_REAL_MOVE (ins)) {
14854                                                         ins->opcode = OP_NOP;
14855                                                         sreg = ins->dreg;
14856                                                 } else {
14857                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
14858
14859                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
14860
14861                                                         if ((!cfg->backend->use_fpstack || ((load_opcode != OP_LOADR8_MEMBASE) && (load_opcode != OP_LOADR4_MEMBASE))) && !((var)->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT)) && !no_lvreg) {
14862                                                                 if (var->dreg == prev_dreg) {
14863                                                                         /*
14864                                                                          * sreg refers to the value loaded by the load
14865                                                                          * emitted below, but we need to use ins->dreg
14866                                                                          * since it refers to the store emitted earlier.
14867                                                                          */
14868                                                                         sreg = ins->dreg;
14869                                                                 }
14870                                                                 g_assert (sreg != -1);
14871                                                                 vreg_to_lvreg [var->dreg] = sreg;
14872                                                                 g_assert (lvregs_len < 1024);
14873                                                                 lvregs [lvregs_len ++] = var->dreg;
14874                                                         }
14875                                                 }
14876
14877                                                 sregs [srcindex] = sreg;
14878                                                 //mono_inst_set_src_registers (ins, sregs);
14879
14880 #if SIZEOF_REGISTER != 8
14881                                                 if (regtype == 'l') {
14882                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, MONO_LVREG_MS (sreg), var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
14883                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14884                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, MONO_LVREG_LS (sreg), var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
14885                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14886                                                         use_ins = load_ins;
14887                                                 }
14888                                                 else
14889 #endif
14890                                                 {
14891 #if SIZEOF_REGISTER == 4
14892                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
14893 #endif
14894                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
14895                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14896                                                         use_ins = load_ins;
14897                                                 }
14898                                         }
14899
14900                                         if (var->dreg < orig_next_vreg) {
14901                                                 live_range_end [var->dreg] = use_ins;
14902                                                 live_range_end_bb [var->dreg] = bb;
14903                                         }
14904
14905                                         if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14906                                                 MonoInst *tmp;
14907
14908                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14909                                                 tmp->inst_c1 = var->dreg;
14910                                                 mono_bblock_insert_after_ins (bb, ins, tmp);
14911                                         }
14912                                 }
14913                         }
14914                         mono_inst_set_src_registers (ins, sregs);
14915
14916                         if (dest_has_lvreg) {
14917                                 g_assert (ins->dreg != -1);
14918                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
14919                                 g_assert (lvregs_len < 1024);
14920                                 lvregs [lvregs_len ++] = prev_dreg;
14921                                 dest_has_lvreg = FALSE;
14922                         }
14923
14924                         if (store) {
14925                                 tmp_reg = ins->dreg;
14926                                 ins->dreg = ins->sreg2;
14927                                 ins->sreg2 = tmp_reg;
14928                         }
14929
14930                         if (MONO_IS_CALL (ins)) {
14931                                 /* Clear vreg_to_lvreg array */
14932                                 for (i = 0; i < lvregs_len; i++)
14933                                         vreg_to_lvreg [lvregs [i]] = 0;
14934                                 lvregs_len = 0;
14935                         } else if (ins->opcode == OP_NOP) {
14936                                 ins->dreg = -1;
14937                                 MONO_INST_NULLIFY_SREGS (ins);
14938                         }
14939
14940                         if (cfg->verbose_level > 2)
14941                                 mono_print_ins_index (1, ins);
14942                 }
14943
14944                 /* Extend the live range based on the liveness info */
14945                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
14946                         for (i = 0; i < cfg->num_varinfo; i ++) {
14947                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
14948
14949                                 if (vreg_is_volatile (cfg, vi->vreg))
14950                                         /* The liveness info is incomplete */
14951                                         continue;
14952
14953                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
14954                                         /* Live from at least the first ins of this bb */
14955                                         live_range_start [vi->vreg] = bb->code;
14956                                         live_range_start_bb [vi->vreg] = bb;
14957                                 }
14958
14959                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
14960                                         /* Live at least until the last ins of this bb */
14961                                         live_range_end [vi->vreg] = bb->last_ins;
14962                                         live_range_end_bb [vi->vreg] = bb;
14963                                 }
14964                         }
14965                 }
14966         }
14967         
14968         /*
14969          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
14970          * by storing the current native offset into MonoMethodVar->live_range_start/end.
14971          */
14972         if (cfg->backend->have_liverange_ops && cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
14973                 for (i = 0; i < cfg->num_varinfo; ++i) {
14974                         int vreg = MONO_VARINFO (cfg, i)->vreg;
14975                         MonoInst *ins;
14976
14977                         if (live_range_start [vreg]) {
14978                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
14979                                 ins->inst_c0 = i;
14980                                 ins->inst_c1 = vreg;
14981                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
14982                         }
14983                         if (live_range_end [vreg]) {
14984                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
14985                                 ins->inst_c0 = i;
14986                                 ins->inst_c1 = vreg;
14987                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
14988                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
14989                                 else
14990                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
14991                         }
14992                 }
14993         }
14994
14995         if (cfg->gsharedvt_locals_var_ins) {
14996                 /* Nullify if unused */
14997                 cfg->gsharedvt_locals_var_ins->opcode = OP_PCONST;
14998                 cfg->gsharedvt_locals_var_ins->inst_imm = 0;
14999         }
15000
15001         g_free (live_range_start);
15002         g_free (live_range_end);
15003         g_free (live_range_start_bb);
15004         g_free (live_range_end_bb);
15005 }
15006
15007 /**
15008  * FIXME:
15009  * - use 'iadd' instead of 'int_add'
15010  * - handling ovf opcodes: decompose in method_to_ir.
15011  * - unify iregs/fregs
15012  *   -> partly done, the missing parts are:
15013  *   - a more complete unification would involve unifying the hregs as well, so
15014  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
15015  *     would no longer map to the machine hregs, so the code generators would need to
15016  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
15017  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
15018  *     fp/non-fp branches speeds it up by about 15%.
15019  * - use sext/zext opcodes instead of shifts
15020  * - add OP_ICALL
15021  * - get rid of TEMPLOADs if possible and use vregs instead
15022  * - clean up usage of OP_P/OP_ opcodes
15023  * - cleanup usage of DUMMY_USE
15024  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
15025  *   stack
15026  * - set the stack type and allocate a dreg in the EMIT_NEW macros
15027  * - get rid of all the <foo>2 stuff when the new JIT is ready.
15028  * - make sure handle_stack_args () is called before the branch is emitted
15029  * - when the new IR is done, get rid of all unused stuff
15030  * - COMPARE/BEQ as separate instructions or unify them ?
15031  *   - keeping them separate allows specialized compare instructions like
15032  *     compare_imm, compare_membase
15033  *   - most back ends unify fp compare+branch, fp compare+ceq
15034  * - integrate mono_save_args into inline_method
15035  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
15036  * - handle long shift opts on 32 bit platforms somehow: they require 
15037  *   3 sregs (2 for arg1 and 1 for arg2)
15038  * - make byref a 'normal' type.
15039  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
15040  *   variable if needed.
15041  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
15042  *   like inline_method.
15043  * - remove inlining restrictions
15044  * - fix LNEG and enable cfold of INEG
15045  * - generalize x86 optimizations like ldelema as a peephole optimization
15046  * - add store_mem_imm for amd64
15047  * - optimize the loading of the interruption flag in the managed->native wrappers
15048  * - avoid special handling of OP_NOP in passes
15049  * - move code inserting instructions into one function/macro.
15050  * - try a coalescing phase after liveness analysis
15051  * - add float -> vreg conversion + local optimizations on !x86
15052  * - figure out how to handle decomposed branches during optimizations, ie.
15053  *   compare+branch, op_jump_table+op_br etc.
15054  * - promote RuntimeXHandles to vregs
15055  * - vtype cleanups:
15056  *   - add a NEW_VARLOADA_VREG macro
15057  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
15058  *   accessing vtype fields.
15059  * - get rid of I8CONST on 64 bit platforms
15060  * - dealing with the increase in code size due to branches created during opcode
15061  *   decomposition:
15062  *   - use extended basic blocks
15063  *     - all parts of the JIT
15064  *     - handle_global_vregs () && local regalloc
15065  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
15066  * - sources of increase in code size:
15067  *   - vtypes
15068  *   - long compares
15069  *   - isinst and castclass
15070  *   - lvregs not allocated to global registers even if used multiple times
15071  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
15072  *   meaningful.
15073  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
15074  * - add all micro optimizations from the old JIT
15075  * - put tree optimizations into the deadce pass
15076  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
15077  *   specific function.
15078  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
15079  *   fcompare + branchCC.
15080  * - create a helper function for allocating a stack slot, taking into account 
15081  *   MONO_CFG_HAS_SPILLUP.
15082  * - merge r68207.
15083  * - merge the ia64 switch changes.
15084  * - optimize mono_regstate2_alloc_int/float.
15085  * - fix the pessimistic handling of variables accessed in exception handler blocks.
15086  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
15087  *   parts of the tree could be separated by other instructions, killing the tree
15088  *   arguments, or stores killing loads etc. Also, should we fold loads into other
15089  *   instructions if the result of the load is used multiple times ?
15090  * - make the REM_IMM optimization in mini-x86.c arch-independent.
15091  * - LAST MERGE: 108395.
15092  * - when returning vtypes in registers, generate IR and append it to the end of the
15093  *   last bb instead of doing it in the epilog.
15094  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
15095  */
15096
15097 /*
15098
15099 NOTES
15100 -----
15101
15102 - When to decompose opcodes:
15103   - earlier: this makes some optimizations hard to implement, since the low level IR
15104   no longer contains the neccessary information. But it is easier to do.
15105   - later: harder to implement, enables more optimizations.
15106 - Branches inside bblocks:
15107   - created when decomposing complex opcodes. 
15108     - branches to another bblock: harmless, but not tracked by the branch 
15109       optimizations, so need to branch to a label at the start of the bblock.
15110     - branches to inside the same bblock: very problematic, trips up the local
15111       reg allocator. Can be fixed by spitting the current bblock, but that is a
15112       complex operation, since some local vregs can become global vregs etc.
15113 - Local/global vregs:
15114   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
15115     local register allocator.
15116   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
15117     structure, created by mono_create_var (). Assigned to hregs or the stack by
15118     the global register allocator.
15119 - When to do optimizations like alu->alu_imm:
15120   - earlier -> saves work later on since the IR will be smaller/simpler
15121   - later -> can work on more instructions
15122 - Handling of valuetypes:
15123   - When a vtype is pushed on the stack, a new temporary is created, an 
15124     instruction computing its address (LDADDR) is emitted and pushed on
15125     the stack. Need to optimize cases when the vtype is used immediately as in
15126     argument passing, stloc etc.
15127 - Instead of the to_end stuff in the old JIT, simply call the function handling
15128   the values on the stack before emitting the last instruction of the bb.
15129 */
15130
15131 #endif /* DISABLE_JIT */