Merge pull request #2625 from xmcclure/tinymemoryleak
[mono.git] / mono / mini / method-to-ir.c
1 /*
2  * method-to-ir.c: Convert CIL to the JIT internal representation
3  *
4  * Author:
5  *   Paolo Molaro (lupus@ximian.com)
6  *   Dietmar Maurer (dietmar@ximian.com)
7  *
8  * (C) 2002 Ximian, Inc.
9  * Copyright 2003-2010 Novell, Inc (http://www.novell.com)
10  * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
11  */
12
13 #include <config.h>
14
15 #ifndef DISABLE_JIT
16
17 #include <signal.h>
18
19 #ifdef HAVE_UNISTD_H
20 #include <unistd.h>
21 #endif
22
23 #include <math.h>
24 #include <string.h>
25 #include <ctype.h>
26
27 #ifdef HAVE_SYS_TIME_H
28 #include <sys/time.h>
29 #endif
30
31 #ifdef HAVE_ALLOCA_H
32 #include <alloca.h>
33 #endif
34
35 #include <mono/utils/memcheck.h>
36 #include "mini.h"
37 #include <mono/metadata/abi-details.h>
38 #include <mono/metadata/assembly.h>
39 #include <mono/metadata/attrdefs.h>
40 #include <mono/metadata/loader.h>
41 #include <mono/metadata/tabledefs.h>
42 #include <mono/metadata/class.h>
43 #include <mono/metadata/object.h>
44 #include <mono/metadata/exception.h>
45 #include <mono/metadata/opcodes.h>
46 #include <mono/metadata/mono-endian.h>
47 #include <mono/metadata/tokentype.h>
48 #include <mono/metadata/tabledefs.h>
49 #include <mono/metadata/marshal.h>
50 #include <mono/metadata/debug-helpers.h>
51 #include <mono/metadata/mono-debug.h>
52 #include <mono/metadata/mono-debug-debugger.h>
53 #include <mono/metadata/gc-internals.h>
54 #include <mono/metadata/security-manager.h>
55 #include <mono/metadata/threads-types.h>
56 #include <mono/metadata/security-core-clr.h>
57 #include <mono/metadata/profiler-private.h>
58 #include <mono/metadata/profiler.h>
59 #include <mono/metadata/monitor.h>
60 #include <mono/metadata/debug-mono-symfile.h>
61 #include <mono/utils/mono-compiler.h>
62 #include <mono/utils/mono-memory-model.h>
63 #include <mono/metadata/mono-basic-block.h>
64 #include <mono/metadata/reflection-internals.h>
65
66 #include "trace.h"
67
68 #include "ir-emit.h"
69
70 #include "jit-icalls.h"
71 #include "jit.h"
72 #include "debugger-agent.h"
73 #include "seq-points.h"
74 #include "aot-compiler.h"
75 #include "mini-llvm.h"
76
77 #define BRANCH_COST 10
78 #define INLINE_LENGTH_LIMIT 20
79
80 /* These have 'cfg' as an implicit argument */
81 #define INLINE_FAILURE(msg) do {                                                                        \
82         if ((cfg->method != cfg->current_method) && (cfg->current_method->wrapper_type == MONO_WRAPPER_NONE)) { \
83                 inline_failure (cfg, msg);                                                                              \
84                 goto exception_exit;                                                                                    \
85         } \
86         } while (0)
87 #define CHECK_CFG_EXCEPTION do {\
88                 if (cfg->exception_type != MONO_EXCEPTION_NONE) \
89                         goto exception_exit;                                            \
90         } while (0)
91 #define METHOD_ACCESS_FAILURE(method, cmethod) do {                     \
92                 method_access_failure ((cfg), (method), (cmethod));                     \
93                 goto exception_exit;                                                                            \
94         } while (0)
95 #define FIELD_ACCESS_FAILURE(method, field) do {                                        \
96                 field_access_failure ((cfg), (method), (field));                        \
97                 goto exception_exit;    \
98         } while (0)
99 #define GENERIC_SHARING_FAILURE(opcode) do {            \
100                 if (cfg->gshared) {                                                                     \
101                         gshared_failure (cfg, opcode, __FILE__, __LINE__);      \
102                         goto exception_exit;    \
103                 }                       \
104         } while (0)
105 #define GSHAREDVT_FAILURE(opcode) do {          \
106         if (cfg->gsharedvt) {                                                                                           \
107                 gsharedvt_failure (cfg, opcode, __FILE__, __LINE__);                    \
108                 goto exception_exit;                                                                                    \
109         }                                                                                                                                       \
110         } while (0)
111 #define OUT_OF_MEMORY_FAILURE do {      \
112                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);                \
113                 mono_error_set_out_of_memory (&cfg->error, "");                                 \
114                 goto exception_exit;    \
115         } while (0)
116 #define DISABLE_AOT(cfg) do { \
117                 if ((cfg)->verbose_level >= 2)                                            \
118                         printf ("AOT disabled: %s:%d\n", __FILE__, __LINE__);   \
119                 (cfg)->disable_aot = TRUE;                                                        \
120         } while (0)
121 #define LOAD_ERROR do { \
122                 break_on_unverified ();                                                         \
123                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD); \
124                 goto exception_exit;                                                                    \
125         } while (0)
126
127 #define TYPE_LOAD_ERROR(klass) do { \
128                 cfg->exception_ptr = klass; \
129                 LOAD_ERROR;                                     \
130         } while (0)
131
132 #define CHECK_CFG_ERROR do {\
133                 if (!mono_error_ok (&cfg->error)) { \
134                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);        \
135                         goto mono_error_exit; \
136                 } \
137         } while (0)
138
139 /* Determine whenever 'ins' represents a load of the 'this' argument */
140 #define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && ((ins)->opcode == OP_MOVE) && ((ins)->sreg1 == cfg->args [0]->dreg))
141
142 static int ldind_to_load_membase (int opcode);
143 static int stind_to_store_membase (int opcode);
144
145 int mono_op_to_op_imm (int opcode);
146 int mono_op_to_op_imm_noemul (int opcode);
147
148 MONO_API MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
149
150 static int inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
151                                                   guchar *ip, guint real_offset, gboolean inline_always);
152 static MonoInst*
153 emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used, MonoInst **sp);
154
155 /* helper methods signatures */
156 static MonoMethodSignature *helper_sig_domain_get;
157 static MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline;
158 static MonoMethodSignature *helper_sig_llvmonly_imt_thunk;
159
160
161 /* type loading helpers */
162 static GENERATE_GET_CLASS_WITH_CACHE (runtime_helpers, System.Runtime.CompilerServices, RuntimeHelpers)
163
164 /*
165  * Instruction metadata
166  */
167 #ifdef MINI_OP
168 #undef MINI_OP
169 #endif
170 #ifdef MINI_OP3
171 #undef MINI_OP3
172 #endif
173 #define MINI_OP(a,b,dest,src1,src2) dest, src1, src2, ' ',
174 #define MINI_OP3(a,b,dest,src1,src2,src3) dest, src1, src2, src3,
175 #define NONE ' '
176 #define IREG 'i'
177 #define FREG 'f'
178 #define VREG 'v'
179 #define XREG 'x'
180 #if SIZEOF_REGISTER == 8 && SIZEOF_REGISTER == SIZEOF_VOID_P
181 #define LREG IREG
182 #else
183 #define LREG 'l'
184 #endif
185 /* keep in sync with the enum in mini.h */
186 const char
187 ins_info[] = {
188 #include "mini-ops.h"
189 };
190 #undef MINI_OP
191 #undef MINI_OP3
192
193 #define MINI_OP(a,b,dest,src1,src2) ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0)),
194 #define MINI_OP3(a,b,dest,src1,src2,src3) ((src3) != NONE ? 3 : ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0))),
195 /* 
196  * This should contain the index of the last sreg + 1. This is not the same
197  * as the number of sregs for opcodes like IA64_CMP_EQ_IMM.
198  */
199 const gint8 ins_sreg_counts[] = {
200 #include "mini-ops.h"
201 };
202 #undef MINI_OP
203 #undef MINI_OP3
204
205 #define MONO_INIT_VARINFO(vi,id) do { \
206         (vi)->range.first_use.pos.bid = 0xffff; \
207         (vi)->reg = -1; \
208         (vi)->idx = (id); \
209 } while (0)
210
211 guint32
212 mono_alloc_ireg (MonoCompile *cfg)
213 {
214         return alloc_ireg (cfg);
215 }
216
217 guint32
218 mono_alloc_lreg (MonoCompile *cfg)
219 {
220         return alloc_lreg (cfg);
221 }
222
223 guint32
224 mono_alloc_freg (MonoCompile *cfg)
225 {
226         return alloc_freg (cfg);
227 }
228
229 guint32
230 mono_alloc_preg (MonoCompile *cfg)
231 {
232         return alloc_preg (cfg);
233 }
234
235 guint32
236 mono_alloc_dreg (MonoCompile *cfg, MonoStackType stack_type)
237 {
238         return alloc_dreg (cfg, stack_type);
239 }
240
241 /*
242  * mono_alloc_ireg_ref:
243  *
244  *   Allocate an IREG, and mark it as holding a GC ref.
245  */
246 guint32
247 mono_alloc_ireg_ref (MonoCompile *cfg)
248 {
249         return alloc_ireg_ref (cfg);
250 }
251
252 /*
253  * mono_alloc_ireg_mp:
254  *
255  *   Allocate an IREG, and mark it as holding a managed pointer.
256  */
257 guint32
258 mono_alloc_ireg_mp (MonoCompile *cfg)
259 {
260         return alloc_ireg_mp (cfg);
261 }
262
263 /*
264  * mono_alloc_ireg_copy:
265  *
266  *   Allocate an IREG with the same GC type as VREG.
267  */
268 guint32
269 mono_alloc_ireg_copy (MonoCompile *cfg, guint32 vreg)
270 {
271         if (vreg_is_ref (cfg, vreg))
272                 return alloc_ireg_ref (cfg);
273         else if (vreg_is_mp (cfg, vreg))
274                 return alloc_ireg_mp (cfg);
275         else
276                 return alloc_ireg (cfg);
277 }
278
279 guint
280 mono_type_to_regmove (MonoCompile *cfg, MonoType *type)
281 {
282         if (type->byref)
283                 return OP_MOVE;
284
285         type = mini_get_underlying_type (type);
286 handle_enum:
287         switch (type->type) {
288         case MONO_TYPE_I1:
289         case MONO_TYPE_U1:
290                 return OP_MOVE;
291         case MONO_TYPE_I2:
292         case MONO_TYPE_U2:
293                 return OP_MOVE;
294         case MONO_TYPE_I4:
295         case MONO_TYPE_U4:
296                 return OP_MOVE;
297         case MONO_TYPE_I:
298         case MONO_TYPE_U:
299         case MONO_TYPE_PTR:
300         case MONO_TYPE_FNPTR:
301                 return OP_MOVE;
302         case MONO_TYPE_CLASS:
303         case MONO_TYPE_STRING:
304         case MONO_TYPE_OBJECT:
305         case MONO_TYPE_SZARRAY:
306         case MONO_TYPE_ARRAY:    
307                 return OP_MOVE;
308         case MONO_TYPE_I8:
309         case MONO_TYPE_U8:
310 #if SIZEOF_REGISTER == 8
311                 return OP_MOVE;
312 #else
313                 return OP_LMOVE;
314 #endif
315         case MONO_TYPE_R4:
316                 return cfg->r4fp ? OP_RMOVE : OP_FMOVE;
317         case MONO_TYPE_R8:
318                 return OP_FMOVE;
319         case MONO_TYPE_VALUETYPE:
320                 if (type->data.klass->enumtype) {
321                         type = mono_class_enum_basetype (type->data.klass);
322                         goto handle_enum;
323                 }
324                 if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
325                         return OP_XMOVE;
326                 return OP_VMOVE;
327         case MONO_TYPE_TYPEDBYREF:
328                 return OP_VMOVE;
329         case MONO_TYPE_GENERICINST:
330                 type = &type->data.generic_class->container_class->byval_arg;
331                 goto handle_enum;
332         case MONO_TYPE_VAR:
333         case MONO_TYPE_MVAR:
334                 g_assert (cfg->gshared);
335                 if (mini_type_var_is_vt (type))
336                         return OP_VMOVE;
337                 else
338                         return mono_type_to_regmove (cfg, mini_get_underlying_type (type));
339         default:
340                 g_error ("unknown type 0x%02x in type_to_regstore", type->type);
341         }
342         return -1;
343 }
344
345 void
346 mono_print_bb (MonoBasicBlock *bb, const char *msg)
347 {
348         int i;
349         MonoInst *tree;
350
351         printf ("\n%s %d: [IN: ", msg, bb->block_num);
352         for (i = 0; i < bb->in_count; ++i)
353                 printf (" BB%d(%d)", bb->in_bb [i]->block_num, bb->in_bb [i]->dfn);
354         printf (", OUT: ");
355         for (i = 0; i < bb->out_count; ++i)
356                 printf (" BB%d(%d)", bb->out_bb [i]->block_num, bb->out_bb [i]->dfn);
357         printf (" ]\n");
358         for (tree = bb->code; tree; tree = tree->next)
359                 mono_print_ins_index (-1, tree);
360 }
361
362 void
363 mono_create_helper_signatures (void)
364 {
365         helper_sig_domain_get = mono_create_icall_signature ("ptr");
366         helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
367         helper_sig_llvmonly_imt_thunk = mono_create_icall_signature ("ptr ptr ptr");
368 }
369
370 static MONO_NEVER_INLINE void
371 break_on_unverified (void)
372 {
373         if (mini_get_debug_options ()->break_on_unverified)
374                 G_BREAKPOINT ();
375 }
376
377 static MONO_NEVER_INLINE void
378 method_access_failure (MonoCompile *cfg, MonoMethod *method, MonoMethod *cil_method)
379 {
380         char *method_fname = mono_method_full_name (method, TRUE);
381         char *cil_method_fname = mono_method_full_name (cil_method, TRUE);
382         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
383         mono_error_set_generic_error (&cfg->error, "System", "MethodAccessException", "Method `%s' is inaccessible from method `%s'\n", cil_method_fname, method_fname);
384         g_free (method_fname);
385         g_free (cil_method_fname);
386 }
387
388 static MONO_NEVER_INLINE void
389 field_access_failure (MonoCompile *cfg, MonoMethod *method, MonoClassField *field)
390 {
391         char *method_fname = mono_method_full_name (method, TRUE);
392         char *field_fname = mono_field_full_name (field);
393         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
394         mono_error_set_generic_error (&cfg->error, "System", "FieldAccessException", "Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname);
395         g_free (method_fname);
396         g_free (field_fname);
397 }
398
399 static MONO_NEVER_INLINE void
400 inline_failure (MonoCompile *cfg, const char *msg)
401 {
402         if (cfg->verbose_level >= 2)
403                 printf ("inline failed: %s\n", msg);
404         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INLINE_FAILED);
405 }
406
407 static MONO_NEVER_INLINE void
408 gshared_failure (MonoCompile *cfg, int opcode, const char *file, int line)
409 {
410         if (cfg->verbose_level > 2)                                                                                     \
411                 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);
412         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
413 }
414
415 static MONO_NEVER_INLINE void
416 gsharedvt_failure (MonoCompile *cfg, int opcode, const char *file, int line)
417 {
418         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);
419         if (cfg->verbose_level >= 2)
420                 printf ("%s\n", cfg->exception_message);
421         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
422 }
423
424 /*
425  * When using gsharedvt, some instatiations might be verifiable, and some might be not. i.e. 
426  * foo<T> (int i) { ldarg.0; box T; }
427  */
428 #define UNVERIFIED do { \
429         if (cfg->gsharedvt) { \
430                 if (cfg->verbose_level > 2)                                                                     \
431                         printf ("gsharedvt method failed to verify, falling back to instantiation.\n"); \
432                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED); \
433                 goto exception_exit;                                                                                    \
434         }                                                                                                                                       \
435         break_on_unverified ();                                                                                         \
436         goto unverified;                                                                                                        \
437 } while (0)
438
439 #define GET_BBLOCK(cfg,tblock,ip) do {  \
440                 (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
441                 if (!(tblock)) {        \
442                         if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
443             NEW_BBLOCK (cfg, (tblock)); \
444                         (tblock)->cil_code = (ip);      \
445                         ADD_BBLOCK (cfg, (tblock));     \
446                 } \
447         } while (0)
448
449 #if defined(TARGET_X86) || defined(TARGET_AMD64)
450 #define EMIT_NEW_X86_LEA(cfg,dest,sr1,sr2,shift,imm) do { \
451                 MONO_INST_NEW (cfg, dest, OP_X86_LEA); \
452                 (dest)->dreg = alloc_ireg_mp ((cfg)); \
453                 (dest)->sreg1 = (sr1); \
454                 (dest)->sreg2 = (sr2); \
455                 (dest)->inst_imm = (imm); \
456                 (dest)->backend.shift_amount = (shift); \
457                 MONO_ADD_INS ((cfg)->cbb, (dest)); \
458         } while (0)
459 #endif
460
461 /* Emit conversions so both operands of a binary opcode are of the same type */
462 static void
463 add_widen_op (MonoCompile *cfg, MonoInst *ins, MonoInst **arg1_ref, MonoInst **arg2_ref)
464 {
465         MonoInst *arg1 = *arg1_ref;
466         MonoInst *arg2 = *arg2_ref;
467
468         if (cfg->r4fp &&
469                 ((arg1->type == STACK_R4 && arg2->type == STACK_R8) ||
470                  (arg1->type == STACK_R8 && arg2->type == STACK_R4))) {
471                 MonoInst *conv;
472
473                 /* Mixing r4/r8 is allowed by the spec */
474                 if (arg1->type == STACK_R4) {
475                         int dreg = alloc_freg (cfg);
476
477                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg1->dreg);
478                         conv->type = STACK_R8;
479                         ins->sreg1 = dreg;
480                         *arg1_ref = conv;
481                 }
482                 if (arg2->type == STACK_R4) {
483                         int dreg = alloc_freg (cfg);
484
485                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg2->dreg);
486                         conv->type = STACK_R8;
487                         ins->sreg2 = dreg;
488                         *arg2_ref = conv;
489                 }
490         }
491
492 #if SIZEOF_REGISTER == 8
493         /* FIXME: Need to add many more cases */
494         if ((arg1)->type == STACK_PTR && (arg2)->type == STACK_I4) {
495                 MonoInst *widen;
496
497                 int dr = alloc_preg (cfg);
498                 EMIT_NEW_UNALU (cfg, widen, OP_SEXT_I4, dr, (arg2)->dreg);
499                 (ins)->sreg2 = widen->dreg;
500         }
501 #endif
502 }
503
504 #define ADD_BINOP(op) do {      \
505                 MONO_INST_NEW (cfg, ins, (op)); \
506                 sp -= 2;        \
507                 ins->sreg1 = sp [0]->dreg;      \
508                 ins->sreg2 = sp [1]->dreg;      \
509                 type_from_op (cfg, ins, sp [0], sp [1]);        \
510                 CHECK_TYPE (ins);       \
511                 /* Have to insert a widening op */               \
512         add_widen_op (cfg, ins, &sp [0], &sp [1]);               \
513         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type); \
514         MONO_ADD_INS ((cfg)->cbb, (ins)); \
515         *sp++ = mono_decompose_opcode ((cfg), (ins));   \
516         } while (0)
517
518 #define ADD_UNOP(op) do {       \
519                 MONO_INST_NEW (cfg, ins, (op)); \
520                 sp--;   \
521                 ins->sreg1 = sp [0]->dreg;      \
522                 type_from_op (cfg, ins, sp [0], NULL);  \
523                 CHECK_TYPE (ins);       \
524         (ins)->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type); \
525         MONO_ADD_INS ((cfg)->cbb, (ins)); \
526                 *sp++ = mono_decompose_opcode (cfg, ins);       \
527         } while (0)
528
529 #define ADD_BINCOND(next_block) do {    \
530                 MonoInst *cmp;  \
531                 sp -= 2; \
532                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
533                 cmp->sreg1 = sp [0]->dreg;      \
534                 cmp->sreg2 = sp [1]->dreg;      \
535                 type_from_op (cfg, cmp, sp [0], sp [1]);        \
536                 CHECK_TYPE (cmp);       \
537                 add_widen_op (cfg, cmp, &sp [0], &sp [1]);                                              \
538                 type_from_op (cfg, ins, sp [0], sp [1]);                                                        \
539                 ins->inst_many_bb = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);   \
540                 GET_BBLOCK (cfg, tblock, target);               \
541                 link_bblock (cfg, cfg->cbb, tblock);    \
542                 ins->inst_true_bb = tblock;     \
543                 if ((next_block)) {     \
544                         link_bblock (cfg, cfg->cbb, (next_block));      \
545                         ins->inst_false_bb = (next_block);      \
546                         start_new_bblock = 1;   \
547                 } else {        \
548                         GET_BBLOCK (cfg, tblock, ip);           \
549                         link_bblock (cfg, cfg->cbb, tblock);    \
550                         ins->inst_false_bb = tblock;    \
551                         start_new_bblock = 2;   \
552                 }       \
553                 if (sp != stack_start) {                                                                        \
554                     handle_stack_args (cfg, stack_start, sp - stack_start); \
555                         CHECK_UNVERIFIABLE (cfg); \
556                 } \
557         MONO_ADD_INS (cfg->cbb, cmp); \
558                 MONO_ADD_INS (cfg->cbb, ins);   \
559         } while (0)
560
561 /* *
562  * link_bblock: Links two basic blocks
563  *
564  * links two basic blocks in the control flow graph, the 'from'
565  * argument is the starting block and the 'to' argument is the block
566  * the control flow ends to after 'from'.
567  */
568 static void
569 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
570 {
571         MonoBasicBlock **newa;
572         int i, found;
573
574 #if 0
575         if (from->cil_code) {
576                 if (to->cil_code)
577                         printf ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
578                 else
579                         printf ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
580         } else {
581                 if (to->cil_code)
582                         printf ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
583                 else
584                         printf ("edge from entry to exit\n");
585         }
586 #endif
587
588         found = FALSE;
589         for (i = 0; i < from->out_count; ++i) {
590                 if (to == from->out_bb [i]) {
591                         found = TRUE;
592                         break;
593                 }
594         }
595         if (!found) {
596                 newa = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
597                 for (i = 0; i < from->out_count; ++i) {
598                         newa [i] = from->out_bb [i];
599                 }
600                 newa [i] = to;
601                 from->out_count++;
602                 from->out_bb = newa;
603         }
604
605         found = FALSE;
606         for (i = 0; i < to->in_count; ++i) {
607                 if (from == to->in_bb [i]) {
608                         found = TRUE;
609                         break;
610                 }
611         }
612         if (!found) {
613                 newa = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
614                 for (i = 0; i < to->in_count; ++i) {
615                         newa [i] = to->in_bb [i];
616                 }
617                 newa [i] = from;
618                 to->in_count++;
619                 to->in_bb = newa;
620         }
621 }
622
623 void
624 mono_link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
625 {
626         link_bblock (cfg, from, to);
627 }
628
629 /**
630  * mono_find_block_region:
631  *
632  *   We mark each basic block with a region ID. We use that to avoid BB
633  *   optimizations when blocks are in different regions.
634  *
635  * Returns:
636  *   A region token that encodes where this region is, and information
637  *   about the clause owner for this block.
638  *
639  *   The region encodes the try/catch/filter clause that owns this block
640  *   as well as the type.  -1 is a special value that represents a block
641  *   that is in none of try/catch/filter.
642  */
643 static int
644 mono_find_block_region (MonoCompile *cfg, int offset)
645 {
646         MonoMethodHeader *header = cfg->header;
647         MonoExceptionClause *clause;
648         int i;
649
650         for (i = 0; i < header->num_clauses; ++i) {
651                 clause = &header->clauses [i];
652                 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
653                     (offset < (clause->handler_offset)))
654                         return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
655                            
656                 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
657                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
658                                 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
659                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
660                                 return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
661                         else
662                                 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
663                 }
664         }
665         for (i = 0; i < header->num_clauses; ++i) {
666                 clause = &header->clauses [i];
667
668                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
669                         return ((i + 1) << 8) | clause->flags;
670         }
671
672         return -1;
673 }
674
675 static GList*
676 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
677 {
678         MonoMethodHeader *header = cfg->header;
679         MonoExceptionClause *clause;
680         int i;
681         GList *res = NULL;
682
683         for (i = 0; i < header->num_clauses; ++i) {
684                 clause = &header->clauses [i];
685                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
686                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
687                         if (clause->flags == type)
688                                 res = g_list_append (res, clause);
689                 }
690         }
691         return res;
692 }
693
694 static void
695 mono_create_spvar_for_region (MonoCompile *cfg, int region)
696 {
697         MonoInst *var;
698
699         var = (MonoInst *)g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
700         if (var)
701                 return;
702
703         var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
704         /* prevent it from being register allocated */
705         var->flags |= MONO_INST_VOLATILE;
706
707         g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
708 }
709
710 MonoInst *
711 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
712 {
713         return (MonoInst *)g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
714 }
715
716 static MonoInst*
717 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
718 {
719         MonoInst *var;
720
721         var = (MonoInst *)g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
722         if (var)
723                 return var;
724
725         var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
726         /* prevent it from being register allocated */
727         var->flags |= MONO_INST_VOLATILE;
728
729         g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
730
731         return var;
732 }
733
734 /*
735  * Returns the type used in the eval stack when @type is loaded.
736  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
737  */
738 void
739 type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
740 {
741         MonoClass *klass;
742
743         type = mini_get_underlying_type (type);
744         inst->klass = klass = mono_class_from_mono_type (type);
745         if (type->byref) {
746                 inst->type = STACK_MP;
747                 return;
748         }
749
750 handle_enum:
751         switch (type->type) {
752         case MONO_TYPE_VOID:
753                 inst->type = STACK_INV;
754                 return;
755         case MONO_TYPE_I1:
756         case MONO_TYPE_U1:
757         case MONO_TYPE_I2:
758         case MONO_TYPE_U2:
759         case MONO_TYPE_I4:
760         case MONO_TYPE_U4:
761                 inst->type = STACK_I4;
762                 return;
763         case MONO_TYPE_I:
764         case MONO_TYPE_U:
765         case MONO_TYPE_PTR:
766         case MONO_TYPE_FNPTR:
767                 inst->type = STACK_PTR;
768                 return;
769         case MONO_TYPE_CLASS:
770         case MONO_TYPE_STRING:
771         case MONO_TYPE_OBJECT:
772         case MONO_TYPE_SZARRAY:
773         case MONO_TYPE_ARRAY:    
774                 inst->type = STACK_OBJ;
775                 return;
776         case MONO_TYPE_I8:
777         case MONO_TYPE_U8:
778                 inst->type = STACK_I8;
779                 return;
780         case MONO_TYPE_R4:
781                 inst->type = cfg->r4_stack_type;
782                 break;
783         case MONO_TYPE_R8:
784                 inst->type = STACK_R8;
785                 return;
786         case MONO_TYPE_VALUETYPE:
787                 if (type->data.klass->enumtype) {
788                         type = mono_class_enum_basetype (type->data.klass);
789                         goto handle_enum;
790                 } else {
791                         inst->klass = klass;
792                         inst->type = STACK_VTYPE;
793                         return;
794                 }
795         case MONO_TYPE_TYPEDBYREF:
796                 inst->klass = mono_defaults.typed_reference_class;
797                 inst->type = STACK_VTYPE;
798                 return;
799         case MONO_TYPE_GENERICINST:
800                 type = &type->data.generic_class->container_class->byval_arg;
801                 goto handle_enum;
802         case MONO_TYPE_VAR:
803         case MONO_TYPE_MVAR:
804                 g_assert (cfg->gshared);
805                 if (mini_is_gsharedvt_type (type)) {
806                         g_assert (cfg->gsharedvt);
807                         inst->type = STACK_VTYPE;
808                 } else {
809                         type_to_eval_stack_type (cfg, mini_get_underlying_type (type), inst);
810                 }
811                 return;
812         default:
813                 g_error ("unknown type 0x%02x in eval stack type", type->type);
814         }
815 }
816
817 /*
818  * The following tables are used to quickly validate the IL code in type_from_op ().
819  */
820 static const char
821 bin_num_table [STACK_MAX] [STACK_MAX] = {
822         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
823         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
824         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
825         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
826         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV, STACK_R8},
827         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
828         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
829         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
830         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4}
831 };
832
833 static const char 
834 neg_table [] = {
835         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4
836 };
837
838 /* reduce the size of this table */
839 static const char
840 bin_int_table [STACK_MAX] [STACK_MAX] = {
841         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
842         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
843         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
844         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
845         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
846         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
847         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
848         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
849 };
850
851 static const char
852 bin_comp_table [STACK_MAX] [STACK_MAX] = {
853 /*      Inv i  L  p  F  &  O  vt r4 */
854         {0},
855         {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
856         {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
857         {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
858         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* F, R8 */
859         {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
860         {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
861         {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
862         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* r, r4 */
863 };
864
865 /* reduce the size of this table */
866 static const char
867 shift_table [STACK_MAX] [STACK_MAX] = {
868         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
869         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
870         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
871         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
872         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
873         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
874         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
875         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
876 };
877
878 /*
879  * Tables to map from the non-specific opcode to the matching
880  * type-specific opcode.
881  */
882 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
883 static const guint16
884 binops_op_map [STACK_MAX] = {
885         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
886 };
887
888 /* handles from CEE_NEG to CEE_CONV_U8 */
889 static const guint16
890 unops_op_map [STACK_MAX] = {
891         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
892 };
893
894 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
895 static const guint16
896 ovfops_op_map [STACK_MAX] = {
897         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
898 };
899
900 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
901 static const guint16
902 ovf2ops_op_map [STACK_MAX] = {
903         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
904 };
905
906 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
907 static const guint16
908 ovf3ops_op_map [STACK_MAX] = {
909         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
910 };
911
912 /* handles from CEE_BEQ to CEE_BLT_UN */
913 static const guint16
914 beqops_op_map [STACK_MAX] = {
915         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
916 };
917
918 /* handles from CEE_CEQ to CEE_CLT_UN */
919 static const guint16
920 ceqops_op_map [STACK_MAX] = {
921         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
922 };
923
924 /*
925  * Sets ins->type (the type on the eval stack) according to the
926  * type of the opcode and the arguments to it.
927  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
928  *
929  * FIXME: this function sets ins->type unconditionally in some cases, but
930  * it should set it to invalid for some types (a conv.x on an object)
931  */
932 static void
933 type_from_op (MonoCompile *cfg, MonoInst *ins, MonoInst *src1, MonoInst *src2)
934 {
935         switch (ins->opcode) {
936         /* binops */
937         case CEE_ADD:
938         case CEE_SUB:
939         case CEE_MUL:
940         case CEE_DIV:
941         case CEE_REM:
942                 /* FIXME: check unverifiable args for STACK_MP */
943                 ins->type = bin_num_table [src1->type] [src2->type];
944                 ins->opcode += binops_op_map [ins->type];
945                 break;
946         case CEE_DIV_UN:
947         case CEE_REM_UN:
948         case CEE_AND:
949         case CEE_OR:
950         case CEE_XOR:
951                 ins->type = bin_int_table [src1->type] [src2->type];
952                 ins->opcode += binops_op_map [ins->type];
953                 break;
954         case CEE_SHL:
955         case CEE_SHR:
956         case CEE_SHR_UN:
957                 ins->type = shift_table [src1->type] [src2->type];
958                 ins->opcode += binops_op_map [ins->type];
959                 break;
960         case OP_COMPARE:
961         case OP_LCOMPARE:
962         case OP_ICOMPARE:
963                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
964                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
965                         ins->opcode = OP_LCOMPARE;
966                 else if (src1->type == STACK_R4)
967                         ins->opcode = OP_RCOMPARE;
968                 else if (src1->type == STACK_R8)
969                         ins->opcode = OP_FCOMPARE;
970                 else
971                         ins->opcode = OP_ICOMPARE;
972                 break;
973         case OP_ICOMPARE_IMM:
974                 ins->type = bin_comp_table [src1->type] [src1->type] ? STACK_I4 : STACK_INV;
975                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
976                         ins->opcode = OP_LCOMPARE_IMM;          
977                 break;
978         case CEE_BEQ:
979         case CEE_BGE:
980         case CEE_BGT:
981         case CEE_BLE:
982         case CEE_BLT:
983         case CEE_BNE_UN:
984         case CEE_BGE_UN:
985         case CEE_BGT_UN:
986         case CEE_BLE_UN:
987         case CEE_BLT_UN:
988                 ins->opcode += beqops_op_map [src1->type];
989                 break;
990         case OP_CEQ:
991                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
992                 ins->opcode += ceqops_op_map [src1->type];
993                 break;
994         case OP_CGT:
995         case OP_CGT_UN:
996         case OP_CLT:
997         case OP_CLT_UN:
998                 ins->type = (bin_comp_table [src1->type] [src2->type] & 1) ? STACK_I4: STACK_INV;
999                 ins->opcode += ceqops_op_map [src1->type];
1000                 break;
1001         /* unops */
1002         case CEE_NEG:
1003                 ins->type = neg_table [src1->type];
1004                 ins->opcode += unops_op_map [ins->type];
1005                 break;
1006         case CEE_NOT:
1007                 if (src1->type >= STACK_I4 && src1->type <= STACK_PTR)
1008                         ins->type = src1->type;
1009                 else
1010                         ins->type = STACK_INV;
1011                 ins->opcode += unops_op_map [ins->type];
1012                 break;
1013         case CEE_CONV_I1:
1014         case CEE_CONV_I2:
1015         case CEE_CONV_I4:
1016         case CEE_CONV_U4:
1017                 ins->type = STACK_I4;
1018                 ins->opcode += unops_op_map [src1->type];
1019                 break;
1020         case CEE_CONV_R_UN:
1021                 ins->type = STACK_R8;
1022                 switch (src1->type) {
1023                 case STACK_I4:
1024                 case STACK_PTR:
1025                         ins->opcode = OP_ICONV_TO_R_UN;
1026                         break;
1027                 case STACK_I8:
1028                         ins->opcode = OP_LCONV_TO_R_UN; 
1029                         break;
1030                 }
1031                 break;
1032         case CEE_CONV_OVF_I1:
1033         case CEE_CONV_OVF_U1:
1034         case CEE_CONV_OVF_I2:
1035         case CEE_CONV_OVF_U2:
1036         case CEE_CONV_OVF_I4:
1037         case CEE_CONV_OVF_U4:
1038                 ins->type = STACK_I4;
1039                 ins->opcode += ovf3ops_op_map [src1->type];
1040                 break;
1041         case CEE_CONV_OVF_I_UN:
1042         case CEE_CONV_OVF_U_UN:
1043                 ins->type = STACK_PTR;
1044                 ins->opcode += ovf2ops_op_map [src1->type];
1045                 break;
1046         case CEE_CONV_OVF_I1_UN:
1047         case CEE_CONV_OVF_I2_UN:
1048         case CEE_CONV_OVF_I4_UN:
1049         case CEE_CONV_OVF_U1_UN:
1050         case CEE_CONV_OVF_U2_UN:
1051         case CEE_CONV_OVF_U4_UN:
1052                 ins->type = STACK_I4;
1053                 ins->opcode += ovf2ops_op_map [src1->type];
1054                 break;
1055         case CEE_CONV_U:
1056                 ins->type = STACK_PTR;
1057                 switch (src1->type) {
1058                 case STACK_I4:
1059                         ins->opcode = OP_ICONV_TO_U;
1060                         break;
1061                 case STACK_PTR:
1062                 case STACK_MP:
1063 #if SIZEOF_VOID_P == 8
1064                         ins->opcode = OP_LCONV_TO_U;
1065 #else
1066                         ins->opcode = OP_MOVE;
1067 #endif
1068                         break;
1069                 case STACK_I8:
1070                         ins->opcode = OP_LCONV_TO_U;
1071                         break;
1072                 case STACK_R8:
1073                         ins->opcode = OP_FCONV_TO_U;
1074                         break;
1075                 }
1076                 break;
1077         case CEE_CONV_I8:
1078         case CEE_CONV_U8:
1079                 ins->type = STACK_I8;
1080                 ins->opcode += unops_op_map [src1->type];
1081                 break;
1082         case CEE_CONV_OVF_I8:
1083         case CEE_CONV_OVF_U8:
1084                 ins->type = STACK_I8;
1085                 ins->opcode += ovf3ops_op_map [src1->type];
1086                 break;
1087         case CEE_CONV_OVF_U8_UN:
1088         case CEE_CONV_OVF_I8_UN:
1089                 ins->type = STACK_I8;
1090                 ins->opcode += ovf2ops_op_map [src1->type];
1091                 break;
1092         case CEE_CONV_R4:
1093                 ins->type = cfg->r4_stack_type;
1094                 ins->opcode += unops_op_map [src1->type];
1095                 break;
1096         case CEE_CONV_R8:
1097                 ins->type = STACK_R8;
1098                 ins->opcode += unops_op_map [src1->type];
1099                 break;
1100         case OP_CKFINITE:
1101                 ins->type = STACK_R8;           
1102                 break;
1103         case CEE_CONV_U2:
1104         case CEE_CONV_U1:
1105                 ins->type = STACK_I4;
1106                 ins->opcode += ovfops_op_map [src1->type];
1107                 break;
1108         case CEE_CONV_I:
1109         case CEE_CONV_OVF_I:
1110         case CEE_CONV_OVF_U:
1111                 ins->type = STACK_PTR;
1112                 ins->opcode += ovfops_op_map [src1->type];
1113                 break;
1114         case CEE_ADD_OVF:
1115         case CEE_ADD_OVF_UN:
1116         case CEE_MUL_OVF:
1117         case CEE_MUL_OVF_UN:
1118         case CEE_SUB_OVF:
1119         case CEE_SUB_OVF_UN:
1120                 ins->type = bin_num_table [src1->type] [src2->type];
1121                 ins->opcode += ovfops_op_map [src1->type];
1122                 if (ins->type == STACK_R8)
1123                         ins->type = STACK_INV;
1124                 break;
1125         case OP_LOAD_MEMBASE:
1126                 ins->type = STACK_PTR;
1127                 break;
1128         case OP_LOADI1_MEMBASE:
1129         case OP_LOADU1_MEMBASE:
1130         case OP_LOADI2_MEMBASE:
1131         case OP_LOADU2_MEMBASE:
1132         case OP_LOADI4_MEMBASE:
1133         case OP_LOADU4_MEMBASE:
1134                 ins->type = STACK_PTR;
1135                 break;
1136         case OP_LOADI8_MEMBASE:
1137                 ins->type = STACK_I8;
1138                 break;
1139         case OP_LOADR4_MEMBASE:
1140                 ins->type = cfg->r4_stack_type;
1141                 break;
1142         case OP_LOADR8_MEMBASE:
1143                 ins->type = STACK_R8;
1144                 break;
1145         default:
1146                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1147                 break;
1148         }
1149
1150         if (ins->type == STACK_MP)
1151                 ins->klass = mono_defaults.object_class;
1152 }
1153
1154 static const char 
1155 ldind_type [] = {
1156         STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
1157 };
1158
1159 #if 0
1160
1161 static const char
1162 param_table [STACK_MAX] [STACK_MAX] = {
1163         {0},
1164 };
1165
1166 static int
1167 check_values_to_signature (MonoInst *args, MonoType *this_ins, MonoMethodSignature *sig)
1168 {
1169         int i;
1170
1171         if (sig->hasthis) {
1172                 switch (args->type) {
1173                 case STACK_I4:
1174                 case STACK_I8:
1175                 case STACK_R8:
1176                 case STACK_VTYPE:
1177                 case STACK_INV:
1178                         return 0;
1179                 }
1180                 args++;
1181         }
1182         for (i = 0; i < sig->param_count; ++i) {
1183                 switch (args [i].type) {
1184                 case STACK_INV:
1185                         return 0;
1186                 case STACK_MP:
1187                         if (!sig->params [i]->byref)
1188                                 return 0;
1189                         continue;
1190                 case STACK_OBJ:
1191                         if (sig->params [i]->byref)
1192                                 return 0;
1193                         switch (sig->params [i]->type) {
1194                         case MONO_TYPE_CLASS:
1195                         case MONO_TYPE_STRING:
1196                         case MONO_TYPE_OBJECT:
1197                         case MONO_TYPE_SZARRAY:
1198                         case MONO_TYPE_ARRAY:
1199                                 break;
1200                         default:
1201                                 return 0;
1202                         }
1203                         continue;
1204                 case STACK_R8:
1205                         if (sig->params [i]->byref)
1206                                 return 0;
1207                         if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1208                                 return 0;
1209                         continue;
1210                 case STACK_PTR:
1211                 case STACK_I4:
1212                 case STACK_I8:
1213                 case STACK_VTYPE:
1214                         break;
1215                 }
1216                 /*if (!param_table [args [i].type] [sig->params [i]->type])
1217                         return 0;*/
1218         }
1219         return 1;
1220 }
1221 #endif
1222
1223 /*
1224  * When we need a pointer to the current domain many times in a method, we
1225  * call mono_domain_get() once and we store the result in a local variable.
1226  * This function returns the variable that represents the MonoDomain*.
1227  */
1228 inline static MonoInst *
1229 mono_get_domainvar (MonoCompile *cfg)
1230 {
1231         if (!cfg->domainvar)
1232                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1233         return cfg->domainvar;
1234 }
1235
1236 /*
1237  * The got_var contains the address of the Global Offset Table when AOT 
1238  * compiling.
1239  */
1240 MonoInst *
1241 mono_get_got_var (MonoCompile *cfg)
1242 {
1243         if (!cfg->compile_aot || !cfg->backend->need_got_var)
1244                 return NULL;
1245         if (!cfg->got_var) {
1246                 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1247         }
1248         return cfg->got_var;
1249 }
1250
1251 static MonoInst *
1252 mono_get_vtable_var (MonoCompile *cfg)
1253 {
1254         g_assert (cfg->gshared);
1255
1256         if (!cfg->rgctx_var) {
1257                 cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1258                 /* force the var to be stack allocated */
1259                 cfg->rgctx_var->flags |= MONO_INST_VOLATILE;
1260         }
1261
1262         return cfg->rgctx_var;
1263 }
1264
1265 static MonoType*
1266 type_from_stack_type (MonoInst *ins) {
1267         switch (ins->type) {
1268         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1269         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1270         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1271         case STACK_R4: return &mono_defaults.single_class->byval_arg;
1272         case STACK_R8: return &mono_defaults.double_class->byval_arg;
1273         case STACK_MP:
1274                 return &ins->klass->this_arg;
1275         case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1276         case STACK_VTYPE: return &ins->klass->byval_arg;
1277         default:
1278                 g_error ("stack type %d to monotype not handled\n", ins->type);
1279         }
1280         return NULL;
1281 }
1282
1283 static G_GNUC_UNUSED int
1284 type_to_stack_type (MonoCompile *cfg, MonoType *t)
1285 {
1286         t = mono_type_get_underlying_type (t);
1287         switch (t->type) {
1288         case MONO_TYPE_I1:
1289         case MONO_TYPE_U1:
1290         case MONO_TYPE_I2:
1291         case MONO_TYPE_U2:
1292         case MONO_TYPE_I4:
1293         case MONO_TYPE_U4:
1294                 return STACK_I4;
1295         case MONO_TYPE_I:
1296         case MONO_TYPE_U:
1297         case MONO_TYPE_PTR:
1298         case MONO_TYPE_FNPTR:
1299                 return STACK_PTR;
1300         case MONO_TYPE_CLASS:
1301         case MONO_TYPE_STRING:
1302         case MONO_TYPE_OBJECT:
1303         case MONO_TYPE_SZARRAY:
1304         case MONO_TYPE_ARRAY:    
1305                 return STACK_OBJ;
1306         case MONO_TYPE_I8:
1307         case MONO_TYPE_U8:
1308                 return STACK_I8;
1309         case MONO_TYPE_R4:
1310                 return cfg->r4_stack_type;
1311         case MONO_TYPE_R8:
1312                 return STACK_R8;
1313         case MONO_TYPE_VALUETYPE:
1314         case MONO_TYPE_TYPEDBYREF:
1315                 return STACK_VTYPE;
1316         case MONO_TYPE_GENERICINST:
1317                 if (mono_type_generic_inst_is_valuetype (t))
1318                         return STACK_VTYPE;
1319                 else
1320                         return STACK_OBJ;
1321                 break;
1322         default:
1323                 g_assert_not_reached ();
1324         }
1325
1326         return -1;
1327 }
1328
1329 static MonoClass*
1330 array_access_to_klass (int opcode)
1331 {
1332         switch (opcode) {
1333         case CEE_LDELEM_U1:
1334                 return mono_defaults.byte_class;
1335         case CEE_LDELEM_U2:
1336                 return mono_defaults.uint16_class;
1337         case CEE_LDELEM_I:
1338         case CEE_STELEM_I:
1339                 return mono_defaults.int_class;
1340         case CEE_LDELEM_I1:
1341         case CEE_STELEM_I1:
1342                 return mono_defaults.sbyte_class;
1343         case CEE_LDELEM_I2:
1344         case CEE_STELEM_I2:
1345                 return mono_defaults.int16_class;
1346         case CEE_LDELEM_I4:
1347         case CEE_STELEM_I4:
1348                 return mono_defaults.int32_class;
1349         case CEE_LDELEM_U4:
1350                 return mono_defaults.uint32_class;
1351         case CEE_LDELEM_I8:
1352         case CEE_STELEM_I8:
1353                 return mono_defaults.int64_class;
1354         case CEE_LDELEM_R4:
1355         case CEE_STELEM_R4:
1356                 return mono_defaults.single_class;
1357         case CEE_LDELEM_R8:
1358         case CEE_STELEM_R8:
1359                 return mono_defaults.double_class;
1360         case CEE_LDELEM_REF:
1361         case CEE_STELEM_REF:
1362                 return mono_defaults.object_class;
1363         default:
1364                 g_assert_not_reached ();
1365         }
1366         return NULL;
1367 }
1368
1369 /*
1370  * We try to share variables when possible
1371  */
1372 static MonoInst *
1373 mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
1374 {
1375         MonoInst *res;
1376         int pos, vnum;
1377
1378         /* inlining can result in deeper stacks */ 
1379         if (slot >= cfg->header->max_stack)
1380                 return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1381
1382         pos = ins->type - 1 + slot * STACK_MAX;
1383
1384         switch (ins->type) {
1385         case STACK_I4:
1386         case STACK_I8:
1387         case STACK_R8:
1388         case STACK_PTR:
1389         case STACK_MP:
1390         case STACK_OBJ:
1391                 if ((vnum = cfg->intvars [pos]))
1392                         return cfg->varinfo [vnum];
1393                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1394                 cfg->intvars [pos] = res->inst_c0;
1395                 break;
1396         default:
1397                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1398         }
1399         return res;
1400 }
1401
1402 static void
1403 mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
1404 {
1405         /* 
1406          * Don't use this if a generic_context is set, since that means AOT can't
1407          * look up the method using just the image+token.
1408          * table == 0 means this is a reference made from a wrapper.
1409          */
1410         if (cfg->compile_aot && !cfg->generic_context && (mono_metadata_token_table (token) > 0)) {
1411                 MonoJumpInfoToken *jump_info_token = (MonoJumpInfoToken *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
1412                 jump_info_token->image = image;
1413                 jump_info_token->token = token;
1414                 g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
1415         }
1416 }
1417
1418 /*
1419  * This function is called to handle items that are left on the evaluation stack
1420  * at basic block boundaries. What happens is that we save the values to local variables
1421  * and we reload them later when first entering the target basic block (with the
1422  * handle_loaded_temps () function).
1423  * A single joint point will use the same variables (stored in the array bb->out_stack or
1424  * bb->in_stack, if the basic block is before or after the joint point).
1425  *
1426  * This function needs to be called _before_ emitting the last instruction of
1427  * the bb (i.e. before emitting a branch).
1428  * If the stack merge fails at a join point, cfg->unverifiable is set.
1429  */
1430 static void
1431 handle_stack_args (MonoCompile *cfg, MonoInst **sp, int count)
1432 {
1433         int i, bindex;
1434         MonoBasicBlock *bb = cfg->cbb;
1435         MonoBasicBlock *outb;
1436         MonoInst *inst, **locals;
1437         gboolean found;
1438
1439         if (!count)
1440                 return;
1441         if (cfg->verbose_level > 3)
1442                 printf ("%d item(s) on exit from B%d\n", count, bb->block_num);
1443         if (!bb->out_scount) {
1444                 bb->out_scount = count;
1445                 //printf ("bblock %d has out:", bb->block_num);
1446                 found = FALSE;
1447                 for (i = 0; i < bb->out_count; ++i) {
1448                         outb = bb->out_bb [i];
1449                         /* exception handlers are linked, but they should not be considered for stack args */
1450                         if (outb->flags & BB_EXCEPTION_HANDLER)
1451                                 continue;
1452                         //printf (" %d", outb->block_num);
1453                         if (outb->in_stack) {
1454                                 found = TRUE;
1455                                 bb->out_stack = outb->in_stack;
1456                                 break;
1457                         }
1458                 }
1459                 //printf ("\n");
1460                 if (!found) {
1461                         bb->out_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1462                         for (i = 0; i < count; ++i) {
1463                                 /* 
1464                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
1465                                  * stack slot and if they are of the same type.
1466                                  * This won't cause conflicts since if 'local' is used to 
1467                                  * store one of the values in the in_stack of a bblock, then
1468                                  * the same variable will be used for the same outgoing stack 
1469                                  * slot as well. 
1470                                  * This doesn't work when inlining methods, since the bblocks
1471                                  * in the inlined methods do not inherit their in_stack from
1472                                  * the bblock they are inlined to. See bug #58863 for an
1473                                  * example.
1474                                  */
1475                                 if (cfg->inlined_method)
1476                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1477                                 else
1478                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
1479                         }
1480                 }
1481         }
1482
1483         for (i = 0; i < bb->out_count; ++i) {
1484                 outb = bb->out_bb [i];
1485                 /* exception handlers are linked, but they should not be considered for stack args */
1486                 if (outb->flags & BB_EXCEPTION_HANDLER)
1487                         continue;
1488                 if (outb->in_scount) {
1489                         if (outb->in_scount != bb->out_scount) {
1490                                 cfg->unverifiable = TRUE;
1491                                 return;
1492                         }
1493                         continue; /* check they are the same locals */
1494                 }
1495                 outb->in_scount = count;
1496                 outb->in_stack = bb->out_stack;
1497         }
1498
1499         locals = bb->out_stack;
1500         cfg->cbb = bb;
1501         for (i = 0; i < count; ++i) {
1502                 EMIT_NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
1503                 inst->cil_code = sp [i]->cil_code;
1504                 sp [i] = locals [i];
1505                 if (cfg->verbose_level > 3)
1506                         printf ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
1507         }
1508
1509         /*
1510          * It is possible that the out bblocks already have in_stack assigned, and
1511          * the in_stacks differ. In this case, we will store to all the different 
1512          * in_stacks.
1513          */
1514
1515         found = TRUE;
1516         bindex = 0;
1517         while (found) {
1518                 /* Find a bblock which has a different in_stack */
1519                 found = FALSE;
1520                 while (bindex < bb->out_count) {
1521                         outb = bb->out_bb [bindex];
1522                         /* exception handlers are linked, but they should not be considered for stack args */
1523                         if (outb->flags & BB_EXCEPTION_HANDLER) {
1524                                 bindex++;
1525                                 continue;
1526                         }
1527                         if (outb->in_stack != locals) {
1528                                 for (i = 0; i < count; ++i) {
1529                                         EMIT_NEW_TEMPSTORE (cfg, inst, outb->in_stack [i]->inst_c0, sp [i]);
1530                                         inst->cil_code = sp [i]->cil_code;
1531                                         sp [i] = locals [i];
1532                                         if (cfg->verbose_level > 3)
1533                                                 printf ("storing %d to temp %d\n", i, (int)outb->in_stack [i]->inst_c0);
1534                                 }
1535                                 locals = outb->in_stack;
1536                                 found = TRUE;
1537                                 break;
1538                         }
1539                         bindex ++;
1540                 }
1541         }
1542 }
1543
1544 static MonoInst*
1545 emit_runtime_constant (MonoCompile *cfg, MonoJumpInfoType patch_type, gpointer data)
1546 {
1547         MonoInst *ins;
1548
1549         if (cfg->compile_aot) {
1550                 EMIT_NEW_AOTCONST (cfg, ins, patch_type, data);
1551         } else {
1552                 MonoJumpInfo ji;
1553                 gpointer target;
1554
1555                 ji.type = patch_type;
1556                 ji.data.target = data;
1557                 target = mono_resolve_patch_target (NULL, cfg->domain, NULL, &ji, FALSE);
1558
1559                 EMIT_NEW_PCONST (cfg, ins, target);
1560         }
1561         return ins;
1562 }
1563
1564 static void
1565 mini_emit_interface_bitmap_check (MonoCompile *cfg, int intf_bit_reg, int base_reg, int offset, MonoClass *klass)
1566 {
1567         int ibitmap_reg = alloc_preg (cfg);
1568 #ifdef COMPRESSED_INTERFACE_BITMAP
1569         MonoInst *args [2];
1570         MonoInst *res, *ins;
1571         NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, ibitmap_reg, base_reg, offset);
1572         MONO_ADD_INS (cfg->cbb, ins);
1573         args [0] = ins;
1574         args [1] = emit_runtime_constant (cfg, MONO_PATCH_INFO_IID, klass);
1575         res = mono_emit_jit_icall (cfg, mono_class_interface_match, args);
1576         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, intf_bit_reg, res->dreg);
1577 #else
1578         int ibitmap_byte_reg = alloc_preg (cfg);
1579
1580         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, base_reg, offset);
1581
1582         if (cfg->compile_aot) {
1583                 int iid_reg = alloc_preg (cfg);
1584                 int shifted_iid_reg = alloc_preg (cfg);
1585                 int ibitmap_byte_address_reg = alloc_preg (cfg);
1586                 int masked_iid_reg = alloc_preg (cfg);
1587                 int iid_one_bit_reg = alloc_preg (cfg);
1588                 int iid_bit_reg = alloc_preg (cfg);
1589                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1590                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, shifted_iid_reg, iid_reg, 3);
1591                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ibitmap_byte_address_reg, ibitmap_reg, shifted_iid_reg);
1592                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, ibitmap_byte_reg, ibitmap_byte_address_reg, 0);
1593                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, masked_iid_reg, iid_reg, 7);
1594                 MONO_EMIT_NEW_ICONST (cfg, iid_one_bit_reg, 1);
1595                 MONO_EMIT_NEW_BIALU (cfg, OP_ISHL, iid_bit_reg, iid_one_bit_reg, masked_iid_reg);
1596                 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, intf_bit_reg, ibitmap_byte_reg, iid_bit_reg);
1597         } else {
1598                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, klass->interface_id >> 3);
1599                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (klass->interface_id & 7));
1600         }
1601 #endif
1602 }
1603
1604 /* 
1605  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoClass
1606  * stored in "klass_reg" implements the interface "klass".
1607  */
1608 static void
1609 mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass_reg, MonoClass *klass)
1610 {
1611         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, interface_bitmap), klass);
1612 }
1613
1614 /* 
1615  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoVTable
1616  * stored in "vtable_reg" implements the interface "klass".
1617  */
1618 static void
1619 mini_emit_load_intf_bit_reg_vtable (MonoCompile *cfg, int intf_bit_reg, int vtable_reg, MonoClass *klass)
1620 {
1621         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, interface_bitmap), klass);
1622 }
1623
1624 /* 
1625  * Emit code which checks whenever the interface id of @klass is smaller than
1626  * than the value given by max_iid_reg.
1627 */
1628 static void
1629 mini_emit_max_iid_check (MonoCompile *cfg, int max_iid_reg, MonoClass *klass,
1630                                                  MonoBasicBlock *false_target)
1631 {
1632         if (cfg->compile_aot) {
1633                 int iid_reg = alloc_preg (cfg);
1634                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1635                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, max_iid_reg, iid_reg);
1636         }
1637         else
1638                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, max_iid_reg, klass->interface_id);
1639         if (false_target)
1640                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1641         else
1642                 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1643 }
1644
1645 /* Same as above, but obtains max_iid from a vtable */
1646 static void
1647 mini_emit_max_iid_check_vtable (MonoCompile *cfg, int vtable_reg, MonoClass *klass,
1648                                                                  MonoBasicBlock *false_target)
1649 {
1650         int max_iid_reg = alloc_preg (cfg);
1651                 
1652         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, max_interface_id));
1653         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1654 }
1655
1656 /* Same as above, but obtains max_iid from a klass */
1657 static void
1658 mini_emit_max_iid_check_class (MonoCompile *cfg, int klass_reg, MonoClass *klass,
1659                                                                  MonoBasicBlock *false_target)
1660 {
1661         int max_iid_reg = alloc_preg (cfg);
1662
1663         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, max_interface_id));
1664         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1665 }
1666
1667 static void
1668 mini_emit_isninst_cast_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_ins, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1669 {
1670         int idepth_reg = alloc_preg (cfg);
1671         int stypes_reg = alloc_preg (cfg);
1672         int stype = alloc_preg (cfg);
1673
1674         mono_class_setup_supertypes (klass);
1675
1676         if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1677                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1678                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1679                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1680         }
1681         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1682         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1683         if (klass_ins) {
1684                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, klass_ins->dreg);
1685         } else if (cfg->compile_aot) {
1686                 int const_reg = alloc_preg (cfg);
1687                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1688                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, const_reg);
1689         } else {
1690                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, stype, klass);
1691         }
1692         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, true_target);
1693 }
1694
1695 static void
1696 mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1697 {
1698         mini_emit_isninst_cast_inst (cfg, klass_reg, klass, NULL, false_target, true_target);
1699 }
1700
1701 static void
1702 mini_emit_iface_cast (MonoCompile *cfg, int vtable_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1703 {
1704         int intf_reg = alloc_preg (cfg);
1705
1706         mini_emit_max_iid_check_vtable (cfg, vtable_reg, klass, false_target);
1707         mini_emit_load_intf_bit_reg_vtable (cfg, intf_reg, vtable_reg, klass);
1708         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_reg, 0);
1709         if (true_target)
1710                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1711         else
1712                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");               
1713 }
1714
1715 /*
1716  * Variant of the above that takes a register to the class, not the vtable.
1717  */
1718 static void
1719 mini_emit_iface_class_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1720 {
1721         int intf_bit_reg = alloc_preg (cfg);
1722
1723         mini_emit_max_iid_check_class (cfg, klass_reg, klass, false_target);
1724         mini_emit_load_intf_bit_reg_class (cfg, intf_bit_reg, klass_reg, klass);
1725         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_bit_reg, 0);
1726         if (true_target)
1727                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1728         else
1729                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
1730 }
1731
1732 static inline void
1733 mini_emit_class_check_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_inst)
1734 {
1735         if (klass_inst) {
1736                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_inst->dreg);
1737         } else {
1738                 MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
1739                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, ins->dreg);
1740         }
1741         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1742 }
1743
1744 static inline void
1745 mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass)
1746 {
1747         mini_emit_class_check_inst (cfg, klass_reg, klass, NULL);
1748 }
1749
1750 static inline void
1751 mini_emit_class_check_branch (MonoCompile *cfg, int klass_reg, MonoClass *klass, int branch_op, MonoBasicBlock *target)
1752 {
1753         if (cfg->compile_aot) {
1754                 int const_reg = alloc_preg (cfg);
1755                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1756                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1757         } else {
1758                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1759         }
1760         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, branch_op, target);
1761 }
1762
1763 static void
1764 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null);
1765         
1766 static void
1767 mini_emit_castclass_inst (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoInst *klass_inst, MonoBasicBlock *object_is_null)
1768 {
1769         if (klass->rank) {
1770                 int rank_reg = alloc_preg (cfg);
1771                 int eclass_reg = alloc_preg (cfg);
1772
1773                 g_assert (!klass_inst);
1774                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, rank));
1775                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
1776                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1777                 //              MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
1778                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
1779                 if (klass->cast_class == mono_defaults.object_class) {
1780                         int parent_reg = alloc_preg (cfg);
1781                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
1782                         mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, object_is_null);
1783                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1784                 } else if (klass->cast_class == mono_defaults.enum_class->parent) {
1785                         mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, object_is_null);
1786                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1787                 } else if (klass->cast_class == mono_defaults.enum_class) {
1788                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1789                 } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1790                         mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, NULL, NULL);
1791                 } else {
1792                         // Pass -1 as obj_reg to skip the check below for arrays of arrays
1793                         mini_emit_castclass (cfg, -1, eclass_reg, klass->cast_class, object_is_null);
1794                 }
1795
1796                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY) && (obj_reg != -1)) {
1797                         /* Check that the object is a vector too */
1798                         int bounds_reg = alloc_preg (cfg);
1799                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
1800                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
1801                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1802                 }
1803         } else {
1804                 int idepth_reg = alloc_preg (cfg);
1805                 int stypes_reg = alloc_preg (cfg);
1806                 int stype = alloc_preg (cfg);
1807
1808                 mono_class_setup_supertypes (klass);
1809
1810                 if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1811                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1812                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1813                         MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1814                 }
1815                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1816                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1817                 mini_emit_class_check_inst (cfg, stype, klass, klass_inst);
1818         }
1819 }
1820
1821 static void
1822 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null)
1823 {
1824         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, NULL, object_is_null);
1825 }
1826
1827 static void 
1828 mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align)
1829 {
1830         int val_reg;
1831
1832         g_assert (val == 0);
1833
1834         if (align == 0)
1835                 align = 4;
1836
1837         if ((size <= SIZEOF_REGISTER) && (size <= align)) {
1838                 switch (size) {
1839                 case 1:
1840                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, destreg, offset, val);
1841                         return;
1842                 case 2:
1843                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI2_MEMBASE_IMM, destreg, offset, val);
1844                         return;
1845                 case 4:
1846                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI4_MEMBASE_IMM, destreg, offset, val);
1847                         return;
1848 #if SIZEOF_REGISTER == 8
1849                 case 8:
1850                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI8_MEMBASE_IMM, destreg, offset, val);
1851                         return;
1852 #endif
1853                 }
1854         }
1855
1856         val_reg = alloc_preg (cfg);
1857
1858         if (SIZEOF_REGISTER == 8)
1859                 MONO_EMIT_NEW_I8CONST (cfg, val_reg, val);
1860         else
1861                 MONO_EMIT_NEW_ICONST (cfg, val_reg, val);
1862
1863         if (align < 4) {
1864                 /* This could be optimized further if neccesary */
1865                 while (size >= 1) {
1866                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1867                         offset += 1;
1868                         size -= 1;
1869                 }
1870                 return;
1871         }       
1872
1873         if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
1874                 if (offset % 8) {
1875                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1876                         offset += 4;
1877                         size -= 4;
1878                 }
1879                 while (size >= 8) {
1880                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, offset, val_reg);
1881                         offset += 8;
1882                         size -= 8;
1883                 }
1884         }       
1885
1886         while (size >= 4) {
1887                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1888                 offset += 4;
1889                 size -= 4;
1890         }
1891         while (size >= 2) {
1892                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, val_reg);
1893                 offset += 2;
1894                 size -= 2;
1895         }
1896         while (size >= 1) {
1897                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1898                 offset += 1;
1899                 size -= 1;
1900         }
1901 }
1902
1903 void 
1904 mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align)
1905 {
1906         int cur_reg;
1907
1908         if (align == 0)
1909                 align = 4;
1910
1911         /*FIXME arbitrary hack to avoid unbound code expansion.*/
1912         g_assert (size < 10000);
1913
1914         if (align < 4) {
1915                 /* This could be optimized further if neccesary */
1916                 while (size >= 1) {
1917                         cur_reg = alloc_preg (cfg);
1918                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1919                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1920                         doffset += 1;
1921                         soffset += 1;
1922                         size -= 1;
1923                 }
1924         }
1925
1926         if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
1927                 while (size >= 8) {
1928                         cur_reg = alloc_preg (cfg);
1929                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI8_MEMBASE, cur_reg, srcreg, soffset);
1930                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, doffset, cur_reg);
1931                         doffset += 8;
1932                         soffset += 8;
1933                         size -= 8;
1934                 }
1935         }       
1936
1937         while (size >= 4) {
1938                 cur_reg = alloc_preg (cfg);
1939                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, cur_reg, srcreg, soffset);
1940                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, doffset, cur_reg);
1941                 doffset += 4;
1942                 soffset += 4;
1943                 size -= 4;
1944         }
1945         while (size >= 2) {
1946                 cur_reg = alloc_preg (cfg);
1947                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, cur_reg, srcreg, soffset);
1948                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, doffset, cur_reg);
1949                 doffset += 2;
1950                 soffset += 2;
1951                 size -= 2;
1952         }
1953         while (size >= 1) {
1954                 cur_reg = alloc_preg (cfg);
1955                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1956                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1957                 doffset += 1;
1958                 soffset += 1;
1959                 size -= 1;
1960         }
1961 }
1962
1963 static void
1964 emit_tls_set (MonoCompile *cfg, int sreg1, MonoTlsKey tls_key)
1965 {
1966         MonoInst *ins, *c;
1967
1968         if (cfg->compile_aot) {
1969                 EMIT_NEW_TLS_OFFSETCONST (cfg, c, tls_key);
1970                 MONO_INST_NEW (cfg, ins, OP_TLS_SET_REG);
1971                 ins->sreg1 = sreg1;
1972                 ins->sreg2 = c->dreg;
1973                 MONO_ADD_INS (cfg->cbb, ins);
1974         } else {
1975                 MONO_INST_NEW (cfg, ins, OP_TLS_SET);
1976                 ins->sreg1 = sreg1;
1977                 ins->inst_offset = mini_get_tls_offset (tls_key);
1978                 MONO_ADD_INS (cfg->cbb, ins);
1979         }
1980 }
1981
1982 /*
1983  * emit_push_lmf:
1984  *
1985  *   Emit IR to push the current LMF onto the LMF stack.
1986  */
1987 static void
1988 emit_push_lmf (MonoCompile *cfg)
1989 {
1990         /*
1991          * Emit IR to push the LMF:
1992          * lmf_addr = <lmf_addr from tls>
1993          * lmf->lmf_addr = lmf_addr
1994          * lmf->prev_lmf = *lmf_addr
1995          * *lmf_addr = lmf
1996          */
1997         int lmf_reg, prev_lmf_reg;
1998         MonoInst *ins, *lmf_ins;
1999
2000         if (!cfg->lmf_ir)
2001                 return;
2002
2003         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
2004                 /* Load current lmf */
2005                 lmf_ins = mono_get_lmf_intrinsic (cfg);
2006                 g_assert (lmf_ins);
2007                 MONO_ADD_INS (cfg->cbb, lmf_ins);
2008                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2009                 lmf_reg = ins->dreg;
2010                 /* Save previous_lmf */
2011                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), lmf_ins->dreg);
2012                 /* Set new LMF */
2013                 emit_tls_set (cfg, lmf_reg, TLS_KEY_LMF);
2014         } else {
2015                 /*
2016                  * Store lmf_addr in a variable, so it can be allocated to a global register.
2017                  */
2018                 if (!cfg->lmf_addr_var)
2019                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2020
2021 #ifdef HOST_WIN32
2022                 ins = mono_get_jit_tls_intrinsic (cfg);
2023                 if (ins) {
2024                         int jit_tls_dreg = ins->dreg;
2025
2026                         MONO_ADD_INS (cfg->cbb, ins);
2027                         lmf_reg = alloc_preg (cfg);
2028                         EMIT_NEW_BIALU_IMM (cfg, lmf_ins, OP_PADD_IMM, lmf_reg, jit_tls_dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2029                 } else {
2030                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2031                 }
2032 #else
2033                 lmf_ins = mono_get_lmf_addr_intrinsic (cfg);
2034                 if (lmf_ins) {
2035                         MONO_ADD_INS (cfg->cbb, lmf_ins);
2036                 } else {
2037 #ifdef TARGET_IOS
2038                         MonoInst *args [16], *jit_tls_ins, *ins;
2039
2040                         /* Inline mono_get_lmf_addr () */
2041                         /* jit_tls = pthread_getspecific (mono_jit_tls_id); lmf_addr = &jit_tls->lmf; */
2042
2043                         /* Load mono_jit_tls_id */
2044                         if (cfg->compile_aot)
2045                                 EMIT_NEW_AOTCONST (cfg, args [0], MONO_PATCH_INFO_JIT_TLS_ID, NULL);
2046                         else
2047                                 EMIT_NEW_ICONST (cfg, args [0], mono_jit_tls_id);
2048                         /* call pthread_getspecific () */
2049                         jit_tls_ins = mono_emit_jit_icall (cfg, pthread_getspecific, args);
2050                         /* lmf_addr = &jit_tls->lmf */
2051                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, cfg->lmf_addr_var->dreg, jit_tls_ins->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2052                         lmf_ins = ins;
2053 #else
2054                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2055 #endif
2056                 }
2057 #endif
2058                 lmf_ins->dreg = cfg->lmf_addr_var->dreg;
2059
2060                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2061                 lmf_reg = ins->dreg;
2062
2063                 prev_lmf_reg = alloc_preg (cfg);
2064                 /* Save previous_lmf */
2065                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, cfg->lmf_addr_var->dreg, 0);
2066                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), prev_lmf_reg);
2067                 /* Set new lmf */
2068                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, cfg->lmf_addr_var->dreg, 0, lmf_reg);
2069         }
2070 }
2071
2072 /*
2073  * emit_pop_lmf:
2074  *
2075  *   Emit IR to pop the current LMF from the LMF stack.
2076  */
2077 static void
2078 emit_pop_lmf (MonoCompile *cfg)
2079 {
2080         int lmf_reg, lmf_addr_reg, prev_lmf_reg;
2081         MonoInst *ins;
2082
2083         if (!cfg->lmf_ir)
2084                 return;
2085
2086         EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2087         lmf_reg = ins->dreg;
2088
2089         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
2090                 /* Load previous_lmf */
2091                 prev_lmf_reg = alloc_preg (cfg);
2092                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2093                 /* Set new LMF */
2094                 emit_tls_set (cfg, prev_lmf_reg, TLS_KEY_LMF);
2095         } else {
2096                 /*
2097                  * Emit IR to pop the LMF:
2098                  * *(lmf->lmf_addr) = lmf->prev_lmf
2099                  */
2100                 /* This could be called before emit_push_lmf () */
2101                 if (!cfg->lmf_addr_var)
2102                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2103                 lmf_addr_reg = cfg->lmf_addr_var->dreg;
2104
2105                 prev_lmf_reg = alloc_preg (cfg);
2106                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2107                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_addr_reg, 0, prev_lmf_reg);
2108         }
2109 }
2110
2111 static void
2112 emit_instrumentation_call (MonoCompile *cfg, void *func)
2113 {
2114         MonoInst *iargs [1];
2115
2116         /*
2117          * Avoid instrumenting inlined methods since it can
2118          * distort profiling results.
2119          */
2120         if (cfg->method != cfg->current_method)
2121                 return;
2122
2123         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
2124                 EMIT_NEW_METHODCONST (cfg, iargs [0], cfg->method);
2125                 mono_emit_jit_icall (cfg, func, iargs);
2126         }
2127 }
2128
2129 static int
2130 ret_type_to_call_opcode (MonoCompile *cfg, MonoType *type, int calli, int virt)
2131 {
2132 handle_enum:
2133         type = mini_get_underlying_type (type);
2134         switch (type->type) {
2135         case MONO_TYPE_VOID:
2136                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALL_MEMBASE: OP_VOIDCALL;
2137         case MONO_TYPE_I1:
2138         case MONO_TYPE_U1:
2139         case MONO_TYPE_I2:
2140         case MONO_TYPE_U2:
2141         case MONO_TYPE_I4:
2142         case MONO_TYPE_U4:
2143                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2144         case MONO_TYPE_I:
2145         case MONO_TYPE_U:
2146         case MONO_TYPE_PTR:
2147         case MONO_TYPE_FNPTR:
2148                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2149         case MONO_TYPE_CLASS:
2150         case MONO_TYPE_STRING:
2151         case MONO_TYPE_OBJECT:
2152         case MONO_TYPE_SZARRAY:
2153         case MONO_TYPE_ARRAY:    
2154                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2155         case MONO_TYPE_I8:
2156         case MONO_TYPE_U8:
2157                 return calli? OP_LCALL_REG: virt? OP_LCALL_MEMBASE: OP_LCALL;
2158         case MONO_TYPE_R4:
2159                 if (cfg->r4fp)
2160                         return calli? OP_RCALL_REG: virt? OP_RCALL_MEMBASE: OP_RCALL;
2161                 else
2162                         return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2163         case MONO_TYPE_R8:
2164                 return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2165         case MONO_TYPE_VALUETYPE:
2166                 if (type->data.klass->enumtype) {
2167                         type = mono_class_enum_basetype (type->data.klass);
2168                         goto handle_enum;
2169                 } else
2170                         return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2171         case MONO_TYPE_TYPEDBYREF:
2172                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2173         case MONO_TYPE_GENERICINST:
2174                 type = &type->data.generic_class->container_class->byval_arg;
2175                 goto handle_enum;
2176         case MONO_TYPE_VAR:
2177         case MONO_TYPE_MVAR:
2178                 /* gsharedvt */
2179                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2180         default:
2181                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
2182         }
2183         return -1;
2184 }
2185
2186 /*
2187  * target_type_is_incompatible:
2188  * @cfg: MonoCompile context
2189  *
2190  * Check that the item @arg on the evaluation stack can be stored
2191  * in the target type (can be a local, or field, etc).
2192  * The cfg arg can be used to check if we need verification or just
2193  * validity checks.
2194  *
2195  * Returns: non-0 value if arg can't be stored on a target.
2196  */
2197 static int
2198 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
2199 {
2200         MonoType *simple_type;
2201         MonoClass *klass;
2202
2203         if (target->byref) {
2204                 /* FIXME: check that the pointed to types match */
2205                 if (arg->type == STACK_MP) {
2206                         MonoClass *base_class = mono_class_from_mono_type (target);
2207                         /* This is needed to handle gshared types + ldaddr */
2208                         simple_type = mini_get_underlying_type (&base_class->byval_arg);
2209                         return target->type != MONO_TYPE_I && arg->klass != base_class && arg->klass != mono_class_from_mono_type (simple_type);
2210                 }
2211                 if (arg->type == STACK_PTR)
2212                         return 0;
2213                 return 1;
2214         }
2215
2216         simple_type = mini_get_underlying_type (target);
2217         switch (simple_type->type) {
2218         case MONO_TYPE_VOID:
2219                 return 1;
2220         case MONO_TYPE_I1:
2221         case MONO_TYPE_U1:
2222         case MONO_TYPE_I2:
2223         case MONO_TYPE_U2:
2224         case MONO_TYPE_I4:
2225         case MONO_TYPE_U4:
2226                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2227                         return 1;
2228                 return 0;
2229         case MONO_TYPE_PTR:
2230                 /* STACK_MP is needed when setting pinned locals */
2231                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2232                         return 1;
2233                 return 0;
2234         case MONO_TYPE_I:
2235         case MONO_TYPE_U:
2236         case MONO_TYPE_FNPTR:
2237                 /* 
2238                  * Some opcodes like ldloca returns 'transient pointers' which can be stored in
2239                  * in native int. (#688008).
2240                  */
2241                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2242                         return 1;
2243                 return 0;
2244         case MONO_TYPE_CLASS:
2245         case MONO_TYPE_STRING:
2246         case MONO_TYPE_OBJECT:
2247         case MONO_TYPE_SZARRAY:
2248         case MONO_TYPE_ARRAY:    
2249                 if (arg->type != STACK_OBJ)
2250                         return 1;
2251                 /* FIXME: check type compatibility */
2252                 return 0;
2253         case MONO_TYPE_I8:
2254         case MONO_TYPE_U8:
2255                 if (arg->type != STACK_I8)
2256                         return 1;
2257                 return 0;
2258         case MONO_TYPE_R4:
2259                 if (arg->type != cfg->r4_stack_type)
2260                         return 1;
2261                 return 0;
2262         case MONO_TYPE_R8:
2263                 if (arg->type != STACK_R8)
2264                         return 1;
2265                 return 0;
2266         case MONO_TYPE_VALUETYPE:
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_TYPEDBYREF:
2274                 if (arg->type != STACK_VTYPE)
2275                         return 1;
2276                 klass = mono_class_from_mono_type (simple_type);
2277                 if (klass != arg->klass)
2278                         return 1;
2279                 return 0;
2280         case MONO_TYPE_GENERICINST:
2281                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
2282                         MonoClass *target_class;
2283                         if (arg->type != STACK_VTYPE)
2284                                 return 1;
2285                         klass = mono_class_from_mono_type (simple_type);
2286                         target_class = mono_class_from_mono_type (target);
2287                         /* The second cases is needed when doing partial sharing */
2288                         if (klass != arg->klass && target_class != arg->klass && target_class != mono_class_from_mono_type (mini_get_underlying_type (&arg->klass->byval_arg)))
2289                                 return 1;
2290                         return 0;
2291                 } else {
2292                         if (arg->type != STACK_OBJ)
2293                                 return 1;
2294                         /* FIXME: check type compatibility */
2295                         return 0;
2296                 }
2297         case MONO_TYPE_VAR:
2298         case MONO_TYPE_MVAR:
2299                 g_assert (cfg->gshared);
2300                 if (mini_type_var_is_vt (simple_type)) {
2301                         if (arg->type != STACK_VTYPE)
2302                                 return 1;
2303                 } else {
2304                         if (arg->type != STACK_OBJ)
2305                                 return 1;
2306                 }
2307                 return 0;
2308         default:
2309                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
2310         }
2311         return 1;
2312 }
2313
2314 /*
2315  * Prepare arguments for passing to a function call.
2316  * Return a non-zero value if the arguments can't be passed to the given
2317  * signature.
2318  * The type checks are not yet complete and some conversions may need
2319  * casts on 32 or 64 bit architectures.
2320  *
2321  * FIXME: implement this using target_type_is_incompatible ()
2322  */
2323 static int
2324 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2325 {
2326         MonoType *simple_type;
2327         int i;
2328
2329         if (sig->hasthis) {
2330                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2331                         return 1;
2332                 args++;
2333         }
2334         for (i = 0; i < sig->param_count; ++i) {
2335                 if (sig->params [i]->byref) {
2336                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2337                                 return 1;
2338                         continue;
2339                 }
2340                 simple_type = mini_get_underlying_type (sig->params [i]);
2341 handle_enum:
2342                 switch (simple_type->type) {
2343                 case MONO_TYPE_VOID:
2344                         return 1;
2345                         continue;
2346                 case MONO_TYPE_I1:
2347                 case MONO_TYPE_U1:
2348                 case MONO_TYPE_I2:
2349                 case MONO_TYPE_U2:
2350                 case MONO_TYPE_I4:
2351                 case MONO_TYPE_U4:
2352                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2353                                 return 1;
2354                         continue;
2355                 case MONO_TYPE_I:
2356                 case MONO_TYPE_U:
2357                 case MONO_TYPE_PTR:
2358                 case MONO_TYPE_FNPTR:
2359                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2360                                 return 1;
2361                         continue;
2362                 case MONO_TYPE_CLASS:
2363                 case MONO_TYPE_STRING:
2364                 case MONO_TYPE_OBJECT:
2365                 case MONO_TYPE_SZARRAY:
2366                 case MONO_TYPE_ARRAY:    
2367                         if (args [i]->type != STACK_OBJ)
2368                                 return 1;
2369                         continue;
2370                 case MONO_TYPE_I8:
2371                 case MONO_TYPE_U8:
2372                         if (args [i]->type != STACK_I8)
2373                                 return 1;
2374                         continue;
2375                 case MONO_TYPE_R4:
2376                         if (args [i]->type != cfg->r4_stack_type)
2377                                 return 1;
2378                         continue;
2379                 case MONO_TYPE_R8:
2380                         if (args [i]->type != STACK_R8)
2381                                 return 1;
2382                         continue;
2383                 case MONO_TYPE_VALUETYPE:
2384                         if (simple_type->data.klass->enumtype) {
2385                                 simple_type = mono_class_enum_basetype (simple_type->data.klass);
2386                                 goto handle_enum;
2387                         }
2388                         if (args [i]->type != STACK_VTYPE)
2389                                 return 1;
2390                         continue;
2391                 case MONO_TYPE_TYPEDBYREF:
2392                         if (args [i]->type != STACK_VTYPE)
2393                                 return 1;
2394                         continue;
2395                 case MONO_TYPE_GENERICINST:
2396                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2397                         goto handle_enum;
2398                 case MONO_TYPE_VAR:
2399                 case MONO_TYPE_MVAR:
2400                         /* gsharedvt */
2401                         if (args [i]->type != STACK_VTYPE)
2402                                 return 1;
2403                         continue;
2404                 default:
2405                         g_error ("unknown type 0x%02x in check_call_signature",
2406                                  simple_type->type);
2407                 }
2408         }
2409         return 0;
2410 }
2411
2412 static int
2413 callvirt_to_call (int opcode)
2414 {
2415         switch (opcode) {
2416         case OP_CALL_MEMBASE:
2417                 return OP_CALL;
2418         case OP_VOIDCALL_MEMBASE:
2419                 return OP_VOIDCALL;
2420         case OP_FCALL_MEMBASE:
2421                 return OP_FCALL;
2422         case OP_RCALL_MEMBASE:
2423                 return OP_RCALL;
2424         case OP_VCALL_MEMBASE:
2425                 return OP_VCALL;
2426         case OP_LCALL_MEMBASE:
2427                 return OP_LCALL;
2428         default:
2429                 g_assert_not_reached ();
2430         }
2431
2432         return -1;
2433 }
2434
2435 static int
2436 callvirt_to_call_reg (int opcode)
2437 {
2438         switch (opcode) {
2439         case OP_CALL_MEMBASE:
2440                 return OP_CALL_REG;
2441         case OP_VOIDCALL_MEMBASE:
2442                 return OP_VOIDCALL_REG;
2443         case OP_FCALL_MEMBASE:
2444                 return OP_FCALL_REG;
2445         case OP_RCALL_MEMBASE:
2446                 return OP_RCALL_REG;
2447         case OP_VCALL_MEMBASE:
2448                 return OP_VCALL_REG;
2449         case OP_LCALL_MEMBASE:
2450                 return OP_LCALL_REG;
2451         default:
2452                 g_assert_not_reached ();
2453         }
2454
2455         return -1;
2456 }
2457
2458 /* Either METHOD or IMT_ARG needs to be set */
2459 static void
2460 emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoMethod *method, MonoInst *imt_arg)
2461 {
2462         int method_reg;
2463
2464         if (COMPILE_LLVM (cfg)) {
2465                 if (imt_arg) {
2466                         method_reg = alloc_preg (cfg);
2467                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2468                 } else {
2469                         MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHODCONST, method);
2470                         method_reg = ins->dreg;
2471                 }
2472
2473 #ifdef ENABLE_LLVM
2474                 call->imt_arg_reg = method_reg;
2475 #endif
2476                 mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2477                 return;
2478         }
2479
2480         if (imt_arg) {
2481                 method_reg = alloc_preg (cfg);
2482                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2483         } else {
2484                 MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHODCONST, method);
2485                 method_reg = ins->dreg;
2486         }
2487
2488         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2489 }
2490
2491 static MonoJumpInfo *
2492 mono_patch_info_new (MonoMemPool *mp, int ip, MonoJumpInfoType type, gconstpointer target)
2493 {
2494         MonoJumpInfo *ji = (MonoJumpInfo *)mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
2495
2496         ji->ip.i = ip;
2497         ji->type = type;
2498         ji->data.target = target;
2499
2500         return ji;
2501 }
2502
2503 static int
2504 mini_class_check_context_used (MonoCompile *cfg, MonoClass *klass)
2505 {
2506         if (cfg->gshared)
2507                 return mono_class_check_context_used (klass);
2508         else
2509                 return 0;
2510 }
2511
2512 static int
2513 mini_method_check_context_used (MonoCompile *cfg, MonoMethod *method)
2514 {
2515         if (cfg->gshared)
2516                 return mono_method_check_context_used (method);
2517         else
2518                 return 0;
2519 }
2520
2521 /*
2522  * check_method_sharing:
2523  *
2524  *   Check whenever the vtable or an mrgctx needs to be passed when calling CMETHOD.
2525  */
2526 static void
2527 check_method_sharing (MonoCompile *cfg, MonoMethod *cmethod, gboolean *out_pass_vtable, gboolean *out_pass_mrgctx)
2528 {
2529         gboolean pass_vtable = FALSE;
2530         gboolean pass_mrgctx = FALSE;
2531
2532         if (((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
2533                 (cmethod->klass->generic_class || cmethod->klass->generic_container)) {
2534                 gboolean sharable = FALSE;
2535
2536                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE))
2537                         sharable = TRUE;
2538
2539                 /*
2540                  * Pass vtable iff target method might
2541                  * be shared, which means that sharing
2542                  * is enabled for its class and its
2543                  * context is sharable (and it's not a
2544                  * generic method).
2545                  */
2546                 if (sharable && !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
2547                         pass_vtable = TRUE;
2548         }
2549
2550         if (mini_method_get_context (cmethod) &&
2551                 mini_method_get_context (cmethod)->method_inst) {
2552                 g_assert (!pass_vtable);
2553
2554                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE)) {
2555                         pass_mrgctx = TRUE;
2556                 } else {
2557                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (mono_method_signature (cmethod)))
2558                                 pass_mrgctx = TRUE;
2559                 }
2560         }
2561
2562         if (out_pass_vtable)
2563                 *out_pass_vtable = pass_vtable;
2564         if (out_pass_mrgctx)
2565                 *out_pass_mrgctx = pass_mrgctx;
2566 }
2567
2568 inline static MonoCallInst *
2569 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
2570                                          MonoInst **args, int calli, int virtual_, int tail, int rgctx, int unbox_trampoline)
2571 {
2572         MonoType *sig_ret;
2573         MonoCallInst *call;
2574 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2575         int i;
2576 #endif
2577
2578         if (cfg->llvm_only)
2579                 tail = FALSE;
2580
2581         if (tail) {
2582                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
2583
2584                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
2585         } else
2586                 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (cfg, sig->ret, calli, virtual_));
2587
2588         call->args = args;
2589         call->signature = sig;
2590         call->rgctx_reg = rgctx;
2591         sig_ret = mini_get_underlying_type (sig->ret);
2592
2593         type_to_eval_stack_type ((cfg), sig_ret, &call->inst);
2594
2595         if (tail) {
2596                 if (mini_type_is_vtype (sig_ret)) {
2597                         call->vret_var = cfg->vret_addr;
2598                         //g_assert_not_reached ();
2599                 }
2600         } else if (mini_type_is_vtype (sig_ret)) {
2601                 MonoInst *temp = mono_compile_create_var (cfg, sig_ret, OP_LOCAL);
2602                 MonoInst *loada;
2603
2604                 temp->backend.is_pinvoke = sig->pinvoke;
2605
2606                 /*
2607                  * We use a new opcode OP_OUTARG_VTRETADDR instead of LDADDR for emitting the
2608                  * address of return value to increase optimization opportunities.
2609                  * Before vtype decomposition, the dreg of the call ins itself represents the
2610                  * fact the call modifies the return value. After decomposition, the call will
2611                  * be transformed into one of the OP_VOIDCALL opcodes, and the VTRETADDR opcode
2612                  * will be transformed into an LDADDR.
2613                  */
2614                 MONO_INST_NEW (cfg, loada, OP_OUTARG_VTRETADDR);
2615                 loada->dreg = alloc_preg (cfg);
2616                 loada->inst_p0 = temp;
2617                 /* We reference the call too since call->dreg could change during optimization */
2618                 loada->inst_p1 = call;
2619                 MONO_ADD_INS (cfg->cbb, loada);
2620
2621                 call->inst.dreg = temp->dreg;
2622
2623                 call->vret_var = loada;
2624         } else if (!MONO_TYPE_IS_VOID (sig_ret))
2625                 call->inst.dreg = alloc_dreg (cfg, (MonoStackType)call->inst.type);
2626
2627 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2628         if (COMPILE_SOFT_FLOAT (cfg)) {
2629                 /* 
2630                  * If the call has a float argument, we would need to do an r8->r4 conversion using 
2631                  * an icall, but that cannot be done during the call sequence since it would clobber
2632                  * the call registers + the stack. So we do it before emitting the call.
2633                  */
2634                 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2635                         MonoType *t;
2636                         MonoInst *in = call->args [i];
2637
2638                         if (i >= sig->hasthis)
2639                                 t = sig->params [i - sig->hasthis];
2640                         else
2641                                 t = &mono_defaults.int_class->byval_arg;
2642                         t = mono_type_get_underlying_type (t);
2643
2644                         if (!t->byref && t->type == MONO_TYPE_R4) {
2645                                 MonoInst *iargs [1];
2646                                 MonoInst *conv;
2647
2648                                 iargs [0] = in;
2649                                 conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
2650
2651                                 /* The result will be in an int vreg */
2652                                 call->args [i] = conv;
2653                         }
2654                 }
2655         }
2656 #endif
2657
2658         call->need_unbox_trampoline = unbox_trampoline;
2659
2660 #ifdef ENABLE_LLVM
2661         if (COMPILE_LLVM (cfg))
2662                 mono_llvm_emit_call (cfg, call);
2663         else
2664                 mono_arch_emit_call (cfg, call);
2665 #else
2666         mono_arch_emit_call (cfg, call);
2667 #endif
2668
2669         cfg->param_area = MAX (cfg->param_area, call->stack_usage);
2670         cfg->flags |= MONO_CFG_HAS_CALLS;
2671         
2672         return call;
2673 }
2674
2675 static void
2676 set_rgctx_arg (MonoCompile *cfg, MonoCallInst *call, int rgctx_reg, MonoInst *rgctx_arg)
2677 {
2678         mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
2679         cfg->uses_rgctx_reg = TRUE;
2680         call->rgctx_reg = TRUE;
2681 #ifdef ENABLE_LLVM
2682         call->rgctx_arg_reg = rgctx_reg;
2683 #endif
2684 }       
2685
2686 inline static MonoInst*
2687 mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg)
2688 {
2689         MonoCallInst *call;
2690         MonoInst *ins;
2691         int rgctx_reg = -1;
2692         gboolean check_sp = FALSE;
2693
2694         if (cfg->check_pinvoke_callconv && cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
2695                 WrapperInfo *info = mono_marshal_get_wrapper_info (cfg->method);
2696
2697                 if (info && info->subtype == WRAPPER_SUBTYPE_PINVOKE)
2698                         check_sp = TRUE;
2699         }
2700
2701         if (rgctx_arg) {
2702                 rgctx_reg = mono_alloc_preg (cfg);
2703                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2704         }
2705
2706         if (check_sp) {
2707                 if (!cfg->stack_inbalance_var)
2708                         cfg->stack_inbalance_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2709
2710                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2711                 ins->dreg = cfg->stack_inbalance_var->dreg;
2712                 MONO_ADD_INS (cfg->cbb, ins);
2713         }
2714
2715         call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE, FALSE);
2716
2717         call->inst.sreg1 = addr->dreg;
2718
2719         if (imt_arg)
2720                 emit_imt_argument (cfg, call, NULL, imt_arg);
2721
2722         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2723
2724         if (check_sp) {
2725                 int sp_reg;
2726
2727                 sp_reg = mono_alloc_preg (cfg);
2728
2729                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2730                 ins->dreg = sp_reg;
2731                 MONO_ADD_INS (cfg->cbb, ins);
2732
2733                 /* Restore the stack so we don't crash when throwing the exception */
2734                 MONO_INST_NEW (cfg, ins, OP_SET_SP);
2735                 ins->sreg1 = cfg->stack_inbalance_var->dreg;
2736                 MONO_ADD_INS (cfg->cbb, ins);
2737
2738                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, cfg->stack_inbalance_var->dreg, sp_reg);
2739                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ExecutionEngineException");
2740         }
2741
2742         if (rgctx_arg)
2743                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2744
2745         return (MonoInst*)call;
2746 }
2747
2748 static MonoInst*
2749 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2750
2751 static MonoInst*
2752 emit_get_rgctx_method (MonoCompile *cfg, int context_used, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type);
2753 static MonoInst*
2754 emit_get_rgctx_klass (MonoCompile *cfg, int context_used, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2755
2756 static MonoInst*
2757 mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig, gboolean tail,
2758                                                         MonoInst **args, MonoInst *this_ins, MonoInst *imt_arg, MonoInst *rgctx_arg)
2759 {
2760 #ifndef DISABLE_REMOTING
2761         gboolean might_be_remote = FALSE;
2762 #endif
2763         gboolean virtual_ = this_ins != NULL;
2764         gboolean enable_for_aot = TRUE;
2765         int context_used;
2766         MonoCallInst *call;
2767         MonoInst *call_target = NULL;
2768         int rgctx_reg = 0;
2769         gboolean need_unbox_trampoline;
2770
2771         if (!sig)
2772                 sig = mono_method_signature (method);
2773
2774         if (cfg->llvm_only && (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE))
2775                 g_assert_not_reached ();
2776
2777         if (rgctx_arg) {
2778                 rgctx_reg = mono_alloc_preg (cfg);
2779                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2780         }
2781
2782         if (method->string_ctor) {
2783                 /* Create the real signature */
2784                 /* FIXME: Cache these */
2785                 MonoMethodSignature *ctor_sig = mono_metadata_signature_dup_mempool (cfg->mempool, sig);
2786                 ctor_sig->ret = &mono_defaults.string_class->byval_arg;
2787
2788                 sig = ctor_sig;
2789         }
2790
2791         context_used = mini_method_check_context_used (cfg, method);
2792
2793 #ifndef DISABLE_REMOTING
2794         might_be_remote = this_ins && sig->hasthis &&
2795                 (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) &&
2796                 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && (!MONO_CHECK_THIS (this_ins) || context_used);
2797
2798         if (might_be_remote && context_used) {
2799                 MonoInst *addr;
2800
2801                 g_assert (cfg->gshared);
2802
2803                 addr = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK);
2804
2805                 return mono_emit_calli (cfg, sig, args, addr, NULL, NULL);
2806         }
2807 #endif
2808
2809         if (cfg->llvm_only && !call_target && virtual_ && (method->flags & METHOD_ATTRIBUTE_VIRTUAL))
2810                 return emit_llvmonly_virtual_call (cfg, method, sig, 0, args);
2811
2812         need_unbox_trampoline = method->klass == mono_defaults.object_class || (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
2813
2814         call = mono_emit_call_args (cfg, sig, args, FALSE, virtual_, tail, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline);
2815
2816 #ifndef DISABLE_REMOTING
2817         if (might_be_remote)
2818                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2819         else
2820 #endif
2821                 call->method = method;
2822         call->inst.flags |= MONO_INST_HAS_METHOD;
2823         call->inst.inst_left = this_ins;
2824         call->tail_call = tail;
2825
2826         if (virtual_) {
2827                 int vtable_reg, slot_reg, this_reg;
2828                 int offset;
2829
2830                 this_reg = this_ins->dreg;
2831
2832                 if (!cfg->llvm_only && (method->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (method->name, "Invoke")) {
2833                         MonoInst *dummy_use;
2834
2835                         MONO_EMIT_NULL_CHECK (cfg, this_reg);
2836
2837                         /* Make a call to delegate->invoke_impl */
2838                         call->inst.inst_basereg = this_reg;
2839                         call->inst.inst_offset = MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl);
2840                         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2841
2842                         /* We must emit a dummy use here because the delegate trampoline will
2843                         replace the 'this' argument with the delegate target making this activation
2844                         no longer a root for the delegate.
2845                         This is an issue for delegates that target collectible code such as dynamic
2846                         methods of GC'able assemblies.
2847
2848                         For a test case look into #667921.
2849
2850                         FIXME: a dummy use is not the best way to do it as the local register allocator
2851                         will put it on a caller save register and spil it around the call. 
2852                         Ideally, we would either put it on a callee save register or only do the store part.  
2853                          */
2854                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, args [0]);
2855
2856                         return (MonoInst*)call;
2857                 }
2858
2859                 if ((!cfg->compile_aot || enable_for_aot) && 
2860                         (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || 
2861                          (MONO_METHOD_IS_FINAL (method) &&
2862                           method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)) &&
2863                         !(mono_class_is_marshalbyref (method->klass) && context_used)) {
2864                         /* 
2865                          * the method is not virtual, we just need to ensure this is not null
2866                          * and then we can call the method directly.
2867                          */
2868 #ifndef DISABLE_REMOTING
2869                         if (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) {
2870                                 /* 
2871                                  * The check above ensures method is not gshared, this is needed since
2872                                  * gshared methods can't have wrappers.
2873                                  */
2874                                 method = call->method = mono_marshal_get_remoting_invoke_with_check (method);
2875                         }
2876 #endif
2877
2878                         if (!method->string_ctor)
2879                                 MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2880
2881                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2882                 } else if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && MONO_METHOD_IS_FINAL (method)) {
2883                         /*
2884                          * the method is virtual, but we can statically dispatch since either
2885                          * it's class or the method itself are sealed.
2886                          * But first we need to ensure it's not a null reference.
2887                          */
2888                         MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2889
2890                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2891                 } else if (call_target) {
2892                         vtable_reg = alloc_preg (cfg);
2893                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2894
2895                         call->inst.opcode = callvirt_to_call_reg (call->inst.opcode);
2896                         call->inst.sreg1 = call_target->dreg;
2897                         call->inst.flags &= !MONO_INST_HAS_METHOD;
2898                 } else {
2899                         vtable_reg = alloc_preg (cfg);
2900                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2901                         if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2902                                 guint32 imt_slot = mono_method_get_imt_slot (method);
2903                                 emit_imt_argument (cfg, call, call->method, imt_arg);
2904                                 slot_reg = vtable_reg;
2905                                 offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
2906                         } else {
2907                                 slot_reg = vtable_reg;
2908                                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) +
2909                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
2910                                 if (imt_arg) {
2911                                         g_assert (mono_method_signature (method)->generic_param_count);
2912                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2913                                 }
2914                         }
2915
2916                         call->inst.sreg1 = slot_reg;
2917                         call->inst.inst_offset = offset;
2918                         call->is_virtual = TRUE;
2919                 }
2920         }
2921
2922         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2923
2924         if (rgctx_arg)
2925                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2926
2927         return (MonoInst*)call;
2928 }
2929
2930 MonoInst*
2931 mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoInst **args, MonoInst *this_ins)
2932 {
2933         return mono_emit_method_call_full (cfg, method, mono_method_signature (method), FALSE, args, this_ins, NULL, NULL);
2934 }
2935
2936 MonoInst*
2937 mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig,
2938                                            MonoInst **args)
2939 {
2940         MonoCallInst *call;
2941
2942         g_assert (sig);
2943
2944         call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE, FALSE, FALSE);
2945         call->fptr = func;
2946
2947         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2948
2949         return (MonoInst*)call;
2950 }
2951
2952 MonoInst*
2953 mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args)
2954 {
2955         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2956
2957         g_assert (info);
2958
2959         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2960 }
2961
2962 /*
2963  * mono_emit_abs_call:
2964  *
2965  *   Emit a call to the runtime function described by PATCH_TYPE and DATA.
2966  */
2967 inline static MonoInst*
2968 mono_emit_abs_call (MonoCompile *cfg, MonoJumpInfoType patch_type, gconstpointer data, 
2969                                         MonoMethodSignature *sig, MonoInst **args)
2970 {
2971         MonoJumpInfo *ji = mono_patch_info_new (cfg->mempool, 0, patch_type, data);
2972         MonoInst *ins;
2973
2974         /* 
2975          * We pass ji as the call address, the PATCH_INFO_ABS resolving code will
2976          * handle it.
2977          */
2978         if (cfg->abs_patches == NULL)
2979                 cfg->abs_patches = g_hash_table_new (NULL, NULL);
2980         g_hash_table_insert (cfg->abs_patches, ji, ji);
2981         ins = mono_emit_native_call (cfg, ji, sig, args);
2982         ((MonoCallInst*)ins)->fptr_is_patch = TRUE;
2983         return ins;
2984 }
2985
2986 static MonoMethodSignature*
2987 sig_to_rgctx_sig (MonoMethodSignature *sig)
2988 {
2989         // FIXME: memory allocation
2990         MonoMethodSignature *res;
2991         int i;
2992
2993         res = (MonoMethodSignature *)g_malloc (MONO_SIZEOF_METHOD_SIGNATURE + (sig->param_count + 1) * sizeof (MonoType*));
2994         memcpy (res, sig, MONO_SIZEOF_METHOD_SIGNATURE);
2995         res->param_count = sig->param_count + 1;
2996         for (i = 0; i < sig->param_count; ++i)
2997                 res->params [i] = sig->params [i];
2998         res->params [sig->param_count] = &mono_defaults.int_class->this_arg;
2999         return res;
3000 }
3001
3002 /* Make an indirect call to FSIG passing an additional argument */
3003 static MonoInst*
3004 emit_extra_arg_calli (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **orig_args, int arg_reg, MonoInst *call_target)
3005 {
3006         MonoMethodSignature *csig;
3007         MonoInst *args_buf [16];
3008         MonoInst **args;
3009         int i, pindex, tmp_reg;
3010
3011         /* Make a call with an rgctx/extra arg */
3012         if (fsig->param_count + 2 < 16)
3013                 args = args_buf;
3014         else
3015                 args = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (fsig->param_count + 2));
3016         pindex = 0;
3017         if (fsig->hasthis)
3018                 args [pindex ++] = orig_args [0];
3019         for (i = 0; i < fsig->param_count; ++i)
3020                 args [pindex ++] = orig_args [fsig->hasthis + i];
3021         tmp_reg = alloc_preg (cfg);
3022         EMIT_NEW_UNALU (cfg, args [pindex], OP_MOVE, tmp_reg, arg_reg);
3023         csig = sig_to_rgctx_sig (fsig);
3024         return mono_emit_calli (cfg, csig, args, call_target, NULL, NULL);
3025 }
3026
3027 /* Emit an indirect call to the function descriptor ADDR */
3028 static MonoInst*
3029 emit_llvmonly_calli (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, MonoInst *addr)
3030 {
3031         int addr_reg, arg_reg;
3032         MonoInst *call_target;
3033
3034         g_assert (cfg->llvm_only);
3035
3036         /*
3037          * addr points to a <addr, arg> pair, load both of them, and
3038          * make a call to addr, passing arg as an extra arg.
3039          */
3040         addr_reg = alloc_preg (cfg);
3041         EMIT_NEW_LOAD_MEMBASE (cfg, call_target, OP_LOAD_MEMBASE, addr_reg, addr->dreg, 0);
3042         arg_reg = alloc_preg (cfg);
3043         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, arg_reg, addr->dreg, sizeof (gpointer));
3044
3045         return emit_extra_arg_calli (cfg, fsig, args, arg_reg, call_target);
3046 }
3047
3048 static gboolean
3049 direct_icalls_enabled (MonoCompile *cfg)
3050 {
3051         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
3052 #ifdef TARGET_AMD64
3053         if (cfg->compile_llvm)
3054                 return FALSE;
3055 #endif
3056         if (cfg->gen_sdb_seq_points || cfg->disable_direct_icalls)
3057                 return FALSE;
3058         return TRUE;
3059 }
3060
3061 MonoInst*
3062 mono_emit_jit_icall_by_info (MonoCompile *cfg, MonoJitICallInfo *info, MonoInst **args)
3063 {
3064         /*
3065          * Call the jit icall without a wrapper if possible.
3066          * The wrapper is needed for the following reasons:
3067          * - to handle exceptions thrown using mono_raise_exceptions () from the
3068          *   icall function. The EH code needs the lmf frame pushed by the
3069          *   wrapper to be able to unwind back to managed code.
3070          * - to be able to do stack walks for asynchronously suspended
3071          *   threads when debugging.
3072          */
3073         if (info->no_raise && direct_icalls_enabled (cfg)) {
3074                 char *name;
3075                 int costs;
3076
3077                 if (!info->wrapper_method) {
3078                         name = g_strdup_printf ("__icall_wrapper_%s", info->name);
3079                         info->wrapper_method = mono_marshal_get_icall_wrapper (info->sig, name, info->func, TRUE);
3080                         g_free (name);
3081                         mono_memory_barrier ();
3082                 }
3083
3084                 /*
3085                  * Inline the wrapper method, which is basically a call to the C icall, and
3086                  * an exception check.
3087                  */
3088                 costs = inline_method (cfg, info->wrapper_method, NULL,
3089                                                            args, NULL, cfg->real_offset, TRUE);
3090                 g_assert (costs > 0);
3091                 g_assert (!MONO_TYPE_IS_VOID (info->sig->ret));
3092
3093                 return args [0];
3094         } else {
3095                 return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
3096         }
3097 }
3098  
3099 static MonoInst*
3100 mono_emit_widen_call_res (MonoCompile *cfg, MonoInst *ins, MonoMethodSignature *fsig)
3101 {
3102         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
3103                 if ((fsig->pinvoke || LLVM_ENABLED) && !fsig->ret->byref) {
3104                         int widen_op = -1;
3105
3106                         /* 
3107                          * Native code might return non register sized integers 
3108                          * without initializing the upper bits.
3109                          */
3110                         switch (mono_type_to_load_membase (cfg, fsig->ret)) {
3111                         case OP_LOADI1_MEMBASE:
3112                                 widen_op = OP_ICONV_TO_I1;
3113                                 break;
3114                         case OP_LOADU1_MEMBASE:
3115                                 widen_op = OP_ICONV_TO_U1;
3116                                 break;
3117                         case OP_LOADI2_MEMBASE:
3118                                 widen_op = OP_ICONV_TO_I2;
3119                                 break;
3120                         case OP_LOADU2_MEMBASE:
3121                                 widen_op = OP_ICONV_TO_U2;
3122                                 break;
3123                         default:
3124                                 break;
3125                         }
3126
3127                         if (widen_op != -1) {
3128                                 int dreg = alloc_preg (cfg);
3129                                 MonoInst *widen;
3130
3131                                 EMIT_NEW_UNALU (cfg, widen, widen_op, dreg, ins->dreg);
3132                                 widen->type = ins->type;
3133                                 ins = widen;
3134                         }
3135                 }
3136         }
3137
3138         return ins;
3139 }
3140
3141 static MonoMethod*
3142 get_memcpy_method (void)
3143 {
3144         static MonoMethod *memcpy_method = NULL;
3145         if (!memcpy_method) {
3146                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
3147                 if (!memcpy_method)
3148                         g_error ("Old corlib found. Install a new one");
3149         }
3150         return memcpy_method;
3151 }
3152
3153 static void
3154 create_write_barrier_bitmap (MonoCompile *cfg, MonoClass *klass, unsigned *wb_bitmap, int offset)
3155 {
3156         MonoClassField *field;
3157         gpointer iter = NULL;
3158
3159         while ((field = mono_class_get_fields (klass, &iter))) {
3160                 int foffset;
3161
3162                 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3163                         continue;
3164                 foffset = klass->valuetype ? field->offset - sizeof (MonoObject): field->offset;
3165                 if (mini_type_is_reference (mono_field_get_type (field))) {
3166                         g_assert ((foffset % SIZEOF_VOID_P) == 0);
3167                         *wb_bitmap |= 1 << ((offset + foffset) / SIZEOF_VOID_P);
3168                 } else {
3169                         MonoClass *field_class = mono_class_from_mono_type (field->type);
3170                         if (field_class->has_references)
3171                                 create_write_barrier_bitmap (cfg, field_class, wb_bitmap, offset + foffset);
3172                 }
3173         }
3174 }
3175
3176 static void
3177 emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value)
3178 {
3179         int card_table_shift_bits;
3180         gpointer card_table_mask;
3181         guint8 *card_table;
3182         MonoInst *dummy_use;
3183         int nursery_shift_bits;
3184         size_t nursery_size;
3185
3186         if (!cfg->gen_write_barriers)
3187                 return;
3188
3189         card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
3190
3191         mono_gc_get_nursery (&nursery_shift_bits, &nursery_size);
3192
3193         if (cfg->backend->have_card_table_wb && !cfg->compile_aot && card_table && nursery_shift_bits > 0 && !COMPILE_LLVM (cfg)) {
3194                 MonoInst *wbarrier;
3195
3196                 MONO_INST_NEW (cfg, wbarrier, OP_CARD_TABLE_WBARRIER);
3197                 wbarrier->sreg1 = ptr->dreg;
3198                 wbarrier->sreg2 = value->dreg;
3199                 MONO_ADD_INS (cfg->cbb, wbarrier);
3200         } else if (card_table && !cfg->compile_aot && !mono_gc_card_table_nursery_check ()) {
3201                 int offset_reg = alloc_preg (cfg);
3202                 int card_reg;
3203                 MonoInst *ins;
3204
3205                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, offset_reg, ptr->dreg, card_table_shift_bits);
3206                 if (card_table_mask)
3207                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, offset_reg, offset_reg, card_table_mask);
3208
3209                 /*We can't use PADD_IMM since the cardtable might end up in high addresses and amd64 doesn't support
3210                  * IMM's larger than 32bits.
3211                  */
3212                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
3213                 card_reg = ins->dreg;
3214
3215                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, offset_reg, offset_reg, card_reg);
3216                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, offset_reg, 0, 1);
3217         } else {
3218                 MonoMethod *write_barrier = mono_gc_get_write_barrier ();
3219                 mono_emit_method_call (cfg, write_barrier, &ptr, NULL);
3220         }
3221
3222         EMIT_NEW_DUMMY_USE (cfg, dummy_use, value);
3223 }
3224
3225 static gboolean
3226 mono_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align)
3227 {
3228         int dest_ptr_reg, tmp_reg, destreg, srcreg, offset;
3229         unsigned need_wb = 0;
3230
3231         if (align == 0)
3232                 align = 4;
3233
3234         /*types with references can't have alignment smaller than sizeof(void*) */
3235         if (align < SIZEOF_VOID_P)
3236                 return FALSE;
3237
3238         /*This value cannot be bigger than 32 due to the way we calculate the required wb bitmap.*/
3239         if (size > 32 * SIZEOF_VOID_P)
3240                 return FALSE;
3241
3242         create_write_barrier_bitmap (cfg, klass, &need_wb, 0);
3243
3244         /* We don't unroll more than 5 stores to avoid code bloat. */
3245         if (size > 5 * SIZEOF_VOID_P) {
3246                 /*This is harmless and simplify mono_gc_wbarrier_value_copy_bitmap */
3247                 size += (SIZEOF_VOID_P - 1);
3248                 size &= ~(SIZEOF_VOID_P - 1);
3249
3250                 EMIT_NEW_ICONST (cfg, iargs [2], size);
3251                 EMIT_NEW_ICONST (cfg, iargs [3], need_wb);
3252                 mono_emit_jit_icall (cfg, mono_gc_wbarrier_value_copy_bitmap, iargs);
3253                 return TRUE;
3254         }
3255
3256         destreg = iargs [0]->dreg;
3257         srcreg = iargs [1]->dreg;
3258         offset = 0;
3259
3260         dest_ptr_reg = alloc_preg (cfg);
3261         tmp_reg = alloc_preg (cfg);
3262
3263         /*tmp = dreg*/
3264         EMIT_NEW_UNALU (cfg, iargs [0], OP_MOVE, dest_ptr_reg, destreg);
3265
3266         while (size >= SIZEOF_VOID_P) {
3267                 MonoInst *load_inst;
3268                 MONO_INST_NEW (cfg, load_inst, OP_LOAD_MEMBASE);
3269                 load_inst->dreg = tmp_reg;
3270                 load_inst->inst_basereg = srcreg;
3271                 load_inst->inst_offset = offset;
3272                 MONO_ADD_INS (cfg->cbb, load_inst);
3273
3274                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, dest_ptr_reg, 0, tmp_reg);
3275
3276                 if (need_wb & 0x1)
3277                         emit_write_barrier (cfg, iargs [0], load_inst);
3278
3279                 offset += SIZEOF_VOID_P;
3280                 size -= SIZEOF_VOID_P;
3281                 need_wb >>= 1;
3282
3283                 /*tmp += sizeof (void*)*/
3284                 if (size >= SIZEOF_VOID_P) {
3285                         NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dest_ptr_reg, dest_ptr_reg, SIZEOF_VOID_P);
3286                         MONO_ADD_INS (cfg->cbb, iargs [0]);
3287                 }
3288         }
3289
3290         /* Those cannot be references since size < sizeof (void*) */
3291         while (size >= 4) {
3292                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tmp_reg, srcreg, offset);
3293                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, tmp_reg);
3294                 offset += 4;
3295                 size -= 4;
3296         }
3297
3298         while (size >= 2) {
3299                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmp_reg, srcreg, offset);
3300                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, tmp_reg);
3301                 offset += 2;
3302                 size -= 2;
3303         }
3304
3305         while (size >= 1) {
3306                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmp_reg, srcreg, offset);
3307                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, tmp_reg);
3308                 offset += 1;
3309                 size -= 1;
3310         }
3311
3312         return TRUE;
3313 }
3314
3315 /*
3316  * Emit code to copy a valuetype of type @klass whose address is stored in
3317  * @src->dreg to memory whose address is stored at @dest->dreg.
3318  */
3319 void
3320 mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native)
3321 {
3322         MonoInst *iargs [4];
3323         int n;
3324         guint32 align = 0;
3325         MonoMethod *memcpy_method;
3326         MonoInst *size_ins = NULL;
3327         MonoInst *memcpy_ins = NULL;
3328
3329         g_assert (klass);
3330         if (cfg->gshared)
3331                 klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg));
3332
3333         /*
3334          * This check breaks with spilled vars... need to handle it during verification anyway.
3335          * g_assert (klass && klass == src->klass && klass == dest->klass);
3336          */
3337
3338         if (mini_is_gsharedvt_klass (klass)) {
3339                 g_assert (!native);
3340                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3341                 memcpy_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_MEMCPY);
3342         }
3343
3344         if (native)
3345                 n = mono_class_native_size (klass, &align);
3346         else
3347                 n = mono_class_value_size (klass, &align);
3348
3349         /* if native is true there should be no references in the struct */
3350         if (cfg->gen_write_barriers && (klass->has_references || size_ins) && !native) {
3351                 /* Avoid barriers when storing to the stack */
3352                 if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) ||
3353                           (dest->opcode == OP_LDADDR))) {
3354                         int context_used;
3355
3356                         iargs [0] = dest;
3357                         iargs [1] = src;
3358
3359                         context_used = mini_class_check_context_used (cfg, klass);
3360
3361                         /* It's ok to intrinsify under gsharing since shared code types are layout stable. */
3362                         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && mono_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
3363                                 return;
3364                         } else if (context_used) {
3365                                 iargs [2] = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3366                         }  else {
3367                                 iargs [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
3368                                 if (!cfg->compile_aot)
3369                                         mono_class_compute_gc_descriptor (klass);
3370                         }
3371
3372                         if (size_ins)
3373                                 mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs);
3374                         else
3375                                 mono_emit_jit_icall (cfg, mono_value_copy, iargs);
3376                         return;
3377                 }
3378         }
3379
3380         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 8) {
3381                 /* FIXME: Optimize the case when src/dest is OP_LDADDR */
3382                 mini_emit_memcpy (cfg, dest->dreg, 0, src->dreg, 0, n, align);
3383         } else {
3384                 iargs [0] = dest;
3385                 iargs [1] = src;
3386                 if (size_ins)
3387                         iargs [2] = size_ins;
3388                 else
3389                         EMIT_NEW_ICONST (cfg, iargs [2], n);
3390                 
3391                 memcpy_method = get_memcpy_method ();
3392                 if (memcpy_ins)
3393                         mono_emit_calli (cfg, mono_method_signature (memcpy_method), iargs, memcpy_ins, NULL, NULL);
3394                 else
3395                         mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
3396         }
3397 }
3398
3399 static MonoMethod*
3400 get_memset_method (void)
3401 {
3402         static MonoMethod *memset_method = NULL;
3403         if (!memset_method) {
3404                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
3405                 if (!memset_method)
3406                         g_error ("Old corlib found. Install a new one");
3407         }
3408         return memset_method;
3409 }
3410
3411 void
3412 mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass)
3413 {
3414         MonoInst *iargs [3];
3415         int n;
3416         guint32 align;
3417         MonoMethod *memset_method;
3418         MonoInst *size_ins = NULL;
3419         MonoInst *bzero_ins = NULL;
3420         static MonoMethod *bzero_method;
3421
3422         /* FIXME: Optimize this for the case when dest is an LDADDR */
3423         mono_class_init (klass);
3424         if (mini_is_gsharedvt_klass (klass)) {
3425                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3426                 bzero_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_BZERO);
3427                 if (!bzero_method)
3428                         bzero_method = mono_class_get_method_from_name (mono_defaults.string_class, "bzero_aligned_1", 2);
3429                 g_assert (bzero_method);
3430                 iargs [0] = dest;
3431                 iargs [1] = size_ins;
3432                 mono_emit_calli (cfg, mono_method_signature (bzero_method), iargs, bzero_ins, NULL, NULL);
3433                 return;
3434         }
3435
3436         klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg));
3437
3438         n = mono_class_value_size (klass, &align);
3439
3440         if (n <= sizeof (gpointer) * 8) {
3441                 mini_emit_memset (cfg, dest->dreg, 0, n, 0, align);
3442         }
3443         else {
3444                 memset_method = get_memset_method ();
3445                 iargs [0] = dest;
3446                 EMIT_NEW_ICONST (cfg, iargs [1], 0);
3447                 EMIT_NEW_ICONST (cfg, iargs [2], n);
3448                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
3449         }
3450 }
3451
3452 /*
3453  * emit_get_rgctx:
3454  *
3455  *   Emit IR to return either the this pointer for instance method,
3456  * or the mrgctx for static methods.
3457  */
3458 static MonoInst*
3459 emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used)
3460 {
3461         MonoInst *this_ins = NULL;
3462
3463         g_assert (cfg->gshared);
3464
3465         if (!(method->flags & METHOD_ATTRIBUTE_STATIC) &&
3466                         !(context_used & MONO_GENERIC_CONTEXT_USED_METHOD) &&
3467                         !method->klass->valuetype)
3468                 EMIT_NEW_ARGLOAD (cfg, this_ins, 0);
3469
3470         if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
3471                 MonoInst *mrgctx_loc, *mrgctx_var;
3472
3473                 g_assert (!this_ins);
3474                 g_assert (method->is_inflated && mono_method_get_context (method)->method_inst);
3475
3476                 mrgctx_loc = mono_get_vtable_var (cfg);
3477                 EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
3478
3479                 return mrgctx_var;
3480         } else if (method->flags & METHOD_ATTRIBUTE_STATIC || method->klass->valuetype) {
3481                 MonoInst *vtable_loc, *vtable_var;
3482
3483                 g_assert (!this_ins);
3484
3485                 vtable_loc = mono_get_vtable_var (cfg);
3486                 EMIT_NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
3487
3488                 if (method->is_inflated && mono_method_get_context (method)->method_inst) {
3489                         MonoInst *mrgctx_var = vtable_var;
3490                         int vtable_reg;
3491
3492                         vtable_reg = alloc_preg (cfg);
3493                         EMIT_NEW_LOAD_MEMBASE (cfg, vtable_var, OP_LOAD_MEMBASE, vtable_reg, mrgctx_var->dreg, MONO_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, class_vtable));
3494                         vtable_var->type = STACK_PTR;
3495                 }
3496
3497                 return vtable_var;
3498         } else {
3499                 MonoInst *ins;
3500                 int vtable_reg;
3501         
3502                 vtable_reg = alloc_preg (cfg);
3503                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, vtable_reg, this_ins->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3504                 return ins;
3505         }
3506 }
3507
3508 static MonoJumpInfoRgctxEntry *
3509 mono_patch_info_rgctx_entry_new (MonoMemPool *mp, MonoMethod *method, gboolean in_mrgctx, MonoJumpInfoType patch_type, gconstpointer patch_data, MonoRgctxInfoType info_type)
3510 {
3511         MonoJumpInfoRgctxEntry *res = (MonoJumpInfoRgctxEntry *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoRgctxEntry));
3512         res->method = method;
3513         res->in_mrgctx = in_mrgctx;
3514         res->data = (MonoJumpInfo *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
3515         res->data->type = patch_type;
3516         res->data->data.target = patch_data;
3517         res->info_type = info_type;
3518
3519         return res;
3520 }
3521
3522 static inline MonoInst*
3523 emit_rgctx_fetch_inline (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3524 {
3525         MonoInst *args [16];
3526         MonoInst *call;
3527
3528         // FIXME: No fastpath since the slot is not a compile time constant
3529         args [0] = rgctx;
3530         EMIT_NEW_AOTCONST (cfg, args [1], MONO_PATCH_INFO_RGCTX_SLOT_INDEX, entry);
3531         if (entry->in_mrgctx)
3532                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3533         else
3534                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3535         return call;
3536 #if 0
3537         /*
3538          * FIXME: This can be called during decompose, which is a problem since it creates
3539          * new bblocks.
3540          * Also, the fastpath doesn't work since the slot number is dynamically allocated.
3541          */
3542         int i, slot, depth, index, rgctx_reg, val_reg, res_reg;
3543         gboolean mrgctx;
3544         MonoBasicBlock *is_null_bb, *end_bb;
3545         MonoInst *res, *ins, *call;
3546         MonoInst *args[16];
3547
3548         slot = mini_get_rgctx_entry_slot (entry);
3549
3550         mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot);
3551         index = MONO_RGCTX_SLOT_INDEX (slot);
3552         if (mrgctx)
3553                 index += MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
3554         for (depth = 0; ; ++depth) {
3555                 int size = mono_class_rgctx_get_array_size (depth, mrgctx);
3556
3557                 if (index < size - 1)
3558                         break;
3559                 index -= size - 1;
3560         }
3561
3562         NEW_BBLOCK (cfg, end_bb);
3563         NEW_BBLOCK (cfg, is_null_bb);
3564
3565         if (mrgctx) {
3566                 rgctx_reg = rgctx->dreg;
3567         } else {
3568                 rgctx_reg = alloc_preg (cfg);
3569
3570                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, rgctx_reg, rgctx->dreg, MONO_STRUCT_OFFSET (MonoVTable, runtime_generic_context));
3571                 // FIXME: Avoid this check by allocating the table when the vtable is created etc.
3572                 NEW_BBLOCK (cfg, is_null_bb);
3573
3574                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3575                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3576         }
3577
3578         for (i = 0; i < depth; ++i) {
3579                 int array_reg = alloc_preg (cfg);
3580
3581                 /* load ptr to next array */
3582                 if (mrgctx && i == 0)
3583                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT);
3584                 else
3585                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, 0);
3586                 rgctx_reg = array_reg;
3587                 /* is the ptr null? */
3588                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3589                 /* if yes, jump to actual trampoline */
3590                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3591         }
3592
3593         /* fetch slot */
3594         val_reg = alloc_preg (cfg);
3595         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, val_reg, rgctx_reg, (index + 1) * sizeof (gpointer));
3596         /* is the slot null? */
3597         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, val_reg, 0);
3598         /* if yes, jump to actual trampoline */
3599         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3600
3601         /* Fastpath */
3602         res_reg = alloc_preg (cfg);
3603         MONO_INST_NEW (cfg, ins, OP_MOVE);
3604         ins->dreg = res_reg;
3605         ins->sreg1 = val_reg;
3606         MONO_ADD_INS (cfg->cbb, ins);
3607         res = ins;
3608         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3609
3610         /* Slowpath */
3611         MONO_START_BB (cfg, is_null_bb);
3612         args [0] = rgctx;
3613         EMIT_NEW_ICONST (cfg, args [1], index);
3614         if (mrgctx)
3615                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3616         else
3617                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3618         MONO_INST_NEW (cfg, ins, OP_MOVE);
3619         ins->dreg = res_reg;
3620         ins->sreg1 = call->dreg;
3621         MONO_ADD_INS (cfg->cbb, ins);
3622         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3623
3624         MONO_START_BB (cfg, end_bb);
3625
3626         return res;
3627 #endif
3628 }
3629
3630 /*
3631  * emit_rgctx_fetch:
3632  *
3633  *   Emit IR to load the value of the rgctx entry ENTRY from the rgctx
3634  * given by RGCTX.
3635  */
3636 static inline MonoInst*
3637 emit_rgctx_fetch (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3638 {
3639         if (cfg->llvm_only)
3640                 return emit_rgctx_fetch_inline (cfg, rgctx, entry);
3641         else
3642                 return mono_emit_abs_call (cfg, MONO_PATCH_INFO_RGCTX_FETCH, entry, helper_sig_rgctx_lazy_fetch_trampoline, &rgctx);
3643 }
3644
3645 static MonoInst*
3646 emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
3647                                           MonoClass *klass, MonoRgctxInfoType rgctx_type)
3648 {
3649         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);
3650         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3651
3652         return emit_rgctx_fetch (cfg, rgctx, entry);
3653 }
3654
3655 static MonoInst*
3656 emit_get_rgctx_sig (MonoCompile *cfg, int context_used,
3657                                         MonoMethodSignature *sig, MonoRgctxInfoType rgctx_type)
3658 {
3659         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);
3660         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3661
3662         return emit_rgctx_fetch (cfg, rgctx, entry);
3663 }
3664
3665 static MonoInst*
3666 emit_get_rgctx_gsharedvt_call (MonoCompile *cfg, int context_used,
3667                                                            MonoMethodSignature *sig, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3668 {
3669         MonoJumpInfoGSharedVtCall *call_info;
3670         MonoJumpInfoRgctxEntry *entry;
3671         MonoInst *rgctx;
3672
3673         call_info = (MonoJumpInfoGSharedVtCall *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoGSharedVtCall));
3674         call_info->sig = sig;
3675         call_info->method = cmethod;
3676
3677         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);
3678         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3679
3680         return emit_rgctx_fetch (cfg, rgctx, entry);
3681 }
3682
3683 /*
3684  * emit_get_rgctx_virt_method:
3685  *
3686  *   Return data for method VIRT_METHOD for a receiver of type KLASS.
3687  */
3688 static MonoInst*
3689 emit_get_rgctx_virt_method (MonoCompile *cfg, int context_used,
3690                                                         MonoClass *klass, MonoMethod *virt_method, MonoRgctxInfoType rgctx_type)
3691 {
3692         MonoJumpInfoVirtMethod *info;
3693         MonoJumpInfoRgctxEntry *entry;
3694         MonoInst *rgctx;
3695
3696         info = (MonoJumpInfoVirtMethod *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoVirtMethod));
3697         info->klass = klass;
3698         info->method = virt_method;
3699
3700         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);
3701         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3702
3703         return emit_rgctx_fetch (cfg, rgctx, entry);
3704 }
3705
3706 static MonoInst*
3707 emit_get_rgctx_gsharedvt_method (MonoCompile *cfg, int context_used,
3708                                                                  MonoMethod *cmethod, MonoGSharedVtMethodInfo *info)
3709 {
3710         MonoJumpInfoRgctxEntry *entry;
3711         MonoInst *rgctx;
3712
3713         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);
3714         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3715
3716         return emit_rgctx_fetch (cfg, rgctx, entry);
3717 }
3718
3719 /*
3720  * emit_get_rgctx_method:
3721  *
3722  *   Emit IR to load the property RGCTX_TYPE of CMETHOD. If context_used is 0, emit
3723  * normal constants, else emit a load from the rgctx.
3724  */
3725 static MonoInst*
3726 emit_get_rgctx_method (MonoCompile *cfg, int context_used,
3727                                            MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3728 {
3729         if (!context_used) {
3730                 MonoInst *ins;
3731
3732                 switch (rgctx_type) {
3733                 case MONO_RGCTX_INFO_METHOD:
3734                         EMIT_NEW_METHODCONST (cfg, ins, cmethod);
3735                         return ins;
3736                 case MONO_RGCTX_INFO_METHOD_RGCTX:
3737                         EMIT_NEW_METHOD_RGCTX_CONST (cfg, ins, cmethod);
3738                         return ins;
3739                 default:
3740                         g_assert_not_reached ();
3741                 }
3742         } else {
3743                 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);
3744                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3745
3746                 return emit_rgctx_fetch (cfg, rgctx, entry);
3747         }
3748 }
3749
3750 static MonoInst*
3751 emit_get_rgctx_field (MonoCompile *cfg, int context_used,
3752                                           MonoClassField *field, MonoRgctxInfoType rgctx_type)
3753 {
3754         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);
3755         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3756
3757         return emit_rgctx_fetch (cfg, rgctx, entry);
3758 }
3759
3760 static int
3761 get_gsharedvt_info_slot (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3762 {
3763         MonoGSharedVtMethodInfo *info = cfg->gsharedvt_info;
3764         MonoRuntimeGenericContextInfoTemplate *template_;
3765         int i, idx;
3766
3767         g_assert (info);
3768
3769         for (i = 0; i < info->num_entries; ++i) {
3770                 MonoRuntimeGenericContextInfoTemplate *otemplate = &info->entries [i];
3771
3772                 if (otemplate->info_type == rgctx_type && otemplate->data == data && rgctx_type != MONO_RGCTX_INFO_LOCAL_OFFSET)
3773                         return i;
3774         }
3775
3776         if (info->num_entries == info->count_entries) {
3777                 MonoRuntimeGenericContextInfoTemplate *new_entries;
3778                 int new_count_entries = info->count_entries ? info->count_entries * 2 : 16;
3779
3780                 new_entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * new_count_entries);
3781
3782                 memcpy (new_entries, info->entries, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
3783                 info->entries = new_entries;
3784                 info->count_entries = new_count_entries;
3785         }
3786
3787         idx = info->num_entries;
3788         template_ = &info->entries [idx];
3789         template_->info_type = rgctx_type;
3790         template_->data = data;
3791
3792         info->num_entries ++;
3793
3794         return idx;
3795 }
3796
3797 /*
3798  * emit_get_gsharedvt_info:
3799  *
3800  *   This is similar to emit_get_rgctx_.., but loads the data from the gsharedvt info var instead of calling an rgctx fetch trampoline.
3801  */
3802 static MonoInst*
3803 emit_get_gsharedvt_info (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3804 {
3805         MonoInst *ins;
3806         int idx, dreg;
3807
3808         idx = get_gsharedvt_info_slot (cfg, data, rgctx_type);
3809         /* Load info->entries [idx] */
3810         dreg = alloc_preg (cfg);
3811         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, cfg->gsharedvt_info_var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
3812
3813         return ins;
3814 }
3815
3816 static MonoInst*
3817 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type)
3818 {
3819         return emit_get_gsharedvt_info (cfg, &klass->byval_arg, rgctx_type);
3820 }
3821
3822 /*
3823  * On return the caller must check @klass for load errors.
3824  */
3825 static void
3826 emit_class_init (MonoCompile *cfg, MonoClass *klass)
3827 {
3828         MonoInst *vtable_arg;
3829         int context_used;
3830
3831         context_used = mini_class_check_context_used (cfg, klass);
3832
3833         if (context_used) {
3834                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
3835                                                                                    klass, MONO_RGCTX_INFO_VTABLE);
3836         } else {
3837                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3838
3839                 if (!vtable)
3840                         return;
3841                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
3842         }
3843
3844         if (!COMPILE_LLVM (cfg) && cfg->backend->have_op_generic_class_init) {
3845                 MonoInst *ins;
3846
3847                 /*
3848                  * Using an opcode instead of emitting IR here allows the hiding of the call inside the opcode,
3849                  * so this doesn't have to clobber any regs and it doesn't break basic blocks.
3850                  */
3851                 MONO_INST_NEW (cfg, ins, OP_GENERIC_CLASS_INIT);
3852                 ins->sreg1 = vtable_arg->dreg;
3853                 MONO_ADD_INS (cfg->cbb, ins);
3854         } else {
3855                 static int byte_offset = -1;
3856                 static guint8 bitmask;
3857                 int bits_reg, inited_reg;
3858                 MonoBasicBlock *inited_bb;
3859                 MonoInst *args [16];
3860
3861                 if (byte_offset < 0)
3862                         mono_marshal_find_bitfield_offset (MonoVTable, initialized, &byte_offset, &bitmask);
3863
3864                 bits_reg = alloc_ireg (cfg);
3865                 inited_reg = alloc_ireg (cfg);
3866
3867                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, bits_reg, vtable_arg->dreg, byte_offset);
3868                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, inited_reg, bits_reg, bitmask);
3869
3870                 NEW_BBLOCK (cfg, inited_bb);
3871
3872                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, inited_reg, 0);
3873                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, inited_bb);
3874
3875                 args [0] = vtable_arg;
3876                 mono_emit_jit_icall (cfg, mono_generic_class_init, args);
3877
3878                 MONO_START_BB (cfg, inited_bb);
3879         }
3880 }
3881
3882 static void
3883 emit_seq_point (MonoCompile *cfg, MonoMethod *method, guint8* ip, gboolean intr_loc, gboolean nonempty_stack)
3884 {
3885         MonoInst *ins;
3886
3887         if (cfg->gen_seq_points && cfg->method == method) {
3888                 NEW_SEQ_POINT (cfg, ins, ip - cfg->header->code, intr_loc);
3889                 if (nonempty_stack)
3890                         ins->flags |= MONO_INST_NONEMPTY_STACK;
3891                 MONO_ADD_INS (cfg->cbb, ins);
3892         }
3893 }
3894
3895 static void
3896 save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean null_check)
3897 {
3898         if (mini_get_debug_options ()->better_cast_details) {
3899                 int vtable_reg = alloc_preg (cfg);
3900                 int klass_reg = alloc_preg (cfg);
3901                 MonoBasicBlock *is_null_bb = NULL;
3902                 MonoInst *tls_get;
3903                 int to_klass_reg, context_used;
3904
3905                 if (null_check) {
3906                         NEW_BBLOCK (cfg, is_null_bb);
3907
3908                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3909                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3910                 }
3911
3912                 tls_get = mono_get_jit_tls_intrinsic (cfg);
3913                 if (!tls_get) {
3914                         fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
3915                         exit (1);
3916                 }
3917
3918                 MONO_ADD_INS (cfg->cbb, tls_get);
3919                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3920                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3921
3922                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg);
3923
3924                 context_used = mini_class_check_context_used (cfg, klass);
3925                 if (context_used) {
3926                         MonoInst *class_ins;
3927
3928                         class_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3929                         to_klass_reg = class_ins->dreg;
3930                 } else {
3931                         to_klass_reg = alloc_preg (cfg);
3932                         MONO_EMIT_NEW_CLASSCONST (cfg, to_klass_reg, klass);
3933                 }
3934                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg);
3935
3936                 if (null_check)
3937                         MONO_START_BB (cfg, is_null_bb);
3938         }
3939 }
3940
3941 static void
3942 reset_cast_details (MonoCompile *cfg)
3943 {
3944         /* Reset the variables holding the cast details */
3945         if (mini_get_debug_options ()->better_cast_details) {
3946                 MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
3947
3948                 MONO_ADD_INS (cfg->cbb, tls_get);
3949                 /* It is enough to reset the from field */
3950                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0);
3951         }
3952 }
3953
3954 /*
3955  * On return the caller must check @array_class for load errors
3956  */
3957 static void
3958 mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_class)
3959 {
3960         int vtable_reg = alloc_preg (cfg);
3961         int context_used;
3962
3963         context_used = mini_class_check_context_used (cfg, array_class);
3964
3965         save_cast_details (cfg, array_class, obj->dreg, FALSE);
3966
3967         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3968
3969         if (cfg->opt & MONO_OPT_SHARED) {
3970                 int class_reg = alloc_preg (cfg);
3971                 MonoInst *ins;
3972
3973                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, class_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3974                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, array_class);
3975                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, class_reg, ins->dreg);
3976         } else if (context_used) {
3977                 MonoInst *vtable_ins;
3978
3979                 vtable_ins = emit_get_rgctx_klass (cfg, context_used, array_class, MONO_RGCTX_INFO_VTABLE);
3980                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vtable_ins->dreg);
3981         } else {
3982                 if (cfg->compile_aot) {
3983                         int vt_reg;
3984                         MonoVTable *vtable;
3985
3986                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3987                                 return;
3988                         vt_reg = alloc_preg (cfg);
3989                         MONO_EMIT_NEW_VTABLECONST (cfg, vt_reg, vtable);
3990                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vt_reg);
3991                 } else {
3992                         MonoVTable *vtable;
3993                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3994                                 return;
3995                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vtable);
3996                 }
3997         }
3998         
3999         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException");
4000
4001         reset_cast_details (cfg);
4002 }
4003
4004 /**
4005  * Handles unbox of a Nullable<T>. If context_used is non zero, then shared 
4006  * generic code is generated.
4007  */
4008 static MonoInst*
4009 handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int context_used)
4010 {
4011         MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
4012
4013         if (context_used) {
4014                 MonoInst *rgctx, *addr;
4015
4016                 /* FIXME: What if the class is shared?  We might not
4017                    have to get the address of the method from the
4018                    RGCTX. */
4019                 addr = emit_get_rgctx_method (cfg, context_used, method,
4020                                                                           MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4021                 if (cfg->llvm_only && cfg->gsharedvt) {
4022                         return emit_llvmonly_calli (cfg, mono_method_signature (method), &val, addr);
4023                 } else {
4024                         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
4025
4026                         return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
4027                 }
4028         } else {
4029                 gboolean pass_vtable, pass_mrgctx;
4030                 MonoInst *rgctx_arg = NULL;
4031
4032                 check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
4033                 g_assert (!pass_mrgctx);
4034
4035                 if (pass_vtable) {
4036                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4037
4038                         g_assert (vtable);
4039                         EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
4040                 }
4041
4042                 return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4043         }
4044 }
4045
4046 static MonoInst*
4047 handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_used)
4048 {
4049         MonoInst *add;
4050         int obj_reg;
4051         int vtable_reg = alloc_dreg (cfg ,STACK_PTR);
4052         int klass_reg = alloc_dreg (cfg ,STACK_PTR);
4053         int eclass_reg = alloc_dreg (cfg ,STACK_PTR);
4054         int rank_reg = alloc_dreg (cfg ,STACK_I4);
4055
4056         obj_reg = sp [0]->dreg;
4057         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4058         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
4059
4060         /* FIXME: generics */
4061         g_assert (klass->rank == 0);
4062                         
4063         // Check rank == 0
4064         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, 0);
4065         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4066
4067         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4068         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, element_class));
4069
4070         if (context_used) {
4071                 MonoInst *element_class;
4072
4073                 /* This assertion is from the unboxcast insn */
4074                 g_assert (klass->rank == 0);
4075
4076                 element_class = emit_get_rgctx_klass (cfg, context_used,
4077                                 klass, MONO_RGCTX_INFO_ELEMENT_KLASS);
4078
4079                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, eclass_reg, element_class->dreg);
4080                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4081         } else {
4082                 save_cast_details (cfg, klass->element_class, obj_reg, FALSE);
4083                 mini_emit_class_check (cfg, eclass_reg, klass->element_class);
4084                 reset_cast_details (cfg);
4085         }
4086
4087         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), obj_reg, sizeof (MonoObject));
4088         MONO_ADD_INS (cfg->cbb, add);
4089         add->type = STACK_MP;
4090         add->klass = klass;
4091
4092         return add;
4093 }
4094
4095 static MonoInst*
4096 handle_unbox_gsharedvt (MonoCompile *cfg, MonoClass *klass, MonoInst *obj)
4097 {
4098         MonoInst *addr, *klass_inst, *is_ref, *args[16];
4099         MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4100         MonoInst *ins;
4101         int dreg, addr_reg;
4102
4103         klass_inst = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_KLASS);
4104
4105         /* obj */
4106         args [0] = obj;
4107
4108         /* klass */
4109         args [1] = klass_inst;
4110
4111         /* CASTCLASS */
4112         obj = mono_emit_jit_icall (cfg, mono_object_castclass_unbox, args);
4113
4114         NEW_BBLOCK (cfg, is_ref_bb);
4115         NEW_BBLOCK (cfg, is_nullable_bb);
4116         NEW_BBLOCK (cfg, end_bb);
4117         is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4118         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
4119         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4120
4121         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
4122         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4123
4124         /* This will contain either the address of the unboxed vtype, or an address of the temporary where the ref is stored */
4125         addr_reg = alloc_dreg (cfg, STACK_MP);
4126
4127         /* Non-ref case */
4128         /* UNBOX */
4129         NEW_BIALU_IMM (cfg, addr, OP_ADD_IMM, addr_reg, obj->dreg, sizeof (MonoObject));
4130         MONO_ADD_INS (cfg->cbb, addr);
4131
4132         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4133
4134         /* Ref case */
4135         MONO_START_BB (cfg, is_ref_bb);
4136
4137         /* Save the ref to a temporary */
4138         dreg = alloc_ireg (cfg);
4139         EMIT_NEW_VARLOADA_VREG (cfg, addr, dreg, &klass->byval_arg);
4140         addr->dreg = addr_reg;
4141         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, obj->dreg);
4142         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4143
4144         /* Nullable case */
4145         MONO_START_BB (cfg, is_nullable_bb);
4146
4147         {
4148                 MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX);
4149                 MonoInst *unbox_call;
4150                 MonoMethodSignature *unbox_sig;
4151
4152                 unbox_sig = (MonoMethodSignature *)mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4153                 unbox_sig->ret = &klass->byval_arg;
4154                 unbox_sig->param_count = 1;
4155                 unbox_sig->params [0] = &mono_defaults.object_class->byval_arg;
4156
4157                 if (cfg->llvm_only)
4158                         unbox_call = emit_llvmonly_calli (cfg, unbox_sig, &obj, addr);
4159                 else
4160                         unbox_call = mono_emit_calli (cfg, unbox_sig, &obj, addr, NULL, NULL);
4161
4162                 EMIT_NEW_VARLOADA_VREG (cfg, addr, unbox_call->dreg, &klass->byval_arg);
4163                 addr->dreg = addr_reg;
4164         }
4165
4166         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4167
4168         /* End */
4169         MONO_START_BB (cfg, end_bb);
4170
4171         /* LDOBJ */
4172         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr_reg, 0);
4173
4174         return ins;
4175 }
4176
4177 /*
4178  * Returns NULL and set the cfg exception on error.
4179  */
4180 static MonoInst*
4181 handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_used)
4182 {
4183         MonoInst *iargs [2];
4184         void *alloc_ftn;
4185
4186         if (context_used) {
4187                 MonoInst *data;
4188                 MonoRgctxInfoType rgctx_info;
4189                 MonoInst *iargs [2];
4190                 gboolean known_instance_size = !mini_is_gsharedvt_klass (klass);
4191
4192                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (klass, for_box, known_instance_size);
4193
4194                 if (cfg->opt & MONO_OPT_SHARED)
4195                         rgctx_info = MONO_RGCTX_INFO_KLASS;
4196                 else
4197                         rgctx_info = MONO_RGCTX_INFO_VTABLE;
4198                 data = emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
4199
4200                 if (cfg->opt & MONO_OPT_SHARED) {
4201                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4202                         iargs [1] = data;
4203                         alloc_ftn = ves_icall_object_new;
4204                 } else {
4205                         iargs [0] = data;
4206                         alloc_ftn = ves_icall_object_new_specific;
4207                 }
4208
4209                 if (managed_alloc && !(cfg->opt & MONO_OPT_SHARED)) {
4210                         if (known_instance_size) {
4211                                 int size = mono_class_instance_size (klass);
4212                                 if (size < sizeof (MonoObject))
4213                                         g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4214
4215                                 EMIT_NEW_ICONST (cfg, iargs [1], mono_gc_get_aligned_size_for_allocator (size));
4216                         }
4217                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4218                 }
4219
4220                 return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4221         }
4222
4223         if (cfg->opt & MONO_OPT_SHARED) {
4224                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4225                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
4226
4227                 alloc_ftn = ves_icall_object_new;
4228         } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !klass->generic_class) {
4229                 /* This happens often in argument checking code, eg. throw new FooException... */
4230                 /* Avoid relocations and save some space by calling a helper function specialized to mscorlib */
4231                 EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
4232                 return mono_emit_jit_icall (cfg, mono_helper_newobj_mscorlib, iargs);
4233         } else {
4234                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
4235                 MonoMethod *managed_alloc = NULL;
4236                 gboolean pass_lw;
4237
4238                 if (!vtable) {
4239                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4240                         cfg->exception_ptr = klass;
4241                         return NULL;
4242                 }
4243
4244                 managed_alloc = mono_gc_get_managed_allocator (klass, for_box, TRUE);
4245
4246                 if (managed_alloc) {
4247                         int size = mono_class_instance_size (klass);
4248                         if (size < sizeof (MonoObject))
4249                                 g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4250
4251                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4252                         EMIT_NEW_ICONST (cfg, iargs [1], mono_gc_get_aligned_size_for_allocator (size));
4253                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4254                 }
4255                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
4256                 if (pass_lw) {
4257                         guint32 lw = vtable->klass->instance_size;
4258                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
4259                         EMIT_NEW_ICONST (cfg, iargs [0], lw);
4260                         EMIT_NEW_VTABLECONST (cfg, iargs [1], vtable);
4261                 }
4262                 else {
4263                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4264                 }
4265         }
4266
4267         return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4268 }
4269         
4270 /*
4271  * Returns NULL and set the cfg exception on error.
4272  */     
4273 static MonoInst*
4274 handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used)
4275 {
4276         MonoInst *alloc, *ins;
4277
4278         if (mono_class_is_nullable (klass)) {
4279                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
4280
4281                 if (context_used) {
4282                         if (cfg->llvm_only && cfg->gsharedvt) {
4283                                 MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4284                                                                                                                 MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4285                                 return emit_llvmonly_calli (cfg, mono_method_signature (method), &val, addr);
4286                         } else {
4287                                 /* FIXME: What if the class is shared?  We might not
4288                                    have to get the method address from the RGCTX. */
4289                                 MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4290                                                                                                                 MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4291                                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
4292
4293                                 return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
4294                         }
4295                 } else {
4296                         gboolean pass_vtable, pass_mrgctx;
4297                         MonoInst *rgctx_arg = NULL;
4298
4299                         check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
4300                         g_assert (!pass_mrgctx);
4301
4302                         if (pass_vtable) {
4303                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4304
4305                                 g_assert (vtable);
4306                                 EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
4307                         }
4308
4309                         return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4310                 }
4311         }
4312
4313         if (mini_is_gsharedvt_klass (klass)) {
4314                 MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4315                 MonoInst *res, *is_ref, *src_var, *addr;
4316                 int dreg;
4317
4318                 dreg = alloc_ireg (cfg);
4319
4320                 NEW_BBLOCK (cfg, is_ref_bb);
4321                 NEW_BBLOCK (cfg, is_nullable_bb);
4322                 NEW_BBLOCK (cfg, end_bb);
4323                 is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4324                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
4325                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4326
4327                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
4328                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4329
4330                 /* Non-ref case */
4331                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4332                 if (!alloc)
4333                         return NULL;
4334                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4335                 ins->opcode = OP_STOREV_MEMBASE;
4336
4337                 EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, alloc->dreg);
4338                 res->type = STACK_OBJ;
4339                 res->klass = klass;
4340                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4341                 
4342                 /* Ref case */
4343                 MONO_START_BB (cfg, is_ref_bb);
4344
4345                 /* val is a vtype, so has to load the value manually */
4346                 src_var = get_vreg_to_inst (cfg, val->dreg);
4347                 if (!src_var)
4348                         src_var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, val->dreg);
4349                 EMIT_NEW_VARLOADA (cfg, addr, src_var, src_var->inst_vtype);
4350                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, addr->dreg, 0);
4351                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4352
4353                 /* Nullable case */
4354                 MONO_START_BB (cfg, is_nullable_bb);
4355
4356                 {
4357                         MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass,
4358                                                                                                         MONO_RGCTX_INFO_NULLABLE_CLASS_BOX);
4359                         MonoInst *box_call;
4360                         MonoMethodSignature *box_sig;
4361
4362                         /*
4363                          * klass is Nullable<T>, need to call Nullable<T>.Box () using a gsharedvt signature, but we cannot
4364                          * construct that method at JIT time, so have to do things by hand.
4365                          */
4366                         box_sig = (MonoMethodSignature *)mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4367                         box_sig->ret = &mono_defaults.object_class->byval_arg;
4368                         box_sig->param_count = 1;
4369                         box_sig->params [0] = &klass->byval_arg;
4370
4371                         if (cfg->llvm_only)
4372                                 box_call = emit_llvmonly_calli (cfg, box_sig, &val, addr);
4373                         else
4374                                 box_call = mono_emit_calli (cfg, box_sig, &val, addr, NULL, NULL);
4375                         EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, box_call->dreg);
4376                         res->type = STACK_OBJ;
4377                         res->klass = klass;
4378                 }
4379
4380                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4381
4382                 MONO_START_BB (cfg, end_bb);
4383
4384                 return res;
4385         } else {
4386                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4387                 if (!alloc)
4388                         return NULL;
4389
4390                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4391                 return alloc;
4392         }
4393 }
4394
4395 static gboolean
4396 mini_class_has_reference_variant_generic_argument (MonoCompile *cfg, MonoClass *klass, int context_used)
4397 {
4398         int i;
4399         MonoGenericContainer *container;
4400         MonoGenericInst *ginst;
4401
4402         if (klass->generic_class) {
4403                 container = klass->generic_class->container_class->generic_container;
4404                 ginst = klass->generic_class->context.class_inst;
4405         } else if (klass->generic_container && context_used) {
4406                 container = klass->generic_container;
4407                 ginst = container->context.class_inst;
4408         } else {
4409                 return FALSE;
4410         }
4411
4412         for (i = 0; i < container->type_argc; ++i) {
4413                 MonoType *type;
4414                 if (!(mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT)))
4415                         continue;
4416                 type = ginst->type_argv [i];
4417                 if (mini_type_is_reference (type))
4418                         return TRUE;
4419         }
4420         return FALSE;
4421 }
4422
4423 static GHashTable* direct_icall_type_hash;
4424
4425 static gboolean
4426 icall_is_direct_callable (MonoCompile *cfg, MonoMethod *cmethod)
4427 {
4428         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
4429         if (!direct_icalls_enabled (cfg))
4430                 return FALSE;
4431
4432         /*
4433          * An icall is directly callable if it doesn't directly or indirectly call mono_raise_exception ().
4434          * Whitelist a few icalls for now.
4435          */
4436         if (!direct_icall_type_hash) {
4437                 GHashTable *h = g_hash_table_new (g_str_hash, g_str_equal);
4438
4439                 g_hash_table_insert (h, (char*)"Decimal", GUINT_TO_POINTER (1));
4440                 g_hash_table_insert (h, (char*)"Number", GUINT_TO_POINTER (1));
4441                 g_hash_table_insert (h, (char*)"Buffer", GUINT_TO_POINTER (1));
4442                 g_hash_table_insert (h, (char*)"Monitor", GUINT_TO_POINTER (1));
4443                 mono_memory_barrier ();
4444                 direct_icall_type_hash = h;
4445         }
4446
4447         if (cmethod->klass == mono_defaults.math_class)
4448                 return TRUE;
4449         /* No locking needed */
4450         if (cmethod->klass->image == mono_defaults.corlib && g_hash_table_lookup (direct_icall_type_hash, cmethod->klass->name))
4451                 return TRUE;
4452         return FALSE;
4453 }
4454
4455 #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)
4456
4457 static MonoInst*
4458 emit_castclass_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args)
4459 {
4460         MonoMethod *mono_castclass;
4461         MonoInst *res;
4462
4463         mono_castclass = mono_marshal_get_castclass_with_cache ();
4464
4465         save_cast_details (cfg, klass, args [0]->dreg, TRUE);
4466         res = mono_emit_method_call (cfg, mono_castclass, args, NULL);
4467         reset_cast_details (cfg);
4468
4469         return res;
4470 }
4471
4472 static int
4473 get_castclass_cache_idx (MonoCompile *cfg)
4474 {
4475         /* Each CASTCLASS_CACHE patch needs a unique index which identifies the call site */
4476         cfg->castclass_cache_index ++;
4477         return (cfg->method_index << 16) | cfg->castclass_cache_index;
4478 }
4479
4480 static MonoInst*
4481 emit_castclass_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass *klass)
4482 {
4483         MonoInst *args [3];
4484         int idx;
4485
4486         /* obj */
4487         args [0] = obj;
4488
4489         /* klass */
4490         EMIT_NEW_CLASSCONST (cfg, args [1], klass);
4491
4492         /* inline cache*/
4493         idx = get_castclass_cache_idx (cfg);
4494         args [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
4495
4496         /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
4497         return emit_castclass_with_cache (cfg, klass, args);
4498 }
4499
4500 /*
4501  * Returns NULL and set the cfg exception on error.
4502  */
4503 static MonoInst*
4504 handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, guint8 *ip, int *inline_costs)
4505 {
4506         MonoBasicBlock *is_null_bb;
4507         int obj_reg = src->dreg;
4508         int vtable_reg = alloc_preg (cfg);
4509         int context_used;
4510         MonoInst *klass_inst = NULL, *res;
4511
4512         context_used = mini_class_check_context_used (cfg, klass);
4513
4514         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
4515                 res = emit_castclass_with_cache_nonshared (cfg, src, klass);
4516                 (*inline_costs) += 2;
4517                 return res;
4518         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
4519                 MonoMethod *mono_castclass;
4520                 MonoInst *iargs [1];
4521                 int costs;
4522
4523                 mono_castclass = mono_marshal_get_castclass (klass); 
4524                 iargs [0] = src;
4525                                 
4526                 save_cast_details (cfg, klass, src->dreg, TRUE);
4527                 costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
4528                                                            iargs, ip, cfg->real_offset, TRUE);
4529                 reset_cast_details (cfg);
4530                 CHECK_CFG_EXCEPTION;
4531                 g_assert (costs > 0);
4532                                 
4533                 cfg->real_offset += 5;
4534
4535                 (*inline_costs) += costs;
4536
4537                 return src;
4538         }
4539
4540         if (context_used) {
4541                 MonoInst *args [3];
4542
4543                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4544                         MonoInst *cache_ins;
4545
4546                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4547
4548                         /* obj */
4549                         args [0] = src;
4550
4551                         /* klass - it's the second element of the cache entry*/
4552                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4553
4554                         /* cache */
4555                         args [2] = cache_ins;
4556
4557                         return emit_castclass_with_cache (cfg, klass, args);
4558                 }
4559
4560                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4561         }
4562
4563         NEW_BBLOCK (cfg, is_null_bb);
4564
4565         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4566         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
4567
4568         save_cast_details (cfg, klass, obj_reg, FALSE);
4569
4570         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4571                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4572                 mini_emit_iface_cast (cfg, vtable_reg, klass, NULL, NULL);
4573         } else {
4574                 int klass_reg = alloc_preg (cfg);
4575
4576                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4577
4578                 if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4579                         /* the remoting code is broken, access the class for now */
4580                         if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4581                                 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4582                                 if (!vt) {
4583                                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4584                                         cfg->exception_ptr = klass;
4585                                         return NULL;
4586                                 }
4587                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4588                         } else {
4589                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4590                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4591                         }
4592                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4593                 } else {
4594                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4595                         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, klass_inst, is_null_bb);
4596                 }
4597         }
4598
4599         MONO_START_BB (cfg, is_null_bb);
4600
4601         reset_cast_details (cfg);
4602
4603         return src;
4604
4605 exception_exit:
4606         return NULL;
4607 }
4608
4609 /*
4610  * Returns NULL and set the cfg exception on error.
4611  */
4612 static MonoInst*
4613 handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
4614 {
4615         MonoInst *ins;
4616         MonoBasicBlock *is_null_bb, *false_bb, *end_bb;
4617         int obj_reg = src->dreg;
4618         int vtable_reg = alloc_preg (cfg);
4619         int res_reg = alloc_ireg_ref (cfg);
4620         MonoInst *klass_inst = NULL;
4621
4622         if (context_used) {
4623                 MonoInst *args [3];
4624
4625                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4626                         MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
4627                         MonoInst *cache_ins;
4628
4629                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4630
4631                         /* obj */
4632                         args [0] = src;
4633
4634                         /* klass - it's the second element of the cache entry*/
4635                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4636
4637                         /* cache */
4638                         args [2] = cache_ins;
4639
4640                         return mono_emit_method_call (cfg, mono_isinst, args, NULL);
4641                 }
4642
4643                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4644         }
4645
4646         NEW_BBLOCK (cfg, is_null_bb);
4647         NEW_BBLOCK (cfg, false_bb);
4648         NEW_BBLOCK (cfg, end_bb);
4649
4650         /* Do the assignment at the beginning, so the other assignment can be if converted */
4651         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, res_reg, obj_reg);
4652         ins->type = STACK_OBJ;
4653         ins->klass = klass;
4654
4655         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4656         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_null_bb);
4657
4658         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4659
4660         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4661                 g_assert (!context_used);
4662                 /* the is_null_bb target simply copies the input register to the output */
4663                 mini_emit_iface_cast (cfg, vtable_reg, klass, false_bb, is_null_bb);
4664         } else {
4665                 int klass_reg = alloc_preg (cfg);
4666
4667                 if (klass->rank) {
4668                         int rank_reg = alloc_preg (cfg);
4669                         int eclass_reg = alloc_preg (cfg);
4670
4671                         g_assert (!context_used);
4672                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
4673                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
4674                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4675                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4676                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
4677                         if (klass->cast_class == mono_defaults.object_class) {
4678                                 int parent_reg = alloc_preg (cfg);
4679                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
4680                                 mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, is_null_bb);
4681                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4682                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4683                         } else if (klass->cast_class == mono_defaults.enum_class->parent) {
4684                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, is_null_bb);
4685                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);                          
4686                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4687                         } else if (klass->cast_class == mono_defaults.enum_class) {
4688                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4689                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4690                         } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
4691                                 mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4692                         } else {
4693                                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY)) {
4694                                         /* Check that the object is a vector too */
4695                                         int bounds_reg = alloc_preg (cfg);
4696                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
4697                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
4698                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4699                                 }
4700
4701                                 /* the is_null_bb target simply copies the input register to the output */
4702                                 mini_emit_isninst_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4703                         }
4704                 } else if (mono_class_is_nullable (klass)) {
4705                         g_assert (!context_used);
4706                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4707                         /* the is_null_bb target simply copies the input register to the output */
4708                         mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb);
4709                 } else {
4710                         if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4711                                 g_assert (!context_used);
4712                                 /* the remoting code is broken, access the class for now */
4713                                 if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4714                                         MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4715                                         if (!vt) {
4716                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4717                                                 cfg->exception_ptr = klass;
4718                                                 return NULL;
4719                                         }
4720                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4721                                 } else {
4722                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4723                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4724                                 }
4725                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4726                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
4727                         } else {
4728                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4729                                 /* the is_null_bb target simply copies the input register to the output */
4730                                 mini_emit_isninst_cast_inst (cfg, klass_reg, klass, klass_inst, false_bb, is_null_bb);
4731                         }
4732                 }
4733         }
4734
4735         MONO_START_BB (cfg, false_bb);
4736
4737         MONO_EMIT_NEW_PCONST (cfg, res_reg, 0);
4738         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4739
4740         MONO_START_BB (cfg, is_null_bb);
4741
4742         MONO_START_BB (cfg, end_bb);
4743
4744         return ins;
4745 }
4746
4747 static MonoInst*
4748 handle_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4749 {
4750         /* This opcode takes as input an object reference and a class, and returns:
4751         0) if the object is an instance of the class,
4752         1) if the object is not instance of the class,
4753         2) if the object is a proxy whose type cannot be determined */
4754
4755         MonoInst *ins;
4756 #ifndef DISABLE_REMOTING
4757         MonoBasicBlock *true_bb, *false_bb, *false2_bb, *end_bb, *no_proxy_bb, *interface_fail_bb;
4758 #else
4759         MonoBasicBlock *true_bb, *false_bb, *end_bb;
4760 #endif
4761         int obj_reg = src->dreg;
4762         int dreg = alloc_ireg (cfg);
4763         int tmp_reg;
4764 #ifndef DISABLE_REMOTING
4765         int klass_reg = alloc_preg (cfg);
4766 #endif
4767
4768         NEW_BBLOCK (cfg, true_bb);
4769         NEW_BBLOCK (cfg, false_bb);
4770         NEW_BBLOCK (cfg, end_bb);
4771 #ifndef DISABLE_REMOTING
4772         NEW_BBLOCK (cfg, false2_bb);
4773         NEW_BBLOCK (cfg, no_proxy_bb);
4774 #endif
4775
4776         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4777         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
4778
4779         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4780 #ifndef DISABLE_REMOTING
4781                 NEW_BBLOCK (cfg, interface_fail_bb);
4782 #endif
4783
4784                 tmp_reg = alloc_preg (cfg);
4785                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4786 #ifndef DISABLE_REMOTING
4787                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, true_bb);
4788                 MONO_START_BB (cfg, interface_fail_bb);
4789                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4790                 
4791                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, false_bb);
4792
4793                 tmp_reg = alloc_preg (cfg);
4794                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4795                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4796                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false2_bb);                
4797 #else
4798                 mini_emit_iface_cast (cfg, tmp_reg, klass, false_bb, true_bb);
4799 #endif
4800         } else {
4801 #ifndef DISABLE_REMOTING
4802                 tmp_reg = alloc_preg (cfg);
4803                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4804                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4805
4806                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4807                 tmp_reg = alloc_preg (cfg);
4808                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4809                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4810
4811                 tmp_reg = alloc_preg (cfg);             
4812                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4813                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4814                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4815                 
4816                 mini_emit_isninst_cast (cfg, klass_reg, klass, false2_bb, true_bb);
4817                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false2_bb);
4818
4819                 MONO_START_BB (cfg, no_proxy_bb);
4820
4821                 mini_emit_isninst_cast (cfg, klass_reg, klass, false_bb, true_bb);
4822 #else
4823                 g_error ("transparent proxy support is disabled while trying to JIT code that uses it");
4824 #endif
4825         }
4826
4827         MONO_START_BB (cfg, false_bb);
4828
4829         MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4830         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4831
4832 #ifndef DISABLE_REMOTING
4833         MONO_START_BB (cfg, false2_bb);
4834
4835         MONO_EMIT_NEW_ICONST (cfg, dreg, 2);
4836         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4837 #endif
4838
4839         MONO_START_BB (cfg, true_bb);
4840
4841         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4842
4843         MONO_START_BB (cfg, end_bb);
4844
4845         /* FIXME: */
4846         MONO_INST_NEW (cfg, ins, OP_ICONST);
4847         ins->dreg = dreg;
4848         ins->type = STACK_I4;
4849
4850         return ins;
4851 }
4852
4853 static MonoInst*
4854 handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4855 {
4856         /* This opcode takes as input an object reference and a class, and returns:
4857         0) if the object is an instance of the class,
4858         1) if the object is a proxy whose type cannot be determined
4859         an InvalidCastException exception is thrown otherwhise*/
4860         
4861         MonoInst *ins;
4862 #ifndef DISABLE_REMOTING
4863         MonoBasicBlock *end_bb, *ok_result_bb, *no_proxy_bb, *interface_fail_bb, *fail_1_bb;
4864 #else
4865         MonoBasicBlock *ok_result_bb;
4866 #endif
4867         int obj_reg = src->dreg;
4868         int dreg = alloc_ireg (cfg);
4869         int tmp_reg = alloc_preg (cfg);
4870
4871 #ifndef DISABLE_REMOTING
4872         int klass_reg = alloc_preg (cfg);
4873         NEW_BBLOCK (cfg, end_bb);
4874 #endif
4875
4876         NEW_BBLOCK (cfg, ok_result_bb);
4877
4878         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4879         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, ok_result_bb);
4880
4881         save_cast_details (cfg, klass, obj_reg, FALSE);
4882
4883         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4884 #ifndef DISABLE_REMOTING
4885                 NEW_BBLOCK (cfg, interface_fail_bb);
4886         
4887                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4888                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, ok_result_bb);
4889                 MONO_START_BB (cfg, interface_fail_bb);
4890                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4891
4892                 mini_emit_class_check (cfg, klass_reg, mono_defaults.transparent_proxy_class);
4893
4894                 tmp_reg = alloc_preg (cfg);             
4895                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4896                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4897                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
4898                 
4899                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4900                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4901 #else
4902                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4903                 mini_emit_iface_cast (cfg, tmp_reg, klass, NULL, NULL);
4904                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, ok_result_bb);
4905 #endif
4906         } else {
4907 #ifndef DISABLE_REMOTING
4908                 NEW_BBLOCK (cfg, no_proxy_bb);
4909
4910                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4911                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4912                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4913
4914                 tmp_reg = alloc_preg (cfg);
4915                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4916                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4917
4918                 tmp_reg = alloc_preg (cfg);
4919                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4920                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4921                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4922
4923                 NEW_BBLOCK (cfg, fail_1_bb);
4924                 
4925                 mini_emit_isninst_cast (cfg, klass_reg, klass, fail_1_bb, ok_result_bb);
4926
4927                 MONO_START_BB (cfg, fail_1_bb);
4928
4929                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4930                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4931
4932                 MONO_START_BB (cfg, no_proxy_bb);
4933
4934                 mini_emit_castclass (cfg, obj_reg, klass_reg, klass, ok_result_bb);
4935 #else
4936                 g_error ("Transparent proxy support is disabled while trying to JIT code that uses it");
4937 #endif
4938         }
4939
4940         MONO_START_BB (cfg, ok_result_bb);
4941
4942         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4943
4944 #ifndef DISABLE_REMOTING
4945         MONO_START_BB (cfg, end_bb);
4946 #endif
4947
4948         /* FIXME: */
4949         MONO_INST_NEW (cfg, ins, OP_ICONST);
4950         ins->dreg = dreg;
4951         ins->type = STACK_I4;
4952
4953         return ins;
4954 }
4955
4956 static G_GNUC_UNUSED MonoInst*
4957 handle_enum_has_flag (MonoCompile *cfg, MonoClass *klass, MonoInst *enum_this, MonoInst *enum_flag)
4958 {
4959         MonoType *enum_type = mono_type_get_underlying_type (&klass->byval_arg);
4960         guint32 load_opc = mono_type_to_load_membase (cfg, enum_type);
4961         gboolean is_i4;
4962
4963         switch (enum_type->type) {
4964         case MONO_TYPE_I8:
4965         case MONO_TYPE_U8:
4966 #if SIZEOF_REGISTER == 8
4967         case MONO_TYPE_I:
4968         case MONO_TYPE_U:
4969 #endif
4970                 is_i4 = FALSE;
4971                 break;
4972         default:
4973                 is_i4 = TRUE;
4974                 break;
4975         }
4976
4977         {
4978                 MonoInst *load, *and_, *cmp, *ceq;
4979                 int enum_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4980                 int and_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4981                 int dest_reg = alloc_ireg (cfg);
4982
4983                 EMIT_NEW_LOAD_MEMBASE (cfg, load, load_opc, enum_reg, enum_this->dreg, 0);
4984                 EMIT_NEW_BIALU (cfg, and_, is_i4 ? OP_IAND : OP_LAND, and_reg, enum_reg, enum_flag->dreg);
4985                 EMIT_NEW_BIALU (cfg, cmp, is_i4 ? OP_ICOMPARE : OP_LCOMPARE, -1, and_reg, enum_flag->dreg);
4986                 EMIT_NEW_UNALU (cfg, ceq, is_i4 ? OP_ICEQ : OP_LCEQ, dest_reg, -1);
4987
4988                 ceq->type = STACK_I4;
4989
4990                 if (!is_i4) {
4991                         load = mono_decompose_opcode (cfg, load);
4992                         and_ = mono_decompose_opcode (cfg, and_);
4993                         cmp = mono_decompose_opcode (cfg, cmp);
4994                         ceq = mono_decompose_opcode (cfg, ceq);
4995                 }
4996
4997                 return ceq;
4998         }
4999 }
5000
5001 /*
5002  * Returns NULL and set the cfg exception on error.
5003  */
5004 static G_GNUC_UNUSED MonoInst*
5005 handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method, int context_used, gboolean virtual_)
5006 {
5007         MonoInst *ptr;
5008         int dreg;
5009         gpointer trampoline;
5010         MonoInst *obj, *method_ins, *tramp_ins;
5011         MonoDomain *domain;
5012         guint8 **code_slot;
5013
5014         if (virtual_ && !cfg->llvm_only) {
5015                 MonoMethod *invoke = mono_get_delegate_invoke (klass);
5016                 g_assert (invoke);
5017
5018                 if (!mono_get_delegate_virtual_invoke_impl (mono_method_signature (invoke), context_used ? NULL : method))
5019                         return NULL;
5020         }
5021
5022         obj = handle_alloc (cfg, klass, FALSE, mono_class_check_context_used (klass));
5023         if (!obj)
5024                 return NULL;
5025
5026         /* Inline the contents of mono_delegate_ctor */
5027
5028         /* Set target field */
5029         /* Optimize away setting of NULL target */
5030         if (!(target->opcode == OP_PCONST && target->inst_p0 == 0)) {
5031                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
5032                 if (cfg->gen_write_barriers) {
5033                         dreg = alloc_preg (cfg);
5034                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target));
5035                         emit_write_barrier (cfg, ptr, target);
5036                 }
5037         }
5038
5039         /* Set method field */
5040         method_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
5041         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg);
5042
5043         /* 
5044          * To avoid looking up the compiled code belonging to the target method
5045          * in mono_delegate_trampoline (), we allocate a per-domain memory slot to
5046          * store it, and we fill it after the method has been compiled.
5047          */
5048         if (!method->dynamic && !(cfg->opt & MONO_OPT_SHARED)) {
5049                 MonoInst *code_slot_ins;
5050
5051                 if (context_used) {
5052                         code_slot_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD_DELEGATE_CODE);
5053                 } else {
5054                         domain = mono_domain_get ();
5055                         mono_domain_lock (domain);
5056                         if (!domain_jit_info (domain)->method_code_hash)
5057                                 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
5058                         code_slot = (guint8 **)g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, method);
5059                         if (!code_slot) {
5060                                 code_slot = (guint8 **)mono_domain_alloc0 (domain, sizeof (gpointer));
5061                                 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, method, code_slot);
5062                         }
5063                         mono_domain_unlock (domain);
5064
5065                         code_slot_ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHOD_CODE_SLOT, method);
5066                 }
5067                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);                
5068         }
5069
5070         if (cfg->llvm_only) {
5071                 MonoInst *args [16];
5072
5073                 if (virtual_) {
5074                         args [0] = obj;
5075                         args [1] = target;
5076                         args [2] = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
5077                         mono_emit_jit_icall (cfg, mono_llvmonly_init_delegate_virtual, args);
5078                 } else {
5079                         args [0] = obj;
5080                         mono_emit_jit_icall (cfg, mono_llvmonly_init_delegate, args);
5081                 }
5082
5083                 return obj;
5084         }
5085
5086         if (cfg->compile_aot) {
5087                 MonoDelegateClassMethodPair *del_tramp;
5088
5089                 del_tramp = (MonoDelegateClassMethodPair *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoDelegateClassMethodPair));
5090                 del_tramp->klass = klass;
5091                 del_tramp->method = context_used ? NULL : method;
5092                 del_tramp->is_virtual = virtual_;
5093                 EMIT_NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_DELEGATE_TRAMPOLINE, del_tramp);
5094         } else {
5095                 if (virtual_)
5096                         trampoline = mono_create_delegate_virtual_trampoline (cfg->domain, klass, context_used ? NULL : method);
5097                 else
5098                         trampoline = mono_create_delegate_trampoline_info (cfg->domain, klass, context_used ? NULL : method);
5099                 EMIT_NEW_PCONST (cfg, tramp_ins, trampoline);
5100         }
5101
5102         /* Set invoke_impl field */
5103         if (virtual_) {
5104                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), tramp_ins->dreg);
5105         } else {
5106                 dreg = alloc_preg (cfg);
5107                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, invoke_impl));
5108                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), dreg);
5109
5110                 dreg = alloc_preg (cfg);
5111                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, method_ptr));
5112                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr), dreg);
5113         }
5114
5115         dreg = alloc_preg (cfg);
5116         MONO_EMIT_NEW_ICONST (cfg, dreg, virtual_ ? 1 : 0);
5117         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_is_virtual), dreg);
5118
5119         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
5120
5121         return obj;
5122 }
5123
5124 static MonoInst*
5125 handle_array_new (MonoCompile *cfg, int rank, MonoInst **sp, unsigned char *ip)
5126 {
5127         MonoJitICallInfo *info;
5128
5129         /* Need to register the icall so it gets an icall wrapper */
5130         info = mono_get_array_new_va_icall (rank);
5131
5132         cfg->flags |= MONO_CFG_HAS_VARARGS;
5133
5134         /* mono_array_new_va () needs a vararg calling convention */
5135         cfg->exception_message = g_strdup ("array-new");
5136         cfg->disable_llvm = TRUE;
5137
5138         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
5139         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, sp);
5140 }
5141
5142 /*
5143  * handle_constrained_gsharedvt_call:
5144  *
5145  *   Handle constrained calls where the receiver is a gsharedvt type.
5146  * Return the instruction representing the call. Set the cfg exception on failure.
5147  */
5148 static MonoInst*
5149 handle_constrained_gsharedvt_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp, MonoClass *constrained_class,
5150                                                                    gboolean *ref_emit_widen)
5151 {
5152         MonoInst *ins = NULL;
5153         gboolean emit_widen = *ref_emit_widen;
5154
5155         /*
5156          * Constrained calls need to behave differently at runtime dependending on whenever the receiver is instantiated as ref type or as a vtype.
5157          * 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
5158          * pack the arguments into an array, and do the rest of the work in in an icall.
5159          */
5160         if (((cmethod->klass == mono_defaults.object_class) || (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) &&
5161                 (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)) &&
5162                 (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]))))) {
5163                 MonoInst *args [16];
5164
5165                 /*
5166                  * This case handles calls to
5167                  * - object:ToString()/Equals()/GetHashCode(),
5168                  * - System.IComparable<T>:CompareTo()
5169                  * - System.IEquatable<T>:Equals ()
5170                  * plus some simple interface calls enough to support AsyncTaskMethodBuilder.
5171                  */
5172
5173                 args [0] = sp [0];
5174                 if (mono_method_check_context_used (cmethod))
5175                         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cmethod), cmethod, MONO_RGCTX_INFO_METHOD);
5176                 else
5177                         EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
5178                 args [2] = emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_class), constrained_class, MONO_RGCTX_INFO_KLASS);
5179
5180                 /* !fsig->hasthis is for the wrapper for the Object.GetType () icall */
5181                 if (fsig->hasthis && fsig->param_count) {
5182                         /* Pass the arguments using a localloc-ed array using the format expected by runtime_invoke () */
5183                         MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
5184                         ins->dreg = alloc_preg (cfg);
5185                         ins->inst_imm = fsig->param_count * sizeof (mgreg_t);
5186                         MONO_ADD_INS (cfg->cbb, ins);
5187                         args [4] = ins;
5188
5189                         if (mini_is_gsharedvt_type (fsig->params [0])) {
5190                                 int addr_reg, deref_arg_reg;
5191
5192                                 ins = emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type (fsig->params [0]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
5193                                 deref_arg_reg = alloc_preg (cfg);
5194                                 /* deref_arg = BOX_TYPE != MONO_GSHAREDVT_BOX_TYPE_VTYPE */
5195                                 EMIT_NEW_BIALU_IMM (cfg, args [3], OP_ISUB_IMM, deref_arg_reg, ins->dreg, 1);
5196
5197                                 EMIT_NEW_VARLOADA_VREG (cfg, ins, sp [1]->dreg, fsig->params [0]);
5198                                 addr_reg = ins->dreg;
5199                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, addr_reg);
5200                         } else {
5201                                 EMIT_NEW_ICONST (cfg, args [3], 0);
5202                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, sp [1]->dreg);
5203                         }
5204                 } else {
5205                         EMIT_NEW_ICONST (cfg, args [3], 0);
5206                         EMIT_NEW_ICONST (cfg, args [4], 0);
5207                 }
5208                 ins = mono_emit_jit_icall (cfg, mono_gsharedvt_constrained_call, args);
5209                 emit_widen = FALSE;
5210
5211                 if (mini_is_gsharedvt_type (fsig->ret)) {
5212                         ins = handle_unbox_gsharedvt (cfg, mono_class_from_mono_type (fsig->ret), ins);
5213                 } else if (MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret)) {
5214                         MonoInst *add;
5215
5216                         /* Unbox */
5217                         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), ins->dreg, sizeof (MonoObject));
5218                         MONO_ADD_INS (cfg->cbb, add);
5219                         /* Load value */
5220                         NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, add->dreg, 0);
5221                         MONO_ADD_INS (cfg->cbb, ins);
5222                         /* ins represents the call result */
5223                 }
5224         } else {
5225                 GSHAREDVT_FAILURE (CEE_CALLVIRT);
5226         }
5227
5228         *ref_emit_widen = emit_widen;
5229
5230         return ins;
5231
5232  exception_exit:
5233         return NULL;
5234 }
5235
5236 static void
5237 mono_emit_load_got_addr (MonoCompile *cfg)
5238 {
5239         MonoInst *getaddr, *dummy_use;
5240
5241         if (!cfg->got_var || cfg->got_var_allocated)
5242                 return;
5243
5244         MONO_INST_NEW (cfg, getaddr, OP_LOAD_GOTADDR);
5245         getaddr->cil_code = cfg->header->code;
5246         getaddr->dreg = cfg->got_var->dreg;
5247
5248         /* Add it to the start of the first bblock */
5249         if (cfg->bb_entry->code) {
5250                 getaddr->next = cfg->bb_entry->code;
5251                 cfg->bb_entry->code = getaddr;
5252         }
5253         else
5254                 MONO_ADD_INS (cfg->bb_entry, getaddr);
5255
5256         cfg->got_var_allocated = TRUE;
5257
5258         /* 
5259          * Add a dummy use to keep the got_var alive, since real uses might
5260          * only be generated by the back ends.
5261          * Add it to end_bblock, so the variable's lifetime covers the whole
5262          * method.
5263          * It would be better to make the usage of the got var explicit in all
5264          * cases when the backend needs it (i.e. calls, throw etc.), so this
5265          * wouldn't be needed.
5266          */
5267         NEW_DUMMY_USE (cfg, dummy_use, cfg->got_var);
5268         MONO_ADD_INS (cfg->bb_exit, dummy_use);
5269 }
5270
5271 static int inline_limit;
5272 static gboolean inline_limit_inited;
5273
5274 static gboolean
5275 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
5276 {
5277         MonoMethodHeaderSummary header;
5278         MonoVTable *vtable;
5279 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5280         MonoMethodSignature *sig = mono_method_signature (method);
5281         int i;
5282 #endif
5283
5284         if (cfg->disable_inline)
5285                 return FALSE;
5286         if (cfg->gshared)
5287                 return FALSE;
5288
5289         if (cfg->inline_depth > 10)
5290                 return FALSE;
5291
5292         if (!mono_method_get_header_summary (method, &header))
5293                 return FALSE;
5294
5295         /*runtime, icall and pinvoke are checked by summary call*/
5296         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
5297             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
5298             (mono_class_is_marshalbyref (method->klass)) ||
5299             header.has_clauses)
5300                 return FALSE;
5301
5302         /* also consider num_locals? */
5303         /* Do the size check early to avoid creating vtables */
5304         if (!inline_limit_inited) {
5305                 if (g_getenv ("MONO_INLINELIMIT"))
5306                         inline_limit = atoi (g_getenv ("MONO_INLINELIMIT"));
5307                 else
5308                         inline_limit = INLINE_LENGTH_LIMIT;
5309                 inline_limit_inited = TRUE;
5310         }
5311         if (header.code_size >= inline_limit && !(method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
5312                 return FALSE;
5313
5314         /*
5315          * if we can initialize the class of the method right away, we do,
5316          * otherwise we don't allow inlining if the class needs initialization,
5317          * since it would mean inserting a call to mono_runtime_class_init()
5318          * inside the inlined code
5319          */
5320         if (!(cfg->opt & MONO_OPT_SHARED)) {
5321                 /* The AggressiveInlining hint is a good excuse to force that cctor to run. */
5322                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING) {
5323                         vtable = mono_class_vtable (cfg->domain, method->klass);
5324                         if (!vtable)
5325                                 return FALSE;
5326                         if (!cfg->compile_aot)
5327                                 mono_runtime_class_init (vtable);
5328                 } else if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5329                         if (cfg->run_cctors && method->klass->has_cctor) {
5330                                 /*FIXME it would easier and lazier to just use mono_class_try_get_vtable */
5331                                 if (!method->klass->runtime_info)
5332                                         /* No vtable created yet */
5333                                         return FALSE;
5334                                 vtable = mono_class_vtable (cfg->domain, method->klass);
5335                                 if (!vtable)
5336                                         return FALSE;
5337                                 /* This makes so that inline cannot trigger */
5338                                 /* .cctors: too many apps depend on them */
5339                                 /* running with a specific order... */
5340                                 if (! vtable->initialized)
5341                                         return FALSE;
5342                                 mono_runtime_class_init (vtable);
5343                         }
5344                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
5345                         if (!method->klass->runtime_info)
5346                                 /* No vtable created yet */
5347                                 return FALSE;
5348                         vtable = mono_class_vtable (cfg->domain, method->klass);
5349                         if (!vtable)
5350                                 return FALSE;
5351                         if (!vtable->initialized)
5352                                 return FALSE;
5353                 }
5354         } else {
5355                 /* 
5356                  * If we're compiling for shared code
5357                  * the cctor will need to be run at aot method load time, for example,
5358                  * or at the end of the compilation of the inlining method.
5359                  */
5360                 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
5361                         return FALSE;
5362         }
5363
5364 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5365         if (mono_arch_is_soft_float ()) {
5366                 /* FIXME: */
5367                 if (sig->ret && sig->ret->type == MONO_TYPE_R4)
5368                         return FALSE;
5369                 for (i = 0; i < sig->param_count; ++i)
5370                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4)
5371                                 return FALSE;
5372         }
5373 #endif
5374
5375         if (g_list_find (cfg->dont_inline, method))
5376                 return FALSE;
5377
5378         return TRUE;
5379 }
5380
5381 static gboolean
5382 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoClass *klass, MonoVTable *vtable)
5383 {
5384         if (!cfg->compile_aot) {
5385                 g_assert (vtable);
5386                 if (vtable->initialized)
5387                         return FALSE;
5388         }
5389
5390         if (klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5391                 if (cfg->method == method)
5392                         return FALSE;
5393         }
5394
5395         if (!mono_class_needs_cctor_run (klass, method))
5396                 return FALSE;
5397
5398         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (klass == method->klass))
5399                 /* The initialization is already done before the method is called */
5400                 return FALSE;
5401
5402         return TRUE;
5403 }
5404
5405 static MonoInst*
5406 mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck)
5407 {
5408         MonoInst *ins;
5409         guint32 size;
5410         int mult_reg, add_reg, array_reg, index_reg, index2_reg;
5411         int context_used;
5412
5413         if (mini_is_gsharedvt_variable_klass (klass)) {
5414                 size = -1;
5415         } else {
5416                 mono_class_init (klass);
5417                 size = mono_class_array_element_size (klass);
5418         }
5419
5420         mult_reg = alloc_preg (cfg);
5421         array_reg = arr->dreg;
5422         index_reg = index->dreg;
5423
5424 #if SIZEOF_REGISTER == 8
5425         /* The array reg is 64 bits but the index reg is only 32 */
5426         if (COMPILE_LLVM (cfg)) {
5427                 /* Not needed */
5428                 index2_reg = index_reg;
5429         } else {
5430                 index2_reg = alloc_preg (cfg);
5431                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
5432         }
5433 #else
5434         if (index->type == STACK_I8) {
5435                 index2_reg = alloc_preg (cfg);
5436                 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I4, index2_reg, index_reg);
5437         } else {
5438                 index2_reg = index_reg;
5439         }
5440 #endif
5441
5442         if (bcheck)
5443                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
5444
5445 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5446         if (size == 1 || size == 2 || size == 4 || size == 8) {
5447                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
5448
5449                 EMIT_NEW_X86_LEA (cfg, ins, array_reg, index2_reg, fast_log2 [size], MONO_STRUCT_OFFSET (MonoArray, vector));
5450                 ins->klass = mono_class_get_element_class (klass);
5451                 ins->type = STACK_MP;
5452
5453                 return ins;
5454         }
5455 #endif          
5456
5457         add_reg = alloc_ireg_mp (cfg);
5458
5459         if (size == -1) {
5460                 MonoInst *rgctx_ins;
5461
5462                 /* gsharedvt */
5463                 g_assert (cfg->gshared);
5464                 context_used = mini_class_check_context_used (cfg, klass);
5465                 g_assert (context_used);
5466                 rgctx_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE);
5467                 MONO_EMIT_NEW_BIALU (cfg, OP_IMUL, mult_reg, index2_reg, rgctx_ins->dreg);
5468         } else {
5469                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
5470         }
5471         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg);
5472         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5473         ins->klass = mono_class_get_element_class (klass);
5474         ins->type = STACK_MP;
5475         MONO_ADD_INS (cfg->cbb, ins);
5476
5477         return ins;
5478 }
5479
5480 static MonoInst*
5481 mini_emit_ldelema_2_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index_ins1, MonoInst *index_ins2)
5482 {
5483         int bounds_reg = alloc_preg (cfg);
5484         int add_reg = alloc_ireg_mp (cfg);
5485         int mult_reg = alloc_preg (cfg);
5486         int mult2_reg = alloc_preg (cfg);
5487         int low1_reg = alloc_preg (cfg);
5488         int low2_reg = alloc_preg (cfg);
5489         int high1_reg = alloc_preg (cfg);
5490         int high2_reg = alloc_preg (cfg);
5491         int realidx1_reg = alloc_preg (cfg);
5492         int realidx2_reg = alloc_preg (cfg);
5493         int sum_reg = alloc_preg (cfg);
5494         int index1, index2, tmpreg;
5495         MonoInst *ins;
5496         guint32 size;
5497
5498         mono_class_init (klass);
5499         size = mono_class_array_element_size (klass);
5500
5501         index1 = index_ins1->dreg;
5502         index2 = index_ins2->dreg;
5503
5504 #if SIZEOF_REGISTER == 8
5505         /* The array reg is 64 bits but the index reg is only 32 */
5506         if (COMPILE_LLVM (cfg)) {
5507                 /* Not needed */
5508         } else {
5509                 tmpreg = alloc_preg (cfg);
5510                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index1);
5511                 index1 = tmpreg;
5512                 tmpreg = alloc_preg (cfg);
5513                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index2);
5514                 index2 = tmpreg;
5515         }
5516 #else
5517         // FIXME: Do we need to do something here for i8 indexes, like in ldelema_1_ins ?
5518         tmpreg = -1;
5519 #endif
5520
5521         /* range checking */
5522         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, 
5523                                        arr->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5524
5525         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low1_reg, 
5526                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5527         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx1_reg, index1, low1_reg);
5528         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high1_reg, 
5529                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5530         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high1_reg, realidx1_reg);
5531         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5532
5533         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low2_reg, 
5534                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5535         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx2_reg, index2, low2_reg);
5536         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high2_reg, 
5537                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5538         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high2_reg, realidx2_reg);
5539         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5540
5541         MONO_EMIT_NEW_BIALU (cfg, OP_PMUL, mult_reg, high2_reg, realidx1_reg);
5542         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, mult_reg, realidx2_reg);
5543         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PMUL_IMM, mult2_reg, sum_reg, size);
5544         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult2_reg, arr->dreg);
5545         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5546
5547         ins->type = STACK_MP;
5548         ins->klass = klass;
5549         MONO_ADD_INS (cfg->cbb, ins);
5550
5551         return ins;
5552 }
5553
5554 static MonoInst*
5555 mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
5556 {
5557         int rank;
5558         MonoInst *addr;
5559         MonoMethod *addr_method;
5560         int element_size;
5561         MonoClass *eclass = cmethod->klass->element_class;
5562
5563         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
5564
5565         if (rank == 1)
5566                 return mini_emit_ldelema_1_ins (cfg, eclass, sp [0], sp [1], TRUE);
5567
5568         /* emit_ldelema_2 depends on OP_LMUL */
5569         if (!cfg->backend->emulate_mul_div && rank == 2 && (cfg->opt & MONO_OPT_INTRINS) && !mini_is_gsharedvt_variable_klass (eclass)) {
5570                 return mini_emit_ldelema_2_ins (cfg, eclass, sp [0], sp [1], sp [2]);
5571         }
5572
5573         if (mini_is_gsharedvt_variable_klass (eclass))
5574                 element_size = 0;
5575         else
5576                 element_size = mono_class_array_element_size (eclass);
5577         addr_method = mono_marshal_get_array_address (rank, element_size);
5578         addr = mono_emit_method_call (cfg, addr_method, sp, NULL);
5579
5580         return addr;
5581 }
5582
5583 static MonoBreakPolicy
5584 always_insert_breakpoint (MonoMethod *method)
5585 {
5586         return MONO_BREAK_POLICY_ALWAYS;
5587 }
5588
5589 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
5590
5591 /**
5592  * mono_set_break_policy:
5593  * policy_callback: the new callback function
5594  *
5595  * Allow embedders to decide wherther to actually obey breakpoint instructions
5596  * (both break IL instructions and Debugger.Break () method calls), for example
5597  * to not allow an app to be aborted by a perfectly valid IL opcode when executing
5598  * untrusted or semi-trusted code.
5599  *
5600  * @policy_callback will be called every time a break point instruction needs to
5601  * be inserted with the method argument being the method that calls Debugger.Break()
5602  * or has the IL break instruction. The callback should return #MONO_BREAK_POLICY_NEVER
5603  * if it wants the breakpoint to not be effective in the given method.
5604  * #MONO_BREAK_POLICY_ALWAYS is the default.
5605  */
5606 void
5607 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
5608 {
5609         if (policy_callback)
5610                 break_policy_func = policy_callback;
5611         else
5612                 break_policy_func = always_insert_breakpoint;
5613 }
5614
5615 static gboolean
5616 should_insert_brekpoint (MonoMethod *method) {
5617         switch (break_policy_func (method)) {
5618         case MONO_BREAK_POLICY_ALWAYS:
5619                 return TRUE;
5620         case MONO_BREAK_POLICY_NEVER:
5621                 return FALSE;
5622         case MONO_BREAK_POLICY_ON_DBG:
5623                 g_warning ("mdb no longer supported");
5624                 return FALSE;
5625         default:
5626                 g_warning ("Incorrect value returned from break policy callback");
5627                 return FALSE;
5628         }
5629 }
5630
5631 /* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */
5632 static MonoInst*
5633 emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5634 {
5635         MonoInst *addr, *store, *load;
5636         MonoClass *eklass = mono_class_from_mono_type (fsig->params [2]);
5637
5638         /* the bounds check is already done by the callers */
5639         addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5640         if (is_set) {
5641                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
5642                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
5643                 if (mini_type_is_reference (fsig->params [2]))
5644                         emit_write_barrier (cfg, addr, load);
5645         } else {
5646                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
5647                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
5648         }
5649         return store;
5650 }
5651
5652
5653 static gboolean
5654 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
5655 {
5656         return mini_type_is_reference (&klass->byval_arg);
5657 }
5658
5659 static MonoInst*
5660 emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboolean safety_checks)
5661 {
5662         if (safety_checks && generic_class_is_reference_type (cfg, klass) &&
5663                 !(sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL)) {
5664                 MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
5665                 MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
5666                 MonoInst *iargs [3];
5667
5668                 if (!helper->slot)
5669                         mono_class_setup_vtable (obj_array);
5670                 g_assert (helper->slot);
5671
5672                 if (sp [0]->type != STACK_OBJ)
5673                         return NULL;
5674                 if (sp [2]->type != STACK_OBJ)
5675                         return NULL;
5676
5677                 iargs [2] = sp [2];
5678                 iargs [1] = sp [1];
5679                 iargs [0] = sp [0];
5680
5681                 return mono_emit_method_call (cfg, helper, iargs, sp [0]);
5682         } else {
5683                 MonoInst *ins;
5684
5685                 if (mini_is_gsharedvt_variable_klass (klass)) {
5686                         MonoInst *addr;
5687
5688                         // FIXME-VT: OP_ICONST optimization
5689                         addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
5690                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5691                         ins->opcode = OP_STOREV_MEMBASE;
5692                 } else if (sp [1]->opcode == OP_ICONST) {
5693                         int array_reg = sp [0]->dreg;
5694                         int index_reg = sp [1]->dreg;
5695                         int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
5696
5697                         if (SIZEOF_REGISTER == 8 && COMPILE_LLVM (cfg))
5698                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, index_reg);
5699
5700                         if (safety_checks)
5701                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
5702                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
5703                 } else {
5704                         MonoInst *addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], safety_checks);
5705                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5706                         if (generic_class_is_reference_type (cfg, klass))
5707                                 emit_write_barrier (cfg, addr, sp [2]);
5708                 }
5709                 return ins;
5710         }
5711 }
5712
5713 static MonoInst*
5714 emit_array_unsafe_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5715 {
5716         MonoClass *eklass;
5717         
5718         if (is_set)
5719                 eklass = mono_class_from_mono_type (fsig->params [2]);
5720         else
5721                 eklass = mono_class_from_mono_type (fsig->ret);
5722
5723         if (is_set) {
5724                 return emit_array_store (cfg, eklass, args, FALSE);
5725         } else {
5726                 MonoInst *ins, *addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5727                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &eklass->byval_arg, addr->dreg, 0);
5728                 return ins;
5729         }
5730 }
5731
5732 static gboolean
5733 is_unsafe_mov_compatible (MonoCompile *cfg, MonoClass *param_klass, MonoClass *return_klass)
5734 {
5735         uint32_t align;
5736         int param_size, return_size;
5737
5738         param_klass = mono_class_from_mono_type (mini_get_underlying_type (&param_klass->byval_arg));
5739         return_klass = mono_class_from_mono_type (mini_get_underlying_type (&return_klass->byval_arg));
5740
5741         if (cfg->verbose_level > 3)
5742                 printf ("[UNSAFE-MOV-INTRISIC] %s <- %s\n", return_klass->name, param_klass->name);
5743
5744         //Don't allow mixing reference types with value types
5745         if (param_klass->valuetype != return_klass->valuetype) {
5746                 if (cfg->verbose_level > 3)
5747                         printf ("[UNSAFE-MOV-INTRISIC]\tone of the args is a valuetype and the other is not\n");
5748                 return FALSE;
5749         }
5750
5751         if (!param_klass->valuetype) {
5752                 if (cfg->verbose_level > 3)
5753                         printf ("[UNSAFE-MOV-INTRISIC]\targs are reference types\n");
5754                 return TRUE;
5755         }
5756
5757         //That are blitable
5758         if (param_klass->has_references || return_klass->has_references)
5759                 return FALSE;
5760
5761         /* Avoid mixing structs and primitive types/enums, they need to be handled differently in the JIT */
5762         if ((MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && !MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)) ||
5763                 (!MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && MONO_TYPE_ISSTRUCT (&return_klass->byval_arg))) {
5764                         if (cfg->verbose_level > 3)
5765                                 printf ("[UNSAFE-MOV-INTRISIC]\tmixing structs and scalars\n");
5766                 return FALSE;
5767         }
5768
5769         if (param_klass->byval_arg.type == MONO_TYPE_R4 || param_klass->byval_arg.type == MONO_TYPE_R8 ||
5770                 return_klass->byval_arg.type == MONO_TYPE_R4 || return_klass->byval_arg.type == MONO_TYPE_R8) {
5771                 if (cfg->verbose_level > 3)
5772                         printf ("[UNSAFE-MOV-INTRISIC]\tfloat or double are not supported\n");
5773                 return FALSE;
5774         }
5775
5776         param_size = mono_class_value_size (param_klass, &align);
5777         return_size = mono_class_value_size (return_klass, &align);
5778
5779         //We can do it if sizes match
5780         if (param_size == return_size) {
5781                 if (cfg->verbose_level > 3)
5782                         printf ("[UNSAFE-MOV-INTRISIC]\tsame size\n");
5783                 return TRUE;
5784         }
5785
5786         //No simple way to handle struct if sizes don't match
5787         if (MONO_TYPE_ISSTRUCT (&param_klass->byval_arg)) {
5788                 if (cfg->verbose_level > 3)
5789                         printf ("[UNSAFE-MOV-INTRISIC]\tsize mismatch and type is a struct\n");
5790                 return FALSE;
5791         }
5792
5793         /*
5794          * Same reg size category.
5795          * A quick note on why we don't require widening here.
5796          * The intrinsic is "R Array.UnsafeMov<S,R> (S s)".
5797          *
5798          * Since the source value comes from a function argument, the JIT will already have
5799          * the value in a VREG and performed any widening needed before (say, when loading from a field).
5800          */
5801         if (param_size <= 4 && return_size <= 4) {
5802                 if (cfg->verbose_level > 3)
5803                         printf ("[UNSAFE-MOV-INTRISIC]\tsize mismatch but both are of the same reg class\n");
5804                 return TRUE;
5805         }
5806
5807         return FALSE;
5808 }
5809
5810 static MonoInst*
5811 emit_array_unsafe_mov (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args)
5812 {
5813         MonoClass *param_klass = mono_class_from_mono_type (fsig->params [0]);
5814         MonoClass *return_klass = mono_class_from_mono_type (fsig->ret);
5815
5816         if (mini_is_gsharedvt_variable_type (fsig->ret))
5817                 return NULL;
5818
5819         //Valuetypes that are semantically equivalent or numbers than can be widened to
5820         if (is_unsafe_mov_compatible (cfg, param_klass, return_klass))
5821                 return args [0];
5822
5823         //Arrays of valuetypes that are semantically equivalent
5824         if (param_klass->rank == 1 && return_klass->rank == 1 && is_unsafe_mov_compatible (cfg, param_klass->element_class, return_klass->element_class))
5825                 return args [0];
5826
5827         return NULL;
5828 }
5829
5830 static MonoInst*
5831 mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5832 {
5833 #ifdef MONO_ARCH_SIMD_INTRINSICS
5834         MonoInst *ins = NULL;
5835
5836         if (cfg->opt & MONO_OPT_SIMD) {
5837                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5838                 if (ins)
5839                         return ins;
5840         }
5841 #endif
5842
5843         return mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
5844 }
5845
5846 static MonoInst*
5847 emit_memory_barrier (MonoCompile *cfg, int kind)
5848 {
5849         MonoInst *ins = NULL;
5850         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
5851         MONO_ADD_INS (cfg->cbb, ins);
5852         ins->backend.memory_barrier_kind = kind;
5853
5854         return ins;
5855 }
5856
5857 static MonoInst*
5858 llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5859 {
5860         MonoInst *ins = NULL;
5861         int opcode = 0;
5862
5863         /* The LLVM backend supports these intrinsics */
5864         if (cmethod->klass == mono_defaults.math_class) {
5865                 if (strcmp (cmethod->name, "Sin") == 0) {
5866                         opcode = OP_SIN;
5867                 } else if (strcmp (cmethod->name, "Cos") == 0) {
5868                         opcode = OP_COS;
5869                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
5870                         opcode = OP_SQRT;
5871                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
5872                         opcode = OP_ABS;
5873                 }
5874
5875                 if (opcode && fsig->param_count == 1) {
5876                         MONO_INST_NEW (cfg, ins, opcode);
5877                         ins->type = STACK_R8;
5878                         ins->dreg = mono_alloc_freg (cfg);
5879                         ins->sreg1 = args [0]->dreg;
5880                         MONO_ADD_INS (cfg->cbb, ins);
5881                 }
5882
5883                 opcode = 0;
5884                 if (cfg->opt & MONO_OPT_CMOV) {
5885                         if (strcmp (cmethod->name, "Min") == 0) {
5886                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5887                                         opcode = OP_IMIN;
5888                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5889                                         opcode = OP_IMIN_UN;
5890                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5891                                         opcode = OP_LMIN;
5892                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5893                                         opcode = OP_LMIN_UN;
5894                         } else if (strcmp (cmethod->name, "Max") == 0) {
5895                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5896                                         opcode = OP_IMAX;
5897                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5898                                         opcode = OP_IMAX_UN;
5899                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5900                                         opcode = OP_LMAX;
5901                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5902                                         opcode = OP_LMAX_UN;
5903                         }
5904                 }
5905
5906                 if (opcode && fsig->param_count == 2) {
5907                         MONO_INST_NEW (cfg, ins, opcode);
5908                         ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
5909                         ins->dreg = mono_alloc_ireg (cfg);
5910                         ins->sreg1 = args [0]->dreg;
5911                         ins->sreg2 = args [1]->dreg;
5912                         MONO_ADD_INS (cfg->cbb, ins);
5913                 }
5914         }
5915
5916         return ins;
5917 }
5918
5919 static MonoInst*
5920 mini_emit_inst_for_sharable_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5921 {
5922         if (cmethod->klass == mono_defaults.array_class) {
5923                 if (strcmp (cmethod->name, "UnsafeStore") == 0)
5924                         return emit_array_unsafe_access (cfg, fsig, args, TRUE);
5925                 else if (strcmp (cmethod->name, "UnsafeLoad") == 0)
5926                         return emit_array_unsafe_access (cfg, fsig, args, FALSE);
5927                 else if (strcmp (cmethod->name, "UnsafeMov") == 0)
5928                         return emit_array_unsafe_mov (cfg, fsig, args);
5929         }
5930
5931         return NULL;
5932 }
5933
5934 static MonoInst*
5935 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5936 {
5937         MonoInst *ins = NULL;
5938
5939          MonoClass *runtime_helpers_class = mono_class_get_runtime_helpers_class ();
5940
5941         if (cmethod->klass == mono_defaults.string_class) {
5942                 if (strcmp (cmethod->name, "get_Chars") == 0 && fsig->param_count + fsig->hasthis == 2) {
5943                         int dreg = alloc_ireg (cfg);
5944                         int index_reg = alloc_preg (cfg);
5945                         int add_reg = alloc_preg (cfg);
5946
5947 #if SIZEOF_REGISTER == 8
5948                         if (COMPILE_LLVM (cfg)) {
5949                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, args [1]->dreg);
5950                         } else {
5951                                 /* The array reg is 64 bits but the index reg is only 32 */
5952                                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index_reg, args [1]->dreg);
5953                         }
5954 #else
5955                         index_reg = args [1]->dreg;
5956 #endif  
5957                         MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
5958
5959 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5960                         EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, MONO_STRUCT_OFFSET (MonoString, chars));
5961                         add_reg = ins->dreg;
5962                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5963                                                                    add_reg, 0);
5964 #else
5965                         int mult_reg = alloc_preg (cfg);
5966                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1);
5967                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5968                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5969                                                                    add_reg, MONO_STRUCT_OFFSET (MonoString, chars));
5970 #endif
5971                         type_from_op (cfg, ins, NULL, NULL);
5972                         return ins;
5973                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
5974                         int dreg = alloc_ireg (cfg);
5975                         /* Decompose later to allow more optimizations */
5976                         EMIT_NEW_UNALU (cfg, ins, OP_STRLEN, dreg, args [0]->dreg);
5977                         ins->type = STACK_I4;
5978                         ins->flags |= MONO_INST_FAULT;
5979                         cfg->cbb->has_array_access = TRUE;
5980                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
5981
5982                         return ins;
5983                 } else 
5984                         return NULL;
5985         } else if (cmethod->klass == mono_defaults.object_class) {
5986                 if (strcmp (cmethod->name, "GetType") == 0 && fsig->param_count + fsig->hasthis == 1) {
5987                         int dreg = alloc_ireg_ref (cfg);
5988                         int vt_reg = alloc_preg (cfg);
5989                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
5990                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, MONO_STRUCT_OFFSET (MonoVTable, type));
5991                         type_from_op (cfg, ins, NULL, NULL);
5992
5993                         return ins;
5994                 } else if (!cfg->backend->emulate_mul_div && strcmp (cmethod->name, "InternalGetHashCode") == 0 && fsig->param_count == 1 && !mono_gc_is_moving ()) {
5995                         int dreg = alloc_ireg (cfg);
5996                         int t1 = alloc_ireg (cfg);
5997         
5998                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, t1, args [0]->dreg, 3);
5999                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_MUL_IMM, dreg, t1, 2654435761u);
6000                         ins->type = STACK_I4;
6001
6002                         return ins;
6003                 } else if (strcmp (cmethod->name, ".ctor") == 0 && fsig->param_count == 0) {
6004                         MONO_INST_NEW (cfg, ins, OP_NOP);
6005                         MONO_ADD_INS (cfg->cbb, ins);
6006                         return ins;
6007                 } else
6008                         return NULL;
6009         } else if (cmethod->klass == mono_defaults.array_class) {
6010                 if (strcmp (cmethod->name, "GetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
6011                         return emit_array_generic_access (cfg, fsig, args, FALSE);
6012                 else if (strcmp (cmethod->name, "SetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
6013                         return emit_array_generic_access (cfg, fsig, args, TRUE);
6014
6015 #ifndef MONO_BIG_ARRAYS
6016                 /*
6017                  * This is an inline version of GetLength/GetLowerBound(0) used frequently in
6018                  * Array methods.
6019                  */
6020                 else if (((strcmp (cmethod->name, "GetLength") == 0 && fsig->param_count + fsig->hasthis == 2) ||
6021                          (strcmp (cmethod->name, "GetLowerBound") == 0 && fsig->param_count + fsig->hasthis == 2)) &&
6022                          args [1]->opcode == OP_ICONST && args [1]->inst_c0 == 0) {
6023                         int dreg = alloc_ireg (cfg);
6024                         int bounds_reg = alloc_ireg_mp (cfg);
6025                         MonoBasicBlock *end_bb, *szarray_bb;
6026                         gboolean get_length = strcmp (cmethod->name, "GetLength") == 0;
6027
6028                         NEW_BBLOCK (cfg, end_bb);
6029                         NEW_BBLOCK (cfg, szarray_bb);
6030
6031                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOAD_MEMBASE, bounds_reg,
6032                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
6033                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
6034                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, szarray_bb);
6035                         /* Non-szarray case */
6036                         if (get_length)
6037                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
6038                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
6039                         else
6040                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
6041                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
6042                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
6043                         MONO_START_BB (cfg, szarray_bb);
6044                         /* Szarray case */
6045                         if (get_length)
6046                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
6047                                                                            args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
6048                         else
6049                                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
6050                         MONO_START_BB (cfg, end_bb);
6051
6052                         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, dreg, dreg);
6053                         ins->type = STACK_I4;
6054                         
6055                         return ins;
6056                 }
6057 #endif
6058
6059                 if (cmethod->name [0] != 'g')
6060                         return NULL;
6061
6062                 if (strcmp (cmethod->name, "get_Rank") == 0 && fsig->param_count + fsig->hasthis == 1) {
6063                         int dreg = alloc_ireg (cfg);
6064                         int vtable_reg = alloc_preg (cfg);
6065                         MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, 
6066                                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
6067                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
6068                                                                    vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
6069                         type_from_op (cfg, ins, NULL, NULL);
6070
6071                         return ins;
6072                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
6073                         int dreg = alloc_ireg (cfg);
6074
6075                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
6076                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
6077                         type_from_op (cfg, ins, NULL, NULL);
6078
6079                         return ins;
6080                 } else
6081                         return NULL;
6082         } else if (cmethod->klass == runtime_helpers_class) {
6083                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0 && fsig->param_count == 0) {
6084                         EMIT_NEW_ICONST (cfg, ins, MONO_STRUCT_OFFSET (MonoString, chars));
6085                         return ins;
6086                 } else
6087                         return NULL;
6088         } else if (cmethod->klass == mono_defaults.monitor_class) {
6089                 gboolean is_enter = FALSE;
6090                 gboolean is_v4 = FALSE;
6091
6092                 if (!strcmp (cmethod->name, "enter_with_atomic_var") && mono_method_signature (cmethod)->param_count == 2) {
6093                         is_enter = TRUE;
6094                         is_v4 = TRUE;
6095                 }
6096                 if (!strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1)
6097                         is_enter = TRUE;
6098
6099                 if (is_enter) {
6100                         /*
6101                          * To make async stack traces work, icalls which can block should have a wrapper.
6102                          * For Monitor.Enter, emit two calls: a fastpath which doesn't have a wrapper, and a slowpath, which does.
6103                          */
6104                         MonoBasicBlock *end_bb;
6105
6106                         NEW_BBLOCK (cfg, end_bb);
6107
6108                         ins = mono_emit_jit_icall (cfg, is_v4 ? (gpointer)mono_monitor_enter_v4_fast : (gpointer)mono_monitor_enter_fast, args);
6109                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, ins->dreg, 0);
6110                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, end_bb);
6111                         ins = mono_emit_jit_icall (cfg, is_v4 ? (gpointer)mono_monitor_enter_v4 : (gpointer)mono_monitor_enter, args);
6112                         MONO_START_BB (cfg, end_bb);
6113                         return ins;
6114                 }
6115         } else if (cmethod->klass == mono_defaults.thread_class) {
6116                 if (strcmp (cmethod->name, "SpinWait_nop") == 0 && fsig->param_count == 0) {
6117                         MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
6118                         MONO_ADD_INS (cfg->cbb, ins);
6119                         return ins;
6120                 } else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0) {
6121                         return emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6122                 } else if (!strcmp (cmethod->name, "VolatileRead") && fsig->param_count == 1) {
6123                         guint32 opcode = 0;
6124                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6125
6126                         if (fsig->params [0]->type == MONO_TYPE_I1)
6127                                 opcode = OP_LOADI1_MEMBASE;
6128                         else if (fsig->params [0]->type == MONO_TYPE_U1)
6129                                 opcode = OP_LOADU1_MEMBASE;
6130                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6131                                 opcode = OP_LOADI2_MEMBASE;
6132                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6133                                 opcode = OP_LOADU2_MEMBASE;
6134                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6135                                 opcode = OP_LOADI4_MEMBASE;
6136                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6137                                 opcode = OP_LOADU4_MEMBASE;
6138                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
6139                                 opcode = OP_LOADI8_MEMBASE;
6140                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6141                                 opcode = OP_LOADR4_MEMBASE;
6142                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6143                                 opcode = OP_LOADR8_MEMBASE;
6144                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
6145                                 opcode = OP_LOAD_MEMBASE;
6146
6147                         if (opcode) {
6148                                 MONO_INST_NEW (cfg, ins, opcode);
6149                                 ins->inst_basereg = args [0]->dreg;
6150                                 ins->inst_offset = 0;
6151                                 MONO_ADD_INS (cfg->cbb, ins);
6152
6153                                 switch (fsig->params [0]->type) {
6154                                 case MONO_TYPE_I1:
6155                                 case MONO_TYPE_U1:
6156                                 case MONO_TYPE_I2:
6157                                 case MONO_TYPE_U2:
6158                                 case MONO_TYPE_I4:
6159                                 case MONO_TYPE_U4:
6160                                         ins->dreg = mono_alloc_ireg (cfg);
6161                                         ins->type = STACK_I4;
6162                                         break;
6163                                 case MONO_TYPE_I8:
6164                                 case MONO_TYPE_U8:
6165                                         ins->dreg = mono_alloc_lreg (cfg);
6166                                         ins->type = STACK_I8;
6167                                         break;
6168                                 case MONO_TYPE_I:
6169                                 case MONO_TYPE_U:
6170                                         ins->dreg = mono_alloc_ireg (cfg);
6171 #if SIZEOF_REGISTER == 8
6172                                         ins->type = STACK_I8;
6173 #else
6174                                         ins->type = STACK_I4;
6175 #endif
6176                                         break;
6177                                 case MONO_TYPE_R4:
6178                                 case MONO_TYPE_R8:
6179                                         ins->dreg = mono_alloc_freg (cfg);
6180                                         ins->type = STACK_R8;
6181                                         break;
6182                                 default:
6183                                         g_assert (mini_type_is_reference (fsig->params [0]));
6184                                         ins->dreg = mono_alloc_ireg_ref (cfg);
6185                                         ins->type = STACK_OBJ;
6186                                         break;
6187                                 }
6188
6189                                 if (opcode == OP_LOADI8_MEMBASE)
6190                                         ins = mono_decompose_opcode (cfg, ins);
6191
6192                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6193
6194                                 return ins;
6195                         }
6196                 } else if (!strcmp (cmethod->name, "VolatileWrite") && fsig->param_count == 2) {
6197                         guint32 opcode = 0;
6198                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6199
6200                         if (fsig->params [0]->type == MONO_TYPE_I1 || fsig->params [0]->type == MONO_TYPE_U1)
6201                                 opcode = OP_STOREI1_MEMBASE_REG;
6202                         else if (fsig->params [0]->type == MONO_TYPE_I2 || fsig->params [0]->type == MONO_TYPE_U2)
6203                                 opcode = OP_STOREI2_MEMBASE_REG;
6204                         else if (fsig->params [0]->type == MONO_TYPE_I4 || fsig->params [0]->type == MONO_TYPE_U4)
6205                                 opcode = OP_STOREI4_MEMBASE_REG;
6206                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
6207                                 opcode = OP_STOREI8_MEMBASE_REG;
6208                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6209                                 opcode = OP_STORER4_MEMBASE_REG;
6210                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6211                                 opcode = OP_STORER8_MEMBASE_REG;
6212                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
6213                                 opcode = OP_STORE_MEMBASE_REG;
6214
6215                         if (opcode) {
6216                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6217
6218                                 MONO_INST_NEW (cfg, ins, opcode);
6219                                 ins->sreg1 = args [1]->dreg;
6220                                 ins->inst_destbasereg = args [0]->dreg;
6221                                 ins->inst_offset = 0;
6222                                 MONO_ADD_INS (cfg->cbb, ins);
6223
6224                                 if (opcode == OP_STOREI8_MEMBASE_REG)
6225                                         ins = mono_decompose_opcode (cfg, ins);
6226
6227                                 return ins;
6228                         }
6229                 }
6230         } else if (cmethod->klass->image == mono_defaults.corlib &&
6231                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6232                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
6233                 ins = NULL;
6234
6235 #if SIZEOF_REGISTER == 8
6236                 if (!cfg->llvm_only && strcmp (cmethod->name, "Read") == 0 && fsig->param_count == 1 && (fsig->params [0]->type == MONO_TYPE_I8)) {
6237                         if (!cfg->llvm_only && mono_arch_opcode_supported (OP_ATOMIC_LOAD_I8)) {
6238                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_LOAD_I8);
6239                                 ins->dreg = mono_alloc_preg (cfg);
6240                                 ins->sreg1 = args [0]->dreg;
6241                                 ins->type = STACK_I8;
6242                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_SEQ;
6243                                 MONO_ADD_INS (cfg->cbb, ins);
6244                         } else {
6245                                 MonoInst *load_ins;
6246
6247                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6248
6249                                 /* 64 bit reads are already atomic */
6250                                 MONO_INST_NEW (cfg, load_ins, OP_LOADI8_MEMBASE);
6251                                 load_ins->dreg = mono_alloc_preg (cfg);
6252                                 load_ins->inst_basereg = args [0]->dreg;
6253                                 load_ins->inst_offset = 0;
6254                                 load_ins->type = STACK_I8;
6255                                 MONO_ADD_INS (cfg->cbb, load_ins);
6256
6257                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6258
6259                                 ins = load_ins;
6260                         }
6261                 }
6262 #endif
6263
6264                 if (strcmp (cmethod->name, "Increment") == 0 && fsig->param_count == 1) {
6265                         MonoInst *ins_iconst;
6266                         guint32 opcode = 0;
6267
6268                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6269                                 opcode = OP_ATOMIC_ADD_I4;
6270                                 cfg->has_atomic_add_i4 = TRUE;
6271                         }
6272 #if SIZEOF_REGISTER == 8
6273                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6274                                 opcode = OP_ATOMIC_ADD_I8;
6275 #endif
6276                         if (opcode) {
6277                                 if (!mono_arch_opcode_supported (opcode))
6278                                         return NULL;
6279                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6280                                 ins_iconst->inst_c0 = 1;
6281                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6282                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6283
6284                                 MONO_INST_NEW (cfg, ins, opcode);
6285                                 ins->dreg = mono_alloc_ireg (cfg);
6286                                 ins->inst_basereg = args [0]->dreg;
6287                                 ins->inst_offset = 0;
6288                                 ins->sreg2 = ins_iconst->dreg;
6289                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6290                                 MONO_ADD_INS (cfg->cbb, ins);
6291                         }
6292                 } else if (strcmp (cmethod->name, "Decrement") == 0 && fsig->param_count == 1) {
6293                         MonoInst *ins_iconst;
6294                         guint32 opcode = 0;
6295
6296                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6297                                 opcode = OP_ATOMIC_ADD_I4;
6298                                 cfg->has_atomic_add_i4 = TRUE;
6299                         }
6300 #if SIZEOF_REGISTER == 8
6301                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6302                                 opcode = OP_ATOMIC_ADD_I8;
6303 #endif
6304                         if (opcode) {
6305                                 if (!mono_arch_opcode_supported (opcode))
6306                                         return NULL;
6307                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6308                                 ins_iconst->inst_c0 = -1;
6309                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6310                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6311
6312                                 MONO_INST_NEW (cfg, ins, opcode);
6313                                 ins->dreg = mono_alloc_ireg (cfg);
6314                                 ins->inst_basereg = args [0]->dreg;
6315                                 ins->inst_offset = 0;
6316                                 ins->sreg2 = ins_iconst->dreg;
6317                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6318                                 MONO_ADD_INS (cfg->cbb, ins);
6319                         }
6320                 } else if (strcmp (cmethod->name, "Add") == 0 && fsig->param_count == 2) {
6321                         guint32 opcode = 0;
6322
6323                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6324                                 opcode = OP_ATOMIC_ADD_I4;
6325                                 cfg->has_atomic_add_i4 = TRUE;
6326                         }
6327 #if SIZEOF_REGISTER == 8
6328                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6329                                 opcode = OP_ATOMIC_ADD_I8;
6330 #endif
6331                         if (opcode) {
6332                                 if (!mono_arch_opcode_supported (opcode))
6333                                         return NULL;
6334                                 MONO_INST_NEW (cfg, ins, opcode);
6335                                 ins->dreg = mono_alloc_ireg (cfg);
6336                                 ins->inst_basereg = args [0]->dreg;
6337                                 ins->inst_offset = 0;
6338                                 ins->sreg2 = args [1]->dreg;
6339                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6340                                 MONO_ADD_INS (cfg->cbb, ins);
6341                         }
6342                 }
6343                 else if (strcmp (cmethod->name, "Exchange") == 0 && fsig->param_count == 2) {
6344                         MonoInst *f2i = NULL, *i2f;
6345                         guint32 opcode, f2i_opcode, i2f_opcode;
6346                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6347                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
6348
6349                         if (fsig->params [0]->type == MONO_TYPE_I4 ||
6350                             fsig->params [0]->type == MONO_TYPE_R4) {
6351                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6352                                 f2i_opcode = OP_MOVE_F_TO_I4;
6353                                 i2f_opcode = OP_MOVE_I4_TO_F;
6354                                 cfg->has_atomic_exchange_i4 = TRUE;
6355                         }
6356 #if SIZEOF_REGISTER == 8
6357                         else if (is_ref ||
6358                                  fsig->params [0]->type == MONO_TYPE_I8 ||
6359                                  fsig->params [0]->type == MONO_TYPE_R8 ||
6360                                  fsig->params [0]->type == MONO_TYPE_I) {
6361                                 opcode = OP_ATOMIC_EXCHANGE_I8;
6362                                 f2i_opcode = OP_MOVE_F_TO_I8;
6363                                 i2f_opcode = OP_MOVE_I8_TO_F;
6364                         }
6365 #else
6366                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I) {
6367                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6368                                 cfg->has_atomic_exchange_i4 = TRUE;
6369                         }
6370 #endif
6371                         else
6372                                 return NULL;
6373
6374                         if (!mono_arch_opcode_supported (opcode))
6375                                 return NULL;
6376
6377                         if (is_float) {
6378                                 /* TODO: Decompose these opcodes instead of bailing here. */
6379                                 if (COMPILE_SOFT_FLOAT (cfg))
6380                                         return NULL;
6381
6382                                 MONO_INST_NEW (cfg, f2i, f2i_opcode);
6383                                 f2i->dreg = mono_alloc_ireg (cfg);
6384                                 f2i->sreg1 = args [1]->dreg;
6385                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6386                                         f2i->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6387                                 MONO_ADD_INS (cfg->cbb, f2i);
6388                         }
6389
6390                         MONO_INST_NEW (cfg, ins, opcode);
6391                         ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : mono_alloc_ireg (cfg);
6392                         ins->inst_basereg = args [0]->dreg;
6393                         ins->inst_offset = 0;
6394                         ins->sreg2 = is_float ? f2i->dreg : args [1]->dreg;
6395                         MONO_ADD_INS (cfg->cbb, ins);
6396
6397                         switch (fsig->params [0]->type) {
6398                         case MONO_TYPE_I4:
6399                                 ins->type = STACK_I4;
6400                                 break;
6401                         case MONO_TYPE_I8:
6402                                 ins->type = STACK_I8;
6403                                 break;
6404                         case MONO_TYPE_I:
6405 #if SIZEOF_REGISTER == 8
6406                                 ins->type = STACK_I8;
6407 #else
6408                                 ins->type = STACK_I4;
6409 #endif
6410                                 break;
6411                         case MONO_TYPE_R4:
6412                         case MONO_TYPE_R8:
6413                                 ins->type = STACK_R8;
6414                                 break;
6415                         default:
6416                                 g_assert (mini_type_is_reference (fsig->params [0]));
6417                                 ins->type = STACK_OBJ;
6418                                 break;
6419                         }
6420
6421                         if (is_float) {
6422                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6423                                 i2f->dreg = mono_alloc_freg (cfg);
6424                                 i2f->sreg1 = ins->dreg;
6425                                 i2f->type = STACK_R8;
6426                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6427                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6428                                 MONO_ADD_INS (cfg->cbb, i2f);
6429
6430                                 ins = i2f;
6431                         }
6432
6433                         if (cfg->gen_write_barriers && is_ref)
6434                                 emit_write_barrier (cfg, args [0], args [1]);
6435                 }
6436                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 3) {
6437                         MonoInst *f2i_new = NULL, *f2i_cmp = NULL, *i2f;
6438                         guint32 opcode, f2i_opcode, i2f_opcode;
6439                         gboolean is_ref = mini_type_is_reference (fsig->params [1]);
6440                         gboolean is_float = fsig->params [1]->type == MONO_TYPE_R4 || fsig->params [1]->type == MONO_TYPE_R8;
6441
6442                         if (fsig->params [1]->type == MONO_TYPE_I4 ||
6443                             fsig->params [1]->type == MONO_TYPE_R4) {
6444                                 opcode = OP_ATOMIC_CAS_I4;
6445                                 f2i_opcode = OP_MOVE_F_TO_I4;
6446                                 i2f_opcode = OP_MOVE_I4_TO_F;
6447                                 cfg->has_atomic_cas_i4 = TRUE;
6448                         }
6449 #if SIZEOF_REGISTER == 8
6450                         else if (is_ref ||
6451                                  fsig->params [1]->type == MONO_TYPE_I8 ||
6452                                  fsig->params [1]->type == MONO_TYPE_R8 ||
6453                                  fsig->params [1]->type == MONO_TYPE_I) {
6454                                 opcode = OP_ATOMIC_CAS_I8;
6455                                 f2i_opcode = OP_MOVE_F_TO_I8;
6456                                 i2f_opcode = OP_MOVE_I8_TO_F;
6457                         }
6458 #else
6459                         else if (is_ref || fsig->params [1]->type == MONO_TYPE_I) {
6460                                 opcode = OP_ATOMIC_CAS_I4;
6461                                 cfg->has_atomic_cas_i4 = TRUE;
6462                         }
6463 #endif
6464                         else
6465                                 return NULL;
6466
6467                         if (!mono_arch_opcode_supported (opcode))
6468                                 return NULL;
6469
6470                         if (is_float) {
6471                                 /* TODO: Decompose these opcodes instead of bailing here. */
6472                                 if (COMPILE_SOFT_FLOAT (cfg))
6473                                         return NULL;
6474
6475                                 MONO_INST_NEW (cfg, f2i_new, f2i_opcode);
6476                                 f2i_new->dreg = mono_alloc_ireg (cfg);
6477                                 f2i_new->sreg1 = args [1]->dreg;
6478                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6479                                         f2i_new->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6480                                 MONO_ADD_INS (cfg->cbb, f2i_new);
6481
6482                                 MONO_INST_NEW (cfg, f2i_cmp, f2i_opcode);
6483                                 f2i_cmp->dreg = mono_alloc_ireg (cfg);
6484                                 f2i_cmp->sreg1 = args [2]->dreg;
6485                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6486                                         f2i_cmp->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6487                                 MONO_ADD_INS (cfg->cbb, f2i_cmp);
6488                         }
6489
6490                         MONO_INST_NEW (cfg, ins, opcode);
6491                         ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
6492                         ins->sreg1 = args [0]->dreg;
6493                         ins->sreg2 = is_float ? f2i_new->dreg : args [1]->dreg;
6494                         ins->sreg3 = is_float ? f2i_cmp->dreg : args [2]->dreg;
6495                         MONO_ADD_INS (cfg->cbb, ins);
6496
6497                         switch (fsig->params [1]->type) {
6498                         case MONO_TYPE_I4:
6499                                 ins->type = STACK_I4;
6500                                 break;
6501                         case MONO_TYPE_I8:
6502                                 ins->type = STACK_I8;
6503                                 break;
6504                         case MONO_TYPE_I:
6505 #if SIZEOF_REGISTER == 8
6506                                 ins->type = STACK_I8;
6507 #else
6508                                 ins->type = STACK_I4;
6509 #endif
6510                                 break;
6511                         case MONO_TYPE_R4:
6512                                 ins->type = cfg->r4_stack_type;
6513                                 break;
6514                         case MONO_TYPE_R8:
6515                                 ins->type = STACK_R8;
6516                                 break;
6517                         default:
6518                                 g_assert (mini_type_is_reference (fsig->params [1]));
6519                                 ins->type = STACK_OBJ;
6520                                 break;
6521                         }
6522
6523                         if (is_float) {
6524                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6525                                 i2f->dreg = mono_alloc_freg (cfg);
6526                                 i2f->sreg1 = ins->dreg;
6527                                 i2f->type = STACK_R8;
6528                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6529                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6530                                 MONO_ADD_INS (cfg->cbb, i2f);
6531
6532                                 ins = i2f;
6533                         }
6534
6535                         if (cfg->gen_write_barriers && is_ref)
6536                                 emit_write_barrier (cfg, args [0], args [1]);
6537                 }
6538                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 4 &&
6539                          fsig->params [1]->type == MONO_TYPE_I4) {
6540                         MonoInst *cmp, *ceq;
6541
6542                         if (!mono_arch_opcode_supported (OP_ATOMIC_CAS_I4))
6543                                 return NULL;
6544
6545                         /* int32 r = CAS (location, value, comparand); */
6546                         MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
6547                         ins->dreg = alloc_ireg (cfg);
6548                         ins->sreg1 = args [0]->dreg;
6549                         ins->sreg2 = args [1]->dreg;
6550                         ins->sreg3 = args [2]->dreg;
6551                         ins->type = STACK_I4;
6552                         MONO_ADD_INS (cfg->cbb, ins);
6553
6554                         /* bool result = r == comparand; */
6555                         MONO_INST_NEW (cfg, cmp, OP_ICOMPARE);
6556                         cmp->sreg1 = ins->dreg;
6557                         cmp->sreg2 = args [2]->dreg;
6558                         cmp->type = STACK_I4;
6559                         MONO_ADD_INS (cfg->cbb, cmp);
6560
6561                         MONO_INST_NEW (cfg, ceq, OP_ICEQ);
6562                         ceq->dreg = alloc_ireg (cfg);
6563                         ceq->type = STACK_I4;
6564                         MONO_ADD_INS (cfg->cbb, ceq);
6565
6566                         /* *success = result; */
6567                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, args [3]->dreg, 0, ceq->dreg);
6568
6569                         cfg->has_atomic_cas_i4 = TRUE;
6570                 }
6571                 else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0)
6572                         ins = emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6573
6574                 if (ins)
6575                         return ins;
6576         } else if (cmethod->klass->image == mono_defaults.corlib &&
6577                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6578                            (strcmp (cmethod->klass->name, "Volatile") == 0)) {
6579                 ins = NULL;
6580
6581                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Read") && fsig->param_count == 1) {
6582                         guint32 opcode = 0;
6583                         MonoType *t = fsig->params [0];
6584                         gboolean is_ref;
6585                         gboolean is_float = t->type == MONO_TYPE_R4 || t->type == MONO_TYPE_R8;
6586
6587                         g_assert (t->byref);
6588                         /* t is a byref type, so the reference check is more complicated */
6589                         is_ref = mini_type_is_reference (&mono_class_from_mono_type (t)->byval_arg);
6590                         if (t->type == MONO_TYPE_I1)
6591                                 opcode = OP_ATOMIC_LOAD_I1;
6592                         else if (t->type == MONO_TYPE_U1 || t->type == MONO_TYPE_BOOLEAN)
6593                                 opcode = OP_ATOMIC_LOAD_U1;
6594                         else if (t->type == MONO_TYPE_I2)
6595                                 opcode = OP_ATOMIC_LOAD_I2;
6596                         else if (t->type == MONO_TYPE_U2)
6597                                 opcode = OP_ATOMIC_LOAD_U2;
6598                         else if (t->type == MONO_TYPE_I4)
6599                                 opcode = OP_ATOMIC_LOAD_I4;
6600                         else if (t->type == MONO_TYPE_U4)
6601                                 opcode = OP_ATOMIC_LOAD_U4;
6602                         else if (t->type == MONO_TYPE_R4)
6603                                 opcode = OP_ATOMIC_LOAD_R4;
6604                         else if (t->type == MONO_TYPE_R8)
6605                                 opcode = OP_ATOMIC_LOAD_R8;
6606 #if SIZEOF_REGISTER == 8
6607                         else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_I)
6608                                 opcode = OP_ATOMIC_LOAD_I8;
6609                         else if (is_ref || t->type == MONO_TYPE_U8 || t->type == MONO_TYPE_U)
6610                                 opcode = OP_ATOMIC_LOAD_U8;
6611 #else
6612                         else if (t->type == MONO_TYPE_I)
6613                                 opcode = OP_ATOMIC_LOAD_I4;
6614                         else if (is_ref || t->type == MONO_TYPE_U)
6615                                 opcode = OP_ATOMIC_LOAD_U4;
6616 #endif
6617
6618                         if (opcode) {
6619                                 if (!mono_arch_opcode_supported (opcode))
6620                                         return NULL;
6621
6622                                 MONO_INST_NEW (cfg, ins, opcode);
6623                                 ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : (is_float ? mono_alloc_freg (cfg) : mono_alloc_ireg (cfg));
6624                                 ins->sreg1 = args [0]->dreg;
6625                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_ACQ;
6626                                 MONO_ADD_INS (cfg->cbb, ins);
6627
6628                                 switch (t->type) {
6629                                 case MONO_TYPE_BOOLEAN:
6630                                 case MONO_TYPE_I1:
6631                                 case MONO_TYPE_U1:
6632                                 case MONO_TYPE_I2:
6633                                 case MONO_TYPE_U2:
6634                                 case MONO_TYPE_I4:
6635                                 case MONO_TYPE_U4:
6636                                         ins->type = STACK_I4;
6637                                         break;
6638                                 case MONO_TYPE_I8:
6639                                 case MONO_TYPE_U8:
6640                                         ins->type = STACK_I8;
6641                                         break;
6642                                 case MONO_TYPE_I:
6643                                 case MONO_TYPE_U:
6644 #if SIZEOF_REGISTER == 8
6645                                         ins->type = STACK_I8;
6646 #else
6647                                         ins->type = STACK_I4;
6648 #endif
6649                                         break;
6650                                 case MONO_TYPE_R4:
6651                                         ins->type = cfg->r4_stack_type;
6652                                         break;
6653                                 case MONO_TYPE_R8:
6654                                         ins->type = STACK_R8;
6655                                         break;
6656                                 default:
6657                                         g_assert (is_ref);
6658                                         ins->type = STACK_OBJ;
6659                                         break;
6660                                 }
6661                         }
6662                 }
6663
6664                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Write") && fsig->param_count == 2) {
6665                         guint32 opcode = 0;
6666                         MonoType *t = fsig->params [0];
6667                         gboolean is_ref;
6668
6669                         g_assert (t->byref);
6670                         is_ref = mini_type_is_reference (&mono_class_from_mono_type (t)->byval_arg);
6671                         if (t->type == MONO_TYPE_I1)
6672                                 opcode = OP_ATOMIC_STORE_I1;
6673                         else if (t->type == MONO_TYPE_U1 || t->type == MONO_TYPE_BOOLEAN)
6674                                 opcode = OP_ATOMIC_STORE_U1;
6675                         else if (t->type == MONO_TYPE_I2)
6676                                 opcode = OP_ATOMIC_STORE_I2;
6677                         else if (t->type == MONO_TYPE_U2)
6678                                 opcode = OP_ATOMIC_STORE_U2;
6679                         else if (t->type == MONO_TYPE_I4)
6680                                 opcode = OP_ATOMIC_STORE_I4;
6681                         else if (t->type == MONO_TYPE_U4)
6682                                 opcode = OP_ATOMIC_STORE_U4;
6683                         else if (t->type == MONO_TYPE_R4)
6684                                 opcode = OP_ATOMIC_STORE_R4;
6685                         else if (t->type == MONO_TYPE_R8)
6686                                 opcode = OP_ATOMIC_STORE_R8;
6687 #if SIZEOF_REGISTER == 8
6688                         else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_I)
6689                                 opcode = OP_ATOMIC_STORE_I8;
6690                         else if (is_ref || t->type == MONO_TYPE_U8 || t->type == MONO_TYPE_U)
6691                                 opcode = OP_ATOMIC_STORE_U8;
6692 #else
6693                         else if (t->type == MONO_TYPE_I)
6694                                 opcode = OP_ATOMIC_STORE_I4;
6695                         else if (is_ref || t->type == MONO_TYPE_U)
6696                                 opcode = OP_ATOMIC_STORE_U4;
6697 #endif
6698
6699                         if (opcode) {
6700                                 if (!mono_arch_opcode_supported (opcode))
6701                                         return NULL;
6702
6703                                 MONO_INST_NEW (cfg, ins, opcode);
6704                                 ins->dreg = args [0]->dreg;
6705                                 ins->sreg1 = args [1]->dreg;
6706                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_REL;
6707                                 MONO_ADD_INS (cfg->cbb, ins);
6708
6709                                 if (cfg->gen_write_barriers && is_ref)
6710                                         emit_write_barrier (cfg, args [0], args [1]);
6711                         }
6712                 }
6713
6714                 if (ins)
6715                         return ins;
6716         } else if (cmethod->klass->image == mono_defaults.corlib &&
6717                            (strcmp (cmethod->klass->name_space, "System.Diagnostics") == 0) &&
6718                            (strcmp (cmethod->klass->name, "Debugger") == 0)) {
6719                 if (!strcmp (cmethod->name, "Break") && fsig->param_count == 0) {
6720                         if (should_insert_brekpoint (cfg->method)) {
6721                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
6722                         } else {
6723                                 MONO_INST_NEW (cfg, ins, OP_NOP);
6724                                 MONO_ADD_INS (cfg->cbb, ins);
6725                         }
6726                         return ins;
6727                 }
6728         } else if (cmethod->klass->image == mono_defaults.corlib &&
6729                    (strcmp (cmethod->klass->name_space, "System") == 0) &&
6730                    (strcmp (cmethod->klass->name, "Environment") == 0)) {
6731                 if (!strcmp (cmethod->name, "get_IsRunningOnWindows") && fsig->param_count == 0) {
6732 #ifdef TARGET_WIN32
6733                         EMIT_NEW_ICONST (cfg, ins, 1);
6734 #else
6735                         EMIT_NEW_ICONST (cfg, ins, 0);
6736 #endif
6737                 }
6738         } else if (cmethod->klass->image == mono_defaults.corlib &&
6739                            (strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
6740                            (strcmp (cmethod->klass->name, "Assembly") == 0)) {
6741                 if (cfg->llvm_only && !strcmp (cmethod->name, "GetExecutingAssembly")) {
6742                         /* No stack walks are currently available, so implement this as an intrinsic */
6743                         MonoInst *assembly_ins;
6744
6745                         EMIT_NEW_AOTCONST (cfg, assembly_ins, MONO_PATCH_INFO_IMAGE, cfg->method->klass->image);
6746                         ins = mono_emit_jit_icall (cfg, mono_get_assembly_object, &assembly_ins);
6747                         return ins;
6748                 }
6749         } else if (cmethod->klass->image == mono_defaults.corlib &&
6750                            (strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
6751                            (strcmp (cmethod->klass->name, "MethodBase") == 0)) {
6752                 if (cfg->llvm_only && !strcmp (cmethod->name, "GetCurrentMethod")) {
6753                         /* No stack walks are currently available, so implement this as an intrinsic */
6754                         MonoInst *method_ins;
6755                         MonoMethod *declaring = cfg->method;
6756
6757                         /* This returns the declaring generic method */
6758                         if (declaring->is_inflated)
6759                                 declaring = ((MonoMethodInflated*)cfg->method)->declaring;
6760                         EMIT_NEW_AOTCONST (cfg, method_ins, MONO_PATCH_INFO_METHODCONST, declaring);
6761                         ins = mono_emit_jit_icall (cfg, mono_get_method_object, &method_ins);
6762                         cfg->no_inline = TRUE;
6763                         if (cfg->method != cfg->current_method)
6764                                 inline_failure (cfg, "MethodBase:GetCurrentMethod ()");
6765                         return ins;
6766                 }
6767         } else if (cmethod->klass == mono_defaults.math_class) {
6768                 /* 
6769                  * There is general branchless code for Min/Max, but it does not work for 
6770                  * all inputs:
6771                  * http://everything2.com/?node_id=1051618
6772                  */
6773         } else if (((!strcmp (cmethod->klass->image->assembly->aname.name, "MonoMac") ||
6774                     !strcmp (cmethod->klass->image->assembly->aname.name, "monotouch")) &&
6775                                 !strcmp (cmethod->klass->name_space, "XamCore.ObjCRuntime") &&
6776                                 !strcmp (cmethod->klass->name, "Selector")) ||
6777                            (!strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.iOS") &&
6778                                 !strcmp (cmethod->klass->name_space, "ObjCRuntime") &&
6779                                 !strcmp (cmethod->klass->name, "Selector"))
6780                            ) {
6781                 if (cfg->backend->have_objc_get_selector &&
6782                         !strcmp (cmethod->name, "GetHandle") && fsig->param_count == 1 &&
6783                     (args [0]->opcode == OP_GOT_ENTRY || args [0]->opcode == OP_AOTCONST) &&
6784                     cfg->compile_aot && !cfg->llvm_only) {
6785                         MonoInst *pi;
6786                         MonoJumpInfoToken *ji;
6787                         MonoString *s;
6788
6789                         // FIXME: llvmonly
6790
6791                         cfg->exception_message = g_strdup ("GetHandle");
6792                         cfg->disable_llvm = TRUE;
6793
6794                         if (args [0]->opcode == OP_GOT_ENTRY) {
6795                                 pi = (MonoInst *)args [0]->inst_p1;
6796                                 g_assert (pi->opcode == OP_PATCH_INFO);
6797                                 g_assert (GPOINTER_TO_INT (pi->inst_p1) == MONO_PATCH_INFO_LDSTR);
6798                                 ji = (MonoJumpInfoToken *)pi->inst_p0;
6799                         } else {
6800                                 g_assert (GPOINTER_TO_INT (args [0]->inst_p1) == MONO_PATCH_INFO_LDSTR);
6801                                 ji = (MonoJumpInfoToken *)args [0]->inst_p0;
6802                         }
6803
6804                         NULLIFY_INS (args [0]);
6805
6806                         // FIXME: Ugly
6807                         s = mono_ldstr (cfg->domain, ji->image, mono_metadata_token_index (ji->token));
6808                         MONO_INST_NEW (cfg, ins, OP_OBJC_GET_SELECTOR);
6809                         ins->dreg = mono_alloc_ireg (cfg);
6810                         // FIXME: Leaks
6811                         ins->inst_p0 = mono_string_to_utf8 (s);
6812                         MONO_ADD_INS (cfg->cbb, ins);
6813                         return ins;
6814                 }
6815         }
6816
6817 #ifdef MONO_ARCH_SIMD_INTRINSICS
6818         if (cfg->opt & MONO_OPT_SIMD) {
6819                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
6820                 if (ins)
6821                         return ins;
6822         }
6823 #endif
6824
6825         ins = mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
6826         if (ins)
6827                 return ins;
6828
6829         if (COMPILE_LLVM (cfg)) {
6830                 ins = llvm_emit_inst_for_method (cfg, cmethod, fsig, args);
6831                 if (ins)
6832                         return ins;
6833         }
6834
6835         return mono_arch_emit_inst_for_method (cfg, cmethod, fsig, args);
6836 }
6837
6838 /*
6839  * This entry point could be used later for arbitrary method
6840  * redirection.
6841  */
6842 inline static MonoInst*
6843 mini_redirect_call (MonoCompile *cfg, MonoMethod *method,  
6844                                         MonoMethodSignature *signature, MonoInst **args, MonoInst *this_ins)
6845 {
6846         if (method->klass == mono_defaults.string_class) {
6847                 /* managed string allocation support */
6848                 if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && !(cfg->opt & MONO_OPT_SHARED)) {
6849                         MonoInst *iargs [2];
6850                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
6851                         MonoMethod *managed_alloc = NULL;
6852
6853                         g_assert (vtable); /*Should not fail since it System.String*/
6854 #ifndef MONO_CROSS_COMPILE
6855                         managed_alloc = mono_gc_get_managed_allocator (method->klass, FALSE, FALSE);
6856 #endif
6857                         if (!managed_alloc)
6858                                 return NULL;
6859                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
6860                         iargs [1] = args [0];
6861                         return mono_emit_method_call (cfg, managed_alloc, iargs, this_ins);
6862                 }
6863         }
6864         return NULL;
6865 }
6866
6867 static void
6868 mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp)
6869 {
6870         MonoInst *store, *temp;
6871         int i;
6872
6873         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
6874                 MonoType *argtype = (sig->hasthis && (i == 0)) ? type_from_stack_type (*sp) : sig->params [i - sig->hasthis];
6875
6876                 /*
6877                  * FIXME: We should use *args++ = sp [0], but that would mean the arg
6878                  * would be different than the MonoInst's used to represent arguments, and
6879                  * the ldelema implementation can't deal with that.
6880                  * Solution: When ldelema is used on an inline argument, create a var for 
6881                  * it, emit ldelema on that var, and emit the saving code below in
6882                  * inline_method () if needed.
6883                  */
6884                 temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
6885                 cfg->args [i] = temp;
6886                 /* This uses cfg->args [i] which is set by the preceeding line */
6887                 EMIT_NEW_ARGSTORE (cfg, store, i, *sp);
6888                 store->cil_code = sp [0]->cil_code;
6889                 sp++;
6890         }
6891 }
6892
6893 #define MONO_INLINE_CALLED_LIMITED_METHODS 1
6894 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
6895
6896 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6897 static gboolean
6898 check_inline_called_method_name_limit (MonoMethod *called_method)
6899 {
6900         int strncmp_result;
6901         static const char *limit = NULL;
6902         
6903         if (limit == NULL) {
6904                 const char *limit_string = g_getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
6905
6906                 if (limit_string != NULL)
6907                         limit = limit_string;
6908                 else
6909                         limit = "";
6910         }
6911
6912         if (limit [0] != '\0') {
6913                 char *called_method_name = mono_method_full_name (called_method, TRUE);
6914
6915                 strncmp_result = strncmp (called_method_name, limit, strlen (limit));
6916                 g_free (called_method_name);
6917         
6918                 //return (strncmp_result <= 0);
6919                 return (strncmp_result == 0);
6920         } else {
6921                 return TRUE;
6922         }
6923 }
6924 #endif
6925
6926 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6927 static gboolean
6928 check_inline_caller_method_name_limit (MonoMethod *caller_method)
6929 {
6930         int strncmp_result;
6931         static const char *limit = NULL;
6932         
6933         if (limit == NULL) {
6934                 const char *limit_string = g_getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
6935                 if (limit_string != NULL) {
6936                         limit = limit_string;
6937                 } else {
6938                         limit = "";
6939                 }
6940         }
6941
6942         if (limit [0] != '\0') {
6943                 char *caller_method_name = mono_method_full_name (caller_method, TRUE);
6944
6945                 strncmp_result = strncmp (caller_method_name, limit, strlen (limit));
6946                 g_free (caller_method_name);
6947         
6948                 //return (strncmp_result <= 0);
6949                 return (strncmp_result == 0);
6950         } else {
6951                 return TRUE;
6952         }
6953 }
6954 #endif
6955
6956 static void
6957 emit_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6958 {
6959         static double r8_0 = 0.0;
6960         static float r4_0 = 0.0;
6961         MonoInst *ins;
6962         int t;
6963
6964         rtype = mini_get_underlying_type (rtype);
6965         t = rtype->type;
6966
6967         if (rtype->byref) {
6968                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6969         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6970                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
6971         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6972                 MONO_EMIT_NEW_I8CONST (cfg, dreg, 0);
6973         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6974                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
6975                 ins->type = STACK_R4;
6976                 ins->inst_p0 = (void*)&r4_0;
6977                 ins->dreg = dreg;
6978                 MONO_ADD_INS (cfg->cbb, ins);
6979         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6980                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
6981                 ins->type = STACK_R8;
6982                 ins->inst_p0 = (void*)&r8_0;
6983                 ins->dreg = dreg;
6984                 MONO_ADD_INS (cfg->cbb, ins);
6985         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6986                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6987                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6988         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
6989                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6990         } else {
6991                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6992         }
6993 }
6994
6995 static void
6996 emit_dummy_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6997 {
6998         int t;
6999
7000         rtype = mini_get_underlying_type (rtype);
7001         t = rtype->type;
7002
7003         if (rtype->byref) {
7004                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_PCONST);
7005         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
7006                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_ICONST);
7007         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
7008                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_I8CONST);
7009         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
7010                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R4CONST);
7011         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
7012                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R8CONST);
7013         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
7014                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
7015                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
7016         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
7017                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
7018         } else {
7019                 emit_init_rvar (cfg, dreg, rtype);
7020         }
7021 }
7022
7023 /* If INIT is FALSE, emit dummy initialization statements to keep the IR valid */
7024 static void
7025 emit_init_local (MonoCompile *cfg, int local, MonoType *type, gboolean init)
7026 {
7027         MonoInst *var = cfg->locals [local];
7028         if (COMPILE_SOFT_FLOAT (cfg)) {
7029                 MonoInst *store;
7030                 int reg = alloc_dreg (cfg, (MonoStackType)var->type);
7031                 emit_init_rvar (cfg, reg, type);
7032                 EMIT_NEW_LOCSTORE (cfg, store, local, cfg->cbb->last_ins);
7033         } else {
7034                 if (init)
7035                         emit_init_rvar (cfg, var->dreg, type);
7036                 else
7037                         emit_dummy_init_rvar (cfg, var->dreg, type);
7038         }
7039 }
7040
7041 /*
7042  * inline_method:
7043  *
7044  *   Return the cost of inlining CMETHOD.
7045  */
7046 static int
7047 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
7048                            guchar *ip, guint real_offset, gboolean inline_always)
7049 {
7050         MonoInst *ins, *rvar = NULL;
7051         MonoMethodHeader *cheader;
7052         MonoBasicBlock *ebblock, *sbblock;
7053         int i, costs;
7054         MonoMethod *prev_inlined_method;
7055         MonoInst **prev_locals, **prev_args;
7056         MonoType **prev_arg_types;
7057         guint prev_real_offset;
7058         GHashTable *prev_cbb_hash;
7059         MonoBasicBlock **prev_cil_offset_to_bb;
7060         MonoBasicBlock *prev_cbb;
7061         unsigned char* prev_cil_start;
7062         guint32 prev_cil_offset_to_bb_len;
7063         MonoMethod *prev_current_method;
7064         MonoGenericContext *prev_generic_context;
7065         gboolean ret_var_set, prev_ret_var_set, prev_disable_inline, virtual_ = FALSE;
7066
7067         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
7068
7069 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
7070         if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod))
7071                 return 0;
7072 #endif
7073 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
7074         if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method))
7075                 return 0;
7076 #endif
7077
7078         if (!fsig)
7079                 fsig = mono_method_signature (cmethod);
7080
7081         if (cfg->verbose_level > 2)
7082                 printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
7083
7084         if (!cmethod->inline_info) {
7085                 cfg->stat_inlineable_methods++;
7086                 cmethod->inline_info = 1;
7087         }
7088
7089         /* allocate local variables */
7090         cheader = mono_method_get_header (cmethod);
7091
7092         if (cheader == NULL || mono_loader_get_last_error ()) {
7093                 if (cheader)
7094                         mono_metadata_free_mh (cheader);
7095                 if (inline_always && mono_loader_get_last_error ()) {
7096                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
7097                         mono_error_set_from_loader_error (&cfg->error);
7098                 }
7099
7100                 mono_loader_clear_error ();
7101                 return 0;
7102         }
7103
7104         /*Must verify before creating locals as it can cause the JIT to assert.*/
7105         if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
7106                 mono_metadata_free_mh (cheader);
7107                 return 0;
7108         }
7109
7110         /* allocate space to store the return value */
7111         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
7112                 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
7113         }
7114
7115         prev_locals = cfg->locals;
7116         cfg->locals = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));
7117         for (i = 0; i < cheader->num_locals; ++i)
7118                 cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
7119
7120         /* allocate start and end blocks */
7121         /* This is needed so if the inline is aborted, we can clean up */
7122         NEW_BBLOCK (cfg, sbblock);
7123         sbblock->real_offset = real_offset;
7124
7125         NEW_BBLOCK (cfg, ebblock);
7126         ebblock->block_num = cfg->num_bblocks++;
7127         ebblock->real_offset = real_offset;
7128
7129         prev_args = cfg->args;
7130         prev_arg_types = cfg->arg_types;
7131         prev_inlined_method = cfg->inlined_method;
7132         cfg->inlined_method = cmethod;
7133         cfg->ret_var_set = FALSE;
7134         cfg->inline_depth ++;
7135         prev_real_offset = cfg->real_offset;
7136         prev_cbb_hash = cfg->cbb_hash;
7137         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
7138         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
7139         prev_cil_start = cfg->cil_start;
7140         prev_cbb = cfg->cbb;
7141         prev_current_method = cfg->current_method;
7142         prev_generic_context = cfg->generic_context;
7143         prev_ret_var_set = cfg->ret_var_set;
7144         prev_disable_inline = cfg->disable_inline;
7145
7146         if (ip && *ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
7147                 virtual_ = TRUE;
7148
7149         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, sp, real_offset, virtual_);
7150
7151         ret_var_set = cfg->ret_var_set;
7152
7153         cfg->inlined_method = prev_inlined_method;
7154         cfg->real_offset = prev_real_offset;
7155         cfg->cbb_hash = prev_cbb_hash;
7156         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
7157         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
7158         cfg->cil_start = prev_cil_start;
7159         cfg->locals = prev_locals;
7160         cfg->args = prev_args;
7161         cfg->arg_types = prev_arg_types;
7162         cfg->current_method = prev_current_method;
7163         cfg->generic_context = prev_generic_context;
7164         cfg->ret_var_set = prev_ret_var_set;
7165         cfg->disable_inline = prev_disable_inline;
7166         cfg->inline_depth --;
7167
7168         if ((costs >= 0 && costs < 60) || inline_always || (costs >= 0 && (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))) {
7169                 if (cfg->verbose_level > 2)
7170                         printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
7171                 
7172                 cfg->stat_inlined_methods++;
7173
7174                 /* always add some code to avoid block split failures */
7175                 MONO_INST_NEW (cfg, ins, OP_NOP);
7176                 MONO_ADD_INS (prev_cbb, ins);
7177
7178                 prev_cbb->next_bb = sbblock;
7179                 link_bblock (cfg, prev_cbb, sbblock);
7180
7181                 /* 
7182                  * Get rid of the begin and end bblocks if possible to aid local
7183                  * optimizations.
7184                  */
7185                 mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
7186
7187                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
7188                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
7189
7190                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
7191                         MonoBasicBlock *prev = ebblock->in_bb [0];
7192
7193                         if (prev->next_bb == ebblock) {
7194                                 mono_merge_basic_blocks (cfg, prev, ebblock);
7195                                 cfg->cbb = prev;
7196                                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
7197                                         mono_merge_basic_blocks (cfg, prev_cbb, prev);
7198                                         cfg->cbb = prev_cbb;
7199                                 }
7200                         } else {
7201                                 /* There could be a bblock after 'prev', and making 'prev' the current bb could cause problems */
7202                                 cfg->cbb = ebblock;
7203                         }
7204                 } else {
7205                         /* 
7206                          * Its possible that the rvar is set in some prev bblock, but not in others.
7207                          * (#1835).
7208                          */
7209                         if (rvar) {
7210                                 MonoBasicBlock *bb;
7211
7212                                 for (i = 0; i < ebblock->in_count; ++i) {
7213                                         bb = ebblock->in_bb [i];
7214
7215                                         if (bb->last_ins && bb->last_ins->opcode == OP_NOT_REACHED) {
7216                                                 cfg->cbb = bb;
7217
7218                                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
7219                                         }
7220                                 }
7221                         }
7222
7223                         cfg->cbb = ebblock;
7224                 }
7225
7226                 if (rvar) {
7227                         /*
7228                          * If the inlined method contains only a throw, then the ret var is not 
7229                          * set, so set it to a dummy value.
7230                          */
7231                         if (!ret_var_set)
7232                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
7233
7234                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
7235                         *sp++ = ins;
7236                 }
7237                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
7238                 return costs + 1;
7239         } else {
7240                 if (cfg->verbose_level > 2)
7241                         printf ("INLINE ABORTED %s (cost %d)\n", mono_method_full_name (cmethod, TRUE), costs);
7242                 cfg->exception_type = MONO_EXCEPTION_NONE;
7243                 mono_loader_clear_error ();
7244
7245                 /* This gets rid of the newly added bblocks */
7246                 cfg->cbb = prev_cbb;
7247         }
7248         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
7249         return 0;
7250 }
7251
7252 /*
7253  * Some of these comments may well be out-of-date.
7254  * Design decisions: we do a single pass over the IL code (and we do bblock 
7255  * splitting/merging in the few cases when it's required: a back jump to an IL
7256  * address that was not already seen as bblock starting point).
7257  * Code is validated as we go (full verification is still better left to metadata/verify.c).
7258  * Complex operations are decomposed in simpler ones right away. We need to let the 
7259  * arch-specific code peek and poke inside this process somehow (except when the 
7260  * optimizations can take advantage of the full semantic info of coarse opcodes).
7261  * All the opcodes of the form opcode.s are 'normalized' to opcode.
7262  * MonoInst->opcode initially is the IL opcode or some simplification of that 
7263  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
7264  * opcode with value bigger than OP_LAST.
7265  * At this point the IR can be handed over to an interpreter, a dumb code generator
7266  * or to the optimizing code generator that will translate it to SSA form.
7267  *
7268  * Profiling directed optimizations.
7269  * We may compile by default with few or no optimizations and instrument the code
7270  * or the user may indicate what methods to optimize the most either in a config file
7271  * or through repeated runs where the compiler applies offline the optimizations to 
7272  * each method and then decides if it was worth it.
7273  */
7274
7275 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
7276 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
7277 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
7278 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
7279 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
7280 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
7281 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
7282 #define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) TYPE_LOAD_ERROR ((klass))
7283
7284 /* offset from br.s -> br like opcodes */
7285 #define BIG_BRANCH_OFFSET 13
7286
7287 static gboolean
7288 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
7289 {
7290         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
7291
7292         return b == NULL || b == bb;
7293 }
7294
7295 static int
7296 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
7297 {
7298         unsigned char *ip = start;
7299         unsigned char *target;
7300         int i;
7301         guint cli_addr;
7302         MonoBasicBlock *bblock;
7303         const MonoOpcode *opcode;
7304
7305         while (ip < end) {
7306                 cli_addr = ip - start;
7307                 i = mono_opcode_value ((const guint8 **)&ip, end);
7308                 if (i < 0)
7309                         UNVERIFIED;
7310                 opcode = &mono_opcodes [i];
7311                 switch (opcode->argument) {
7312                 case MonoInlineNone:
7313                         ip++; 
7314                         break;
7315                 case MonoInlineString:
7316                 case MonoInlineType:
7317                 case MonoInlineField:
7318                 case MonoInlineMethod:
7319                 case MonoInlineTok:
7320                 case MonoInlineSig:
7321                 case MonoShortInlineR:
7322                 case MonoInlineI:
7323                         ip += 5;
7324                         break;
7325                 case MonoInlineVar:
7326                         ip += 3;
7327                         break;
7328                 case MonoShortInlineVar:
7329                 case MonoShortInlineI:
7330                         ip += 2;
7331                         break;
7332                 case MonoShortInlineBrTarget:
7333                         target = start + cli_addr + 2 + (signed char)ip [1];
7334                         GET_BBLOCK (cfg, bblock, target);
7335                         ip += 2;
7336                         if (ip < end)
7337                                 GET_BBLOCK (cfg, bblock, ip);
7338                         break;
7339                 case MonoInlineBrTarget:
7340                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
7341                         GET_BBLOCK (cfg, bblock, target);
7342                         ip += 5;
7343                         if (ip < end)
7344                                 GET_BBLOCK (cfg, bblock, ip);
7345                         break;
7346                 case MonoInlineSwitch: {
7347                         guint32 n = read32 (ip + 1);
7348                         guint32 j;
7349                         ip += 5;
7350                         cli_addr += 5 + 4 * n;
7351                         target = start + cli_addr;
7352                         GET_BBLOCK (cfg, bblock, target);
7353                         
7354                         for (j = 0; j < n; ++j) {
7355                                 target = start + cli_addr + (gint32)read32 (ip);
7356                                 GET_BBLOCK (cfg, bblock, target);
7357                                 ip += 4;
7358                         }
7359                         break;
7360                 }
7361                 case MonoInlineR:
7362                 case MonoInlineI8:
7363                         ip += 9;
7364                         break;
7365                 default:
7366                         g_assert_not_reached ();
7367                 }
7368
7369                 if (i == CEE_THROW) {
7370                         unsigned char *bb_start = ip - 1;
7371                         
7372                         /* Find the start of the bblock containing the throw */
7373                         bblock = NULL;
7374                         while ((bb_start >= start) && !bblock) {
7375                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
7376                                 bb_start --;
7377                         }
7378                         if (bblock)
7379                                 bblock->out_of_line = 1;
7380                 }
7381         }
7382         return 0;
7383 unverified:
7384 exception_exit:
7385         *pos = ip;
7386         return 1;
7387 }
7388
7389 static inline MonoMethod *
7390 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context, MonoError *error)
7391 {
7392         MonoMethod *method;
7393
7394         mono_error_init (error);
7395
7396         if (m->wrapper_type != MONO_WRAPPER_NONE) {
7397                 method = (MonoMethod *)mono_method_get_wrapper_data (m, token);
7398                 if (context) {
7399                         method = mono_class_inflate_generic_method_checked (method, context, error);
7400                 }
7401         } else {
7402                 method = mono_get_method_checked (m->klass->image, token, klass, context, error);
7403         }
7404
7405         return method;
7406 }
7407
7408 static inline MonoMethod *
7409 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
7410 {
7411         MonoError error;
7412         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context, cfg ? &cfg->error : &error);
7413
7414         if (method && cfg && !cfg->gshared && mono_class_is_open_constructed_type (&method->klass->byval_arg)) {
7415                 mono_error_set_bad_image (&cfg->error, cfg->method->klass->image, "Method with open type while not compiling gshared");
7416                 method = NULL;
7417         }
7418
7419         if (!method && !cfg)
7420                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
7421
7422         return method;
7423 }
7424
7425 static inline MonoClass*
7426 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
7427 {
7428         MonoError error;
7429         MonoClass *klass;
7430
7431         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7432                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
7433                 if (context)
7434                         klass = mono_class_inflate_generic_class (klass, context);
7435         } else {
7436                 klass = mono_class_get_and_inflate_typespec_checked (method->klass->image, token, context, &error);
7437                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
7438         }
7439         if (klass)
7440                 mono_class_init (klass);
7441         return klass;
7442 }
7443
7444 static inline MonoMethodSignature*
7445 mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context)
7446 {
7447         MonoMethodSignature *fsig;
7448
7449         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7450                 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
7451         } else {
7452                 fsig = mono_metadata_parse_signature (method->klass->image, token);
7453         }
7454         if (context) {
7455                 MonoError error;
7456                 fsig = mono_inflate_generic_signature(fsig, context, &error);
7457                 // FIXME:
7458                 g_assert(mono_error_ok(&error));
7459         }
7460         return fsig;
7461 }
7462
7463 static MonoMethod*
7464 throw_exception (void)
7465 {
7466         static MonoMethod *method = NULL;
7467
7468         if (!method) {
7469                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
7470                 method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
7471         }
7472         g_assert (method);
7473         return method;
7474 }
7475
7476 static void
7477 emit_throw_exception (MonoCompile *cfg, MonoException *ex)
7478 {
7479         MonoMethod *thrower = throw_exception ();
7480         MonoInst *args [1];
7481
7482         EMIT_NEW_PCONST (cfg, args [0], ex);
7483         mono_emit_method_call (cfg, thrower, args, NULL);
7484 }
7485
7486 /*
7487  * Return the original method is a wrapper is specified. We can only access 
7488  * the custom attributes from the original method.
7489  */
7490 static MonoMethod*
7491 get_original_method (MonoMethod *method)
7492 {
7493         if (method->wrapper_type == MONO_WRAPPER_NONE)
7494                 return method;
7495
7496         /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
7497         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
7498                 return NULL;
7499
7500         /* in other cases we need to find the original method */
7501         return mono_marshal_method_from_wrapper (method);
7502 }
7503
7504 static void
7505 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field)
7506 {
7507         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7508         MonoException *ex = mono_security_core_clr_is_field_access_allowed (get_original_method (caller), field);
7509         if (ex)
7510                 emit_throw_exception (cfg, ex);
7511 }
7512
7513 static void
7514 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
7515 {
7516         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7517         MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
7518         if (ex)
7519                 emit_throw_exception (cfg, ex);
7520 }
7521
7522 /*
7523  * Check that the IL instructions at ip are the array initialization
7524  * sequence and return the pointer to the data and the size.
7525  */
7526 static const char*
7527 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
7528 {
7529         /*
7530          * newarr[System.Int32]
7531          * dup
7532          * ldtoken field valuetype ...
7533          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
7534          */
7535         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
7536                 MonoError error;
7537                 guint32 token = read32 (ip + 7);
7538                 guint32 field_token = read32 (ip + 2);
7539                 guint32 field_index = field_token & 0xffffff;
7540                 guint32 rva;
7541                 const char *data_ptr;
7542                 int size = 0;
7543                 MonoMethod *cmethod;
7544                 MonoClass *dummy_class;
7545                 MonoClassField *field = mono_field_from_token_checked (method->klass->image, field_token, &dummy_class, NULL, &error);
7546                 int dummy_align;
7547
7548                 if (!field) {
7549                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7550                         return NULL;
7551                 }
7552
7553                 *out_field_token = field_token;
7554
7555                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
7556                 if (!cmethod)
7557                         return NULL;
7558                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
7559                         return NULL;
7560                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
7561                 case MONO_TYPE_BOOLEAN:
7562                 case MONO_TYPE_I1:
7563                 case MONO_TYPE_U1:
7564                         size = 1; break;
7565                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
7566 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
7567                 case MONO_TYPE_CHAR:
7568                 case MONO_TYPE_I2:
7569                 case MONO_TYPE_U2:
7570                         size = 2; break;
7571                 case MONO_TYPE_I4:
7572                 case MONO_TYPE_U4:
7573                 case MONO_TYPE_R4:
7574                         size = 4; break;
7575                 case MONO_TYPE_R8:
7576                 case MONO_TYPE_I8:
7577                 case MONO_TYPE_U8:
7578                         size = 8; break;
7579 #endif
7580                 default:
7581                         return NULL;
7582                 }
7583                 size *= len;
7584                 if (size > mono_type_size (field->type, &dummy_align))
7585                     return NULL;
7586                 *out_size = size;
7587                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
7588                 if (!image_is_dynamic (method->klass->image)) {
7589                         field_index = read32 (ip + 2) & 0xffffff;
7590                         mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
7591                         data_ptr = mono_image_rva_map (method->klass->image, rva);
7592                         /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
7593                         /* for aot code we do the lookup on load */
7594                         if (aot && data_ptr)
7595                                 return (const char *)GUINT_TO_POINTER (rva);
7596                 } else {
7597                         /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
7598                         g_assert (!aot);
7599                         data_ptr = mono_field_get_data (field);
7600                 }
7601                 return data_ptr;
7602         }
7603         return NULL;
7604 }
7605
7606 static void
7607 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
7608 {
7609         char *method_fname = mono_method_full_name (method, TRUE);
7610         char *method_code;
7611         MonoMethodHeader *header = mono_method_get_header (method);
7612
7613         if (header->code_size == 0)
7614                 method_code = g_strdup ("method body is empty.");
7615         else
7616                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
7617         mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code));
7618         g_free (method_fname);
7619         g_free (method_code);
7620         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
7621 }
7622
7623 static void
7624 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
7625 {
7626         MonoInst *ins;
7627         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
7628         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
7629                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
7630                 /* Optimize reg-reg moves away */
7631                 /* 
7632                  * Can't optimize other opcodes, since sp[0] might point to
7633                  * the last ins of a decomposed opcode.
7634                  */
7635                 sp [0]->dreg = (cfg)->locals [n]->dreg;
7636         } else {
7637                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
7638         }
7639 }
7640
7641 /*
7642  * ldloca inhibits many optimizations so try to get rid of it in common
7643  * cases.
7644  */
7645 static inline unsigned char *
7646 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
7647 {
7648         int local, token;
7649         MonoClass *klass;
7650         MonoType *type;
7651
7652         if (size == 1) {
7653                 local = ip [1];
7654                 ip += 2;
7655         } else {
7656                 local = read16 (ip + 2);
7657                 ip += 4;
7658         }
7659         
7660         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
7661                 /* From the INITOBJ case */
7662                 token = read32 (ip + 2);
7663                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
7664                 CHECK_TYPELOAD (klass);
7665                 type = mini_get_underlying_type (&klass->byval_arg);
7666                 emit_init_local (cfg, local, type, TRUE);
7667                 return ip + 6;
7668         }
7669  exception_exit:
7670         return NULL;
7671 }
7672
7673 static MonoInst*
7674 emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used, MonoInst **sp)
7675 {
7676         MonoInst *icall_args [16];
7677         MonoInst *call_target, *ins, *vtable_ins;
7678         int arg_reg, this_reg, vtable_reg;
7679         gboolean is_iface = cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE;
7680         gboolean is_gsharedvt = cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig);
7681         gboolean variant_iface = FALSE;
7682         guint32 slot;
7683         int offset;
7684
7685         /*
7686          * In llvm-only mode, vtables contain function descriptors instead of
7687          * method addresses/trampolines.
7688          */
7689         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
7690
7691         if (is_iface)
7692                 slot = mono_method_get_imt_slot (cmethod);
7693         else
7694                 slot = mono_method_get_vtable_index (cmethod);
7695
7696         this_reg = sp [0]->dreg;
7697
7698         if (is_iface && mono_class_has_variant_generic_params (cmethod->klass))
7699                 variant_iface = TRUE;
7700
7701         if (!fsig->generic_param_count && !is_iface && !is_gsharedvt) {
7702                 /*
7703                  * The simplest case, a normal virtual call.
7704                  */
7705                 int slot_reg = alloc_preg (cfg);
7706                 int addr_reg = alloc_preg (cfg);
7707                 int arg_reg = alloc_preg (cfg);
7708                 MonoBasicBlock *non_null_bb;
7709
7710                 vtable_reg = alloc_preg (cfg);
7711                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7712                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) + (slot * SIZEOF_VOID_P);
7713
7714                 /* Load the vtable slot, which contains a function descriptor. */
7715                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7716
7717                 NEW_BBLOCK (cfg, non_null_bb);
7718
7719                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, slot_reg, 0);
7720                 cfg->cbb->last_ins->flags |= MONO_INST_LIKELY;
7721                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, non_null_bb);
7722
7723                 /* Slow path */
7724                 // FIXME: Make the wrapper use the preserveall cconv
7725                 // FIXME: Use one icall per slot for small slot numbers ?
7726                 icall_args [0] = vtable_ins;
7727                 EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7728                 /* Make the icall return the vtable slot value to save some code space */
7729                 ins = mono_emit_jit_icall (cfg, mono_init_vtable_slot, icall_args);
7730                 ins->dreg = slot_reg;
7731                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, non_null_bb);
7732
7733                 /* Fastpath */
7734                 MONO_START_BB (cfg, non_null_bb);
7735                 /* Load the address + arg from the vtable slot */
7736                 EMIT_NEW_LOAD_MEMBASE (cfg, call_target, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7737                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, arg_reg, slot_reg, SIZEOF_VOID_P);
7738
7739                 return emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
7740         }
7741
7742         if (!fsig->generic_param_count && is_iface && !variant_iface && !is_gsharedvt) {
7743                 /*
7744                  * A simple interface call
7745                  *
7746                  * We make a call through an imt slot to obtain the function descriptor we need to call.
7747                  * The imt slot contains a function descriptor for a runtime function + arg.
7748                  */
7749                 int slot_reg = alloc_preg (cfg);
7750                 int addr_reg = alloc_preg (cfg);
7751                 int arg_reg = alloc_preg (cfg);
7752                 MonoInst *thunk_addr_ins, *thunk_arg_ins, *ftndesc_ins;
7753
7754                 vtable_reg = alloc_preg (cfg);
7755                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7756                 offset = ((gint32)slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
7757
7758                 /*
7759                  * The slot is already initialized when the vtable is created so there is no need
7760                  * to check it here.
7761                  */
7762
7763                 /* Load the imt slot, which contains a function descriptor. */
7764                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7765
7766                 /* Load the address + arg of the imt thunk from the imt slot */
7767                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_addr_ins, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7768                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_arg_ins, OP_LOAD_MEMBASE, arg_reg, slot_reg, SIZEOF_VOID_P);
7769                 /*
7770                  * IMT thunks in llvm-only mode are C functions which take an info argument
7771                  * plus the imt method and return the ftndesc to call.
7772                  */
7773                 icall_args [0] = thunk_arg_ins;
7774                 icall_args [1] = emit_get_rgctx_method (cfg, context_used,
7775                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7776                 ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_thunk, icall_args, thunk_addr_ins, NULL, NULL);
7777
7778                 return emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
7779         }
7780
7781         if ((fsig->generic_param_count || variant_iface) && !is_gsharedvt) {
7782                 /*
7783                  * This is similar to the interface case, the vtable slot points to an imt thunk which is
7784                  * dynamically extended as more instantiations are discovered.
7785                  * This handles generic virtual methods both on classes and interfaces.
7786                  */
7787                 int slot_reg = alloc_preg (cfg);
7788                 int addr_reg = alloc_preg (cfg);
7789                 int arg_reg = alloc_preg (cfg);
7790                 int ftndesc_reg = alloc_preg (cfg);
7791                 MonoInst *thunk_addr_ins, *thunk_arg_ins, *ftndesc_ins;
7792                 MonoBasicBlock *slowpath_bb, *end_bb;
7793
7794                 NEW_BBLOCK (cfg, slowpath_bb);
7795                 NEW_BBLOCK (cfg, end_bb);
7796
7797                 vtable_reg = alloc_preg (cfg);
7798                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7799                 if (is_iface)
7800                         offset = ((gint32)slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
7801                 else
7802                         offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) + (slot * SIZEOF_VOID_P);
7803
7804                 /* Load the slot, which contains a function descriptor. */
7805                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7806
7807                 /* These slots are not initialized, so fall back to the slow path until they are initialized */
7808                 /* That happens when mono_method_add_generic_virtual_invocation () creates an IMT thunk */
7809                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, slot_reg, 0);
7810                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, slowpath_bb);
7811
7812                 /* Fastpath */
7813                 /* Same as with iface calls */
7814                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_addr_ins, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7815                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_arg_ins, OP_LOAD_MEMBASE, arg_reg, slot_reg, SIZEOF_VOID_P);
7816                 icall_args [0] = thunk_arg_ins;
7817                 icall_args [1] = emit_get_rgctx_method (cfg, context_used,
7818                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7819                 ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_thunk, icall_args, thunk_addr_ins, NULL, NULL);
7820                 ftndesc_ins->dreg = ftndesc_reg;
7821                 /*
7822                  * Unlike normal iface calls, these imt thunks can return NULL, i.e. when they are passed an instantiation
7823                  * they don't know about yet. Fall back to the slowpath in that case.
7824                  */
7825                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ftndesc_reg, 0);
7826                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, slowpath_bb);
7827
7828                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
7829
7830                 /* Slowpath */
7831                 MONO_START_BB (cfg, slowpath_bb);
7832                 icall_args [0] = vtable_ins;
7833                 EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7834                 icall_args [2] = emit_get_rgctx_method (cfg, context_used,
7835                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7836                 if (is_iface)
7837                         ftndesc_ins = mono_emit_jit_icall (cfg, mono_resolve_generic_virtual_iface_call, icall_args);
7838                 else
7839                         ftndesc_ins = mono_emit_jit_icall (cfg, mono_resolve_generic_virtual_call, icall_args);
7840                 ftndesc_ins->dreg = ftndesc_reg;
7841                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
7842
7843                 /* Common case */
7844                 MONO_START_BB (cfg, end_bb);
7845                 return emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
7846         }
7847
7848         /*
7849          * Non-optimized cases
7850          */
7851         icall_args [0] = sp [0];
7852         EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7853
7854         icall_args [2] = emit_get_rgctx_method (cfg, context_used,
7855                                                                                         cmethod, MONO_RGCTX_INFO_METHOD);
7856
7857         arg_reg = alloc_preg (cfg);
7858         MONO_EMIT_NEW_PCONST (cfg, arg_reg, NULL);
7859         EMIT_NEW_VARLOADA_VREG (cfg, icall_args [3], arg_reg, &mono_defaults.int_class->byval_arg);
7860
7861         g_assert (is_gsharedvt);
7862         if (is_iface)
7863                 call_target = mono_emit_jit_icall (cfg, mono_resolve_iface_call_gsharedvt, icall_args);
7864         else
7865                 call_target = mono_emit_jit_icall (cfg, mono_resolve_vcall_gsharedvt, icall_args);
7866
7867         /*
7868          * Pass the extra argument even if the callee doesn't receive it, most
7869          * calling conventions allow this.
7870          */
7871         return emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
7872 }
7873
7874 static gboolean
7875 is_exception_class (MonoClass *klass)
7876 {
7877         while (klass) {
7878                 if (klass == mono_defaults.exception_class)
7879                         return TRUE;
7880                 klass = klass->parent;
7881         }
7882         return FALSE;
7883 }
7884
7885 /*
7886  * is_jit_optimizer_disabled:
7887  *
7888  *   Determine whenever M's assembly has a DebuggableAttribute with the
7889  * IsJITOptimizerDisabled flag set.
7890  */
7891 static gboolean
7892 is_jit_optimizer_disabled (MonoMethod *m)
7893 {
7894         MonoAssembly *ass = m->klass->image->assembly;
7895         MonoCustomAttrInfo* attrs;
7896         static MonoClass *klass;
7897         int i;
7898         gboolean val = FALSE;
7899
7900         g_assert (ass);
7901         if (ass->jit_optimizer_disabled_inited)
7902                 return ass->jit_optimizer_disabled;
7903
7904         if (!klass)
7905                 klass = mono_class_from_name (mono_defaults.corlib, "System.Diagnostics", "DebuggableAttribute");
7906         if (!klass) {
7907                 /* Linked away */
7908                 ass->jit_optimizer_disabled = FALSE;
7909                 mono_memory_barrier ();
7910                 ass->jit_optimizer_disabled_inited = TRUE;
7911                 return FALSE;
7912         }
7913
7914         attrs = mono_custom_attrs_from_assembly (ass);
7915         if (attrs) {
7916                 for (i = 0; i < attrs->num_attrs; ++i) {
7917                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
7918                         const gchar *p;
7919                         MonoMethodSignature *sig;
7920
7921                         if (!attr->ctor || attr->ctor->klass != klass)
7922                                 continue;
7923                         /* Decode the attribute. See reflection.c */
7924                         p = (const char*)attr->data;
7925                         g_assert (read16 (p) == 0x0001);
7926                         p += 2;
7927
7928                         // FIXME: Support named parameters
7929                         sig = mono_method_signature (attr->ctor);
7930                         if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
7931                                 continue;
7932                         /* Two boolean arguments */
7933                         p ++;
7934                         val = *p;
7935                 }
7936                 mono_custom_attrs_free (attrs);
7937         }
7938
7939         ass->jit_optimizer_disabled = val;
7940         mono_memory_barrier ();
7941         ass->jit_optimizer_disabled_inited = TRUE;
7942
7943         return val;
7944 }
7945
7946 static gboolean
7947 is_supported_tail_call (MonoCompile *cfg, MonoMethod *method, MonoMethod *cmethod, MonoMethodSignature *fsig, int call_opcode)
7948 {
7949         gboolean supported_tail_call;
7950         int i;
7951
7952         supported_tail_call = mono_arch_tail_call_supported (cfg, mono_method_signature (method), mono_method_signature (cmethod));
7953
7954         for (i = 0; i < fsig->param_count; ++i) {
7955                 if (fsig->params [i]->byref || fsig->params [i]->type == MONO_TYPE_PTR || fsig->params [i]->type == MONO_TYPE_FNPTR)
7956                         /* These can point to the current method's stack */
7957                         supported_tail_call = FALSE;
7958         }
7959         if (fsig->hasthis && cmethod->klass->valuetype)
7960                 /* this might point to the current method's stack */
7961                 supported_tail_call = FALSE;
7962         if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
7963                 supported_tail_call = FALSE;
7964         if (cfg->method->save_lmf)
7965                 supported_tail_call = FALSE;
7966         if (cmethod->wrapper_type && cmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
7967                 supported_tail_call = FALSE;
7968         if (call_opcode != CEE_CALL)
7969                 supported_tail_call = FALSE;
7970
7971         /* Debugging support */
7972 #if 0
7973         if (supported_tail_call) {
7974                 if (!mono_debug_count ())
7975                         supported_tail_call = FALSE;
7976         }
7977 #endif
7978
7979         return supported_tail_call;
7980 }
7981
7982 /*
7983  * handle_ctor_call:
7984  *
7985  *   Handle calls made to ctors from NEWOBJ opcodes.
7986  */
7987 static void
7988 handle_ctor_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used,
7989                                   MonoInst **sp, guint8 *ip, int *inline_costs)
7990 {
7991         MonoInst *vtable_arg = NULL, *callvirt_this_arg = NULL, *ins;
7992
7993         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
7994                                         mono_method_is_generic_sharable (cmethod, TRUE)) {
7995                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
7996                         mono_class_vtable (cfg->domain, cmethod->klass);
7997                         CHECK_TYPELOAD (cmethod->klass);
7998
7999                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
8000                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
8001                 } else {
8002                         if (context_used) {
8003                                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
8004                                                                                                    cmethod->klass, MONO_RGCTX_INFO_VTABLE);
8005                         } else {
8006                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
8007
8008                                 CHECK_TYPELOAD (cmethod->klass);
8009                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
8010                         }
8011                 }
8012         }
8013
8014         /* Avoid virtual calls to ctors if possible */
8015         if (mono_class_is_marshalbyref (cmethod->klass))
8016                 callvirt_this_arg = sp [0];
8017
8018         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
8019                 g_assert (MONO_TYPE_IS_VOID (fsig->ret));
8020                 CHECK_CFG_EXCEPTION;
8021         } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
8022                            mono_method_check_inlining (cfg, cmethod) &&
8023                            !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE)) {
8024                 int costs;
8025
8026                 if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, FALSE))) {
8027                         cfg->real_offset += 5;
8028
8029                         *inline_costs += costs - 5;
8030                 } else {
8031                         INLINE_FAILURE ("inline failure");
8032                         // FIXME-VT: Clean this up
8033                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
8034                                 GSHAREDVT_FAILURE(*ip);
8035                         mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, callvirt_this_arg, NULL, NULL);
8036                 }
8037         } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
8038                 MonoInst *addr;
8039
8040                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
8041
8042                 if (cfg->llvm_only) {
8043                         // FIXME: Avoid initializing vtable_arg
8044                         emit_llvmonly_calli (cfg, fsig, sp, addr);
8045                 } else {
8046                         mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
8047                 }
8048         } else if (context_used &&
8049                            ((!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
8050                                  !mono_class_generic_sharing_enabled (cmethod->klass)) || cfg->gsharedvt)) {
8051                 MonoInst *cmethod_addr;
8052
8053                 /* Generic calls made out of gsharedvt methods cannot be patched, so use an indirect call */
8054
8055                 if (cfg->llvm_only) {
8056                         MonoInst *addr = emit_get_rgctx_method (cfg, context_used, cmethod,
8057                                                                                                         MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
8058                         emit_llvmonly_calli (cfg, fsig, sp, addr);
8059                 } else {
8060                         cmethod_addr = emit_get_rgctx_method (cfg, context_used,
8061                                                                                                   cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
8062
8063                         mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
8064                 }
8065         } else {
8066                 INLINE_FAILURE ("ctor call");
8067                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
8068                                                                                   callvirt_this_arg, NULL, vtable_arg);
8069         }
8070  exception_exit:
8071         return;
8072 }
8073
8074 static void
8075 emit_setret (MonoCompile *cfg, MonoInst *val)
8076 {
8077         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (cfg->method)->ret);
8078         MonoInst *ins;
8079
8080         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
8081                 MonoInst *ret_addr;
8082
8083                 if (!cfg->vret_addr) {
8084                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, val);
8085                 } else {
8086                         EMIT_NEW_RETLOADA (cfg, ret_addr);
8087
8088                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, val->dreg);
8089                         ins->klass = mono_class_from_mono_type (ret_type);
8090                 }
8091         } else {
8092 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
8093                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
8094                         MonoInst *iargs [1];
8095                         MonoInst *conv;
8096
8097                         iargs [0] = val;
8098                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
8099                         mono_arch_emit_setret (cfg, cfg->method, conv);
8100                 } else {
8101                         mono_arch_emit_setret (cfg, cfg->method, val);
8102                 }
8103 #else
8104                 mono_arch_emit_setret (cfg, cfg->method, val);
8105 #endif
8106         }
8107 }
8108
8109 /*
8110  * mono_method_to_ir:
8111  *
8112  *   Translate the .net IL into linear IR.
8113  */
8114 int
8115 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
8116                    MonoInst *return_var, MonoInst **inline_args, 
8117                    guint inline_offset, gboolean is_virtual_call)
8118 {
8119         MonoError error;
8120         MonoInst *ins, **sp, **stack_start;
8121         MonoBasicBlock *tblock = NULL, *init_localsbb = NULL;
8122         MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
8123         MonoMethod *cmethod, *method_definition;
8124         MonoInst **arg_array;
8125         MonoMethodHeader *header;
8126         MonoImage *image;
8127         guint32 token, ins_flag;
8128         MonoClass *klass;
8129         MonoClass *constrained_class = NULL;
8130         unsigned char *ip, *end, *target, *err_pos;
8131         MonoMethodSignature *sig;
8132         MonoGenericContext *generic_context = NULL;
8133         MonoGenericContainer *generic_container = NULL;
8134         MonoType **param_types;
8135         int i, n, start_new_bblock, dreg;
8136         int num_calls = 0, inline_costs = 0;
8137         int breakpoint_id = 0;
8138         guint num_args;
8139         GSList *class_inits = NULL;
8140         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
8141         int context_used;
8142         gboolean init_locals, seq_points, skip_dead_blocks;
8143         gboolean sym_seq_points = FALSE;
8144         MonoDebugMethodInfo *minfo;
8145         MonoBitSet *seq_point_locs = NULL;
8146         MonoBitSet *seq_point_set_locs = NULL;
8147
8148         cfg->disable_inline = is_jit_optimizer_disabled (method);
8149
8150         /* serialization and xdomain stuff may need access to private fields and methods */
8151         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
8152         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
8153         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
8154         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
8155         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
8156         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
8157
8158         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
8159         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
8160         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
8161         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
8162         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF;
8163
8164         image = method->klass->image;
8165         header = mono_method_get_header (method);
8166         if (!header) {
8167                 if (mono_loader_get_last_error ()) {
8168                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
8169                         mono_error_set_from_loader_error (&cfg->error);
8170                 } else {
8171                         mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name));
8172                 }
8173                 goto exception_exit;
8174         }
8175         generic_container = mono_method_get_generic_container (method);
8176         sig = mono_method_signature (method);
8177         num_args = sig->hasthis + sig->param_count;
8178         ip = (unsigned char*)header->code;
8179         cfg->cil_start = ip;
8180         end = ip + header->code_size;
8181         cfg->stat_cil_code_size += header->code_size;
8182
8183         seq_points = cfg->gen_seq_points && cfg->method == method;
8184
8185         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
8186                 /* We could hit a seq point before attaching to the JIT (#8338) */
8187                 seq_points = FALSE;
8188         }
8189
8190         if (cfg->gen_sdb_seq_points && cfg->method == method) {
8191                 minfo = mono_debug_lookup_method (method);
8192                 if (minfo) {
8193                         MonoSymSeqPoint *sps;
8194                         int i, n_il_offsets;
8195
8196                         mono_debug_get_seq_points (minfo, NULL, NULL, NULL, &sps, &n_il_offsets);
8197                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
8198                         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);
8199                         sym_seq_points = TRUE;
8200                         for (i = 0; i < n_il_offsets; ++i) {
8201                                 if (sps [i].il_offset < header->code_size)
8202                                         mono_bitset_set_fast (seq_point_locs, sps [i].il_offset);
8203                         }
8204                         g_free (sps);
8205                 } else if (!method->wrapper_type && !method->dynamic && mono_debug_image_has_debug_info (method->klass->image)) {
8206                         /* Methods without line number info like auto-generated property accessors */
8207                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
8208                         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);
8209                         sym_seq_points = TRUE;
8210                 }
8211         }
8212
8213         /* 
8214          * Methods without init_locals set could cause asserts in various passes
8215          * (#497220). To work around this, we emit dummy initialization opcodes
8216          * (OP_DUMMY_ICONST etc.) which generate no code. These are only supported
8217          * on some platforms.
8218          */
8219         if ((cfg->opt & MONO_OPT_UNSAFE) && cfg->backend->have_dummy_init)
8220                 init_locals = header->init_locals;
8221         else
8222                 init_locals = TRUE;
8223
8224         method_definition = method;
8225         while (method_definition->is_inflated) {
8226                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
8227                 method_definition = imethod->declaring;
8228         }
8229
8230         /* SkipVerification is not allowed if core-clr is enabled */
8231         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
8232                 dont_verify = TRUE;
8233                 dont_verify_stloc = TRUE;
8234         }
8235
8236         if (sig->is_inflated)
8237                 generic_context = mono_method_get_context (method);
8238         else if (generic_container)
8239                 generic_context = &generic_container->context;
8240         cfg->generic_context = generic_context;
8241
8242         if (!cfg->gshared)
8243                 g_assert (!sig->has_type_parameters);
8244
8245         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
8246                 g_assert (method->is_inflated);
8247                 g_assert (mono_method_get_context (method)->method_inst);
8248         }
8249         if (method->is_inflated && mono_method_get_context (method)->method_inst)
8250                 g_assert (sig->generic_param_count);
8251
8252         if (cfg->method == method) {
8253                 cfg->real_offset = 0;
8254         } else {
8255                 cfg->real_offset = inline_offset;
8256         }
8257
8258         cfg->cil_offset_to_bb = (MonoBasicBlock **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
8259         cfg->cil_offset_to_bb_len = header->code_size;
8260
8261         cfg->current_method = method;
8262
8263         if (cfg->verbose_level > 2)
8264                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
8265
8266         param_types = (MonoType **)mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
8267         if (sig->hasthis)
8268                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
8269         for (n = 0; n < sig->param_count; ++n)
8270                 param_types [n + sig->hasthis] = sig->params [n];
8271         cfg->arg_types = param_types;
8272
8273         cfg->dont_inline = g_list_prepend (cfg->dont_inline, method);
8274         if (cfg->method == method) {
8275
8276                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
8277                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
8278
8279                 /* ENTRY BLOCK */
8280                 NEW_BBLOCK (cfg, start_bblock);
8281                 cfg->bb_entry = start_bblock;
8282                 start_bblock->cil_code = NULL;
8283                 start_bblock->cil_length = 0;
8284
8285                 /* EXIT BLOCK */
8286                 NEW_BBLOCK (cfg, end_bblock);
8287                 cfg->bb_exit = end_bblock;
8288                 end_bblock->cil_code = NULL;
8289                 end_bblock->cil_length = 0;
8290                 end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
8291                 g_assert (cfg->num_bblocks == 2);
8292
8293                 arg_array = cfg->args;
8294
8295                 if (header->num_clauses) {
8296                         cfg->spvars = g_hash_table_new (NULL, NULL);
8297                         cfg->exvars = g_hash_table_new (NULL, NULL);
8298                 }
8299                 /* handle exception clauses */
8300                 for (i = 0; i < header->num_clauses; ++i) {
8301                         MonoBasicBlock *try_bb;
8302                         MonoExceptionClause *clause = &header->clauses [i];
8303                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
8304
8305                         try_bb->real_offset = clause->try_offset;
8306                         try_bb->try_start = TRUE;
8307                         try_bb->region = ((i + 1) << 8) | clause->flags;
8308                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
8309                         tblock->real_offset = clause->handler_offset;
8310                         tblock->flags |= BB_EXCEPTION_HANDLER;
8311
8312                         /*
8313                          * Linking the try block with the EH block hinders inlining as we won't be able to 
8314                          * merge the bblocks from inlining and produce an artificial hole for no good reason.
8315                          */
8316                         if (COMPILE_LLVM (cfg))
8317                                 link_bblock (cfg, try_bb, tblock);
8318
8319                         if (*(ip + clause->handler_offset) == CEE_POP)
8320                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
8321
8322                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
8323                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
8324                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
8325                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
8326                                 MONO_ADD_INS (tblock, ins);
8327
8328                                 if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FILTER) {
8329                                         /* finally clauses already have a seq point */
8330                                         /* seq points for filter clauses are emitted below */
8331                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
8332                                         MONO_ADD_INS (tblock, ins);
8333                                 }
8334
8335                                 /* todo: is a fault block unsafe to optimize? */
8336                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
8337                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
8338                         }
8339
8340                         /*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);
8341                           while (p < end) {
8342                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
8343                           }*/
8344                         /* catch and filter blocks get the exception object on the stack */
8345                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
8346                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8347
8348                                 /* mostly like handle_stack_args (), but just sets the input args */
8349                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
8350                                 tblock->in_scount = 1;
8351                                 tblock->in_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
8352                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
8353
8354                                 cfg->cbb = tblock;
8355
8356 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
8357                                 /* The EH code passes in the exception in a register to both JITted and LLVM compiled code */
8358                                 if (!cfg->compile_llvm) {
8359                                         MONO_INST_NEW (cfg, ins, OP_GET_EX_OBJ);
8360                                         ins->dreg = tblock->in_stack [0]->dreg;
8361                                         MONO_ADD_INS (tblock, ins);
8362                                 }
8363 #else
8364                                 MonoInst *dummy_use;
8365
8366                                 /* 
8367                                  * Add a dummy use for the exvar so its liveness info will be
8368                                  * correct.
8369                                  */
8370                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
8371 #endif
8372
8373                                 if (seq_points && clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8374                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
8375                                         MONO_ADD_INS (tblock, ins);
8376                                 }
8377                                 
8378                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8379                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
8380                                         tblock->flags |= BB_EXCEPTION_HANDLER;
8381                                         tblock->real_offset = clause->data.filter_offset;
8382                                         tblock->in_scount = 1;
8383                                         tblock->in_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
8384                                         /* The filter block shares the exvar with the handler block */
8385                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
8386                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
8387                                         MONO_ADD_INS (tblock, ins);
8388                                 }
8389                         }
8390
8391                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
8392                                         clause->data.catch_class &&
8393                                         cfg->gshared &&
8394                                         mono_class_check_context_used (clause->data.catch_class)) {
8395                                 /*
8396                                  * In shared generic code with catch
8397                                  * clauses containing type variables
8398                                  * the exception handling code has to
8399                                  * be able to get to the rgctx.
8400                                  * Therefore we have to make sure that
8401                                  * the vtable/mrgctx argument (for
8402                                  * static or generic methods) or the
8403                                  * "this" argument (for non-static
8404                                  * methods) are live.
8405                                  */
8406                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8407                                                 mini_method_get_context (method)->method_inst ||
8408                                                 method->klass->valuetype) {
8409                                         mono_get_vtable_var (cfg);
8410                                 } else {
8411                                         MonoInst *dummy_use;
8412
8413                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
8414                                 }
8415                         }
8416                 }
8417         } else {
8418                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
8419                 cfg->cbb = start_bblock;
8420                 cfg->args = arg_array;
8421                 mono_save_args (cfg, sig, inline_args);
8422         }
8423
8424         /* FIRST CODE BLOCK */
8425         NEW_BBLOCK (cfg, tblock);
8426         tblock->cil_code = ip;
8427         cfg->cbb = tblock;
8428         cfg->ip = ip;
8429
8430         ADD_BBLOCK (cfg, tblock);
8431
8432         if (cfg->method == method) {
8433                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
8434                 if (breakpoint_id) {
8435                         MONO_INST_NEW (cfg, ins, OP_BREAK);
8436                         MONO_ADD_INS (cfg->cbb, ins);
8437                 }
8438         }
8439
8440         /* we use a separate basic block for the initialization code */
8441         NEW_BBLOCK (cfg, init_localsbb);
8442         cfg->bb_init = init_localsbb;
8443         init_localsbb->real_offset = cfg->real_offset;
8444         start_bblock->next_bb = init_localsbb;
8445         init_localsbb->next_bb = cfg->cbb;
8446         link_bblock (cfg, start_bblock, init_localsbb);
8447         link_bblock (cfg, init_localsbb, cfg->cbb);
8448                 
8449         cfg->cbb = init_localsbb;
8450
8451         if (cfg->gsharedvt && cfg->method == method) {
8452                 MonoGSharedVtMethodInfo *info;
8453                 MonoInst *var, *locals_var;
8454                 int dreg;
8455
8456                 info = (MonoGSharedVtMethodInfo *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoGSharedVtMethodInfo));
8457                 info->method = cfg->method;
8458                 info->count_entries = 16;
8459                 info->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
8460                 cfg->gsharedvt_info = info;
8461
8462                 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8463                 /* prevent it from being register allocated */
8464                 //var->flags |= MONO_INST_VOLATILE;
8465                 cfg->gsharedvt_info_var = var;
8466
8467                 ins = emit_get_rgctx_gsharedvt_method (cfg, mini_method_check_context_used (cfg, method), method, info);
8468                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, var->dreg, ins->dreg);
8469
8470                 /* Allocate locals */
8471                 locals_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8472                 /* prevent it from being register allocated */
8473                 //locals_var->flags |= MONO_INST_VOLATILE;
8474                 cfg->gsharedvt_locals_var = locals_var;
8475
8476                 dreg = alloc_ireg (cfg);
8477                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, dreg, var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, locals_size));
8478
8479                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
8480                 ins->dreg = locals_var->dreg;
8481                 ins->sreg1 = dreg;
8482                 MONO_ADD_INS (cfg->cbb, ins);
8483                 cfg->gsharedvt_locals_var_ins = ins;
8484                 
8485                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
8486                 /*
8487                 if (init_locals)
8488                         ins->flags |= MONO_INST_INIT;
8489                 */
8490         }
8491
8492         if (mono_security_core_clr_enabled ()) {
8493                 /* check if this is native code, e.g. an icall or a p/invoke */
8494                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
8495                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
8496                         if (wrapped) {
8497                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
8498                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
8499
8500                                 /* if this ia a native call then it can only be JITted from platform code */
8501                                 if ((icall || pinvk) && method->klass && method->klass->image) {
8502                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
8503                                                 MonoException *ex = icall ? mono_get_exception_security () : 
8504                                                         mono_get_exception_method_access ();
8505                                                 emit_throw_exception (cfg, ex);
8506                                         }
8507                                 }
8508                         }
8509                 }
8510         }
8511
8512         CHECK_CFG_EXCEPTION;
8513
8514         if (header->code_size == 0)
8515                 UNVERIFIED;
8516
8517         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
8518                 ip = err_pos;
8519                 UNVERIFIED;
8520         }
8521
8522         if (cfg->method == method)
8523                 mono_debug_init_method (cfg, cfg->cbb, breakpoint_id);
8524
8525         for (n = 0; n < header->num_locals; ++n) {
8526                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
8527                         UNVERIFIED;
8528         }
8529         class_inits = NULL;
8530
8531         /* We force the vtable variable here for all shared methods
8532            for the possibility that they might show up in a stack
8533            trace where their exact instantiation is needed. */
8534         if (cfg->gshared && method == cfg->method) {
8535                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8536                                 mini_method_get_context (method)->method_inst ||
8537                                 method->klass->valuetype) {
8538                         mono_get_vtable_var (cfg);
8539                 } else {
8540                         /* FIXME: Is there a better way to do this?
8541                            We need the variable live for the duration
8542                            of the whole method. */
8543                         cfg->args [0]->flags |= MONO_INST_VOLATILE;
8544                 }
8545         }
8546
8547         /* add a check for this != NULL to inlined methods */
8548         if (is_virtual_call) {
8549                 MonoInst *arg_ins;
8550
8551                 NEW_ARGLOAD (cfg, arg_ins, 0);
8552                 MONO_ADD_INS (cfg->cbb, arg_ins);
8553                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
8554         }
8555
8556         skip_dead_blocks = !dont_verify;
8557         if (skip_dead_blocks) {
8558                 original_bb = bb = mono_basic_block_split (method, &cfg->error);
8559                 CHECK_CFG_ERROR;
8560                 g_assert (bb);
8561         }
8562
8563         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
8564         stack_start = sp = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
8565
8566         ins_flag = 0;
8567         start_new_bblock = 0;
8568         while (ip < end) {
8569                 if (cfg->method == method)
8570                         cfg->real_offset = ip - header->code;
8571                 else
8572                         cfg->real_offset = inline_offset;
8573                 cfg->ip = ip;
8574
8575                 context_used = 0;
8576
8577                 if (start_new_bblock) {
8578                         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
8579                         if (start_new_bblock == 2) {
8580                                 g_assert (ip == tblock->cil_code);
8581                         } else {
8582                                 GET_BBLOCK (cfg, tblock, ip);
8583                         }
8584                         cfg->cbb->next_bb = tblock;
8585                         cfg->cbb = tblock;
8586                         start_new_bblock = 0;
8587                         for (i = 0; i < cfg->cbb->in_scount; ++i) {
8588                                 if (cfg->verbose_level > 3)
8589                                         printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8590                                 EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8591                                 *sp++ = ins;
8592                         }
8593                         if (class_inits)
8594                                 g_slist_free (class_inits);
8595                         class_inits = NULL;
8596                 } else {
8597                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != cfg->cbb)) {
8598                                 link_bblock (cfg, cfg->cbb, tblock);
8599                                 if (sp != stack_start) {
8600                                         handle_stack_args (cfg, stack_start, sp - stack_start);
8601                                         sp = stack_start;
8602                                         CHECK_UNVERIFIABLE (cfg);
8603                                 }
8604                                 cfg->cbb->next_bb = tblock;
8605                                 cfg->cbb = tblock;
8606                                 for (i = 0; i < cfg->cbb->in_scount; ++i) {
8607                                         if (cfg->verbose_level > 3)
8608                                                 printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8609                                         EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8610                                         *sp++ = ins;
8611                                 }
8612                                 g_slist_free (class_inits);
8613                                 class_inits = NULL;
8614                         }
8615                 }
8616
8617                 if (skip_dead_blocks) {
8618                         int ip_offset = ip - header->code;
8619
8620                         if (ip_offset == bb->end)
8621                                 bb = bb->next;
8622
8623                         if (bb->dead) {
8624                                 int op_size = mono_opcode_size (ip, end);
8625                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
8626
8627                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
8628
8629                                 if (ip_offset + op_size == bb->end) {
8630                                         MONO_INST_NEW (cfg, ins, OP_NOP);
8631                                         MONO_ADD_INS (cfg->cbb, ins);
8632                                         start_new_bblock = 1;
8633                                 }
8634
8635                                 ip += op_size;
8636                                 continue;
8637                         }
8638                 }
8639                 /*
8640                  * Sequence points are points where the debugger can place a breakpoint.
8641                  * Currently, we generate these automatically at points where the IL
8642                  * stack is empty.
8643                  */
8644                 if (seq_points && ((!sym_seq_points && (sp == stack_start)) || (sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code)))) {
8645                         /*
8646                          * Make methods interruptable at the beginning, and at the targets of
8647                          * backward branches.
8648                          * Also, do this at the start of every bblock in methods with clauses too,
8649                          * to be able to handle instructions with inprecise control flow like
8650                          * throw/endfinally.
8651                          * Backward branches are handled at the end of method-to-ir ().
8652                          */
8653                         gboolean intr_loc = ip == header->code || (!cfg->cbb->last_ins && cfg->header->num_clauses);
8654                         gboolean sym_seq_point = sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code);
8655
8656                         /* Avoid sequence points on empty IL like .volatile */
8657                         // FIXME: Enable this
8658                         //if (!(cfg->cbb->last_ins && cfg->cbb->last_ins->opcode == OP_SEQ_POINT)) {
8659                         NEW_SEQ_POINT (cfg, ins, ip - header->code, intr_loc);
8660                         if ((sp != stack_start) && !sym_seq_point)
8661                                 ins->flags |= MONO_INST_NONEMPTY_STACK;
8662                         MONO_ADD_INS (cfg->cbb, ins);
8663
8664                         if (sym_seq_points)
8665                                 mono_bitset_set_fast (seq_point_set_locs, ip - header->code);
8666                 }
8667
8668                 cfg->cbb->real_offset = cfg->real_offset;
8669
8670                 if ((cfg->method == method) && cfg->coverage_info) {
8671                         guint32 cil_offset = ip - header->code;
8672                         cfg->coverage_info->data [cil_offset].cil_code = ip;
8673
8674                         /* TODO: Use an increment here */
8675 #if defined(TARGET_X86)
8676                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
8677                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
8678                         ins->inst_imm = 1;
8679                         MONO_ADD_INS (cfg->cbb, ins);
8680 #else
8681                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
8682                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
8683 #endif
8684                 }
8685
8686                 if (cfg->verbose_level > 3)
8687                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
8688
8689                 switch (*ip) {
8690                 case CEE_NOP:
8691                         if (seq_points && !sym_seq_points && sp != stack_start) {
8692                                 /*
8693                                  * The C# compiler uses these nops to notify the JIT that it should
8694                                  * insert seq points.
8695                                  */
8696                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, FALSE);
8697                                 MONO_ADD_INS (cfg->cbb, ins);
8698                         }
8699                         if (cfg->keep_cil_nops)
8700                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
8701                         else
8702                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8703                         ip++;
8704                         MONO_ADD_INS (cfg->cbb, ins);
8705                         break;
8706                 case CEE_BREAK:
8707                         if (should_insert_brekpoint (cfg->method)) {
8708                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
8709                         } else {
8710                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8711                         }
8712                         ip++;
8713                         MONO_ADD_INS (cfg->cbb, ins);
8714                         break;
8715                 case CEE_LDARG_0:
8716                 case CEE_LDARG_1:
8717                 case CEE_LDARG_2:
8718                 case CEE_LDARG_3:
8719                         CHECK_STACK_OVF (1);
8720                         n = (*ip)-CEE_LDARG_0;
8721                         CHECK_ARG (n);
8722                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8723                         ip++;
8724                         *sp++ = ins;
8725                         break;
8726                 case CEE_LDLOC_0:
8727                 case CEE_LDLOC_1:
8728                 case CEE_LDLOC_2:
8729                 case CEE_LDLOC_3:
8730                         CHECK_STACK_OVF (1);
8731                         n = (*ip)-CEE_LDLOC_0;
8732                         CHECK_LOCAL (n);
8733                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8734                         ip++;
8735                         *sp++ = ins;
8736                         break;
8737                 case CEE_STLOC_0:
8738                 case CEE_STLOC_1:
8739                 case CEE_STLOC_2:
8740                 case CEE_STLOC_3: {
8741                         CHECK_STACK (1);
8742                         n = (*ip)-CEE_STLOC_0;
8743                         CHECK_LOCAL (n);
8744                         --sp;
8745                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
8746                                 UNVERIFIED;
8747                         emit_stloc_ir (cfg, sp, header, n);
8748                         ++ip;
8749                         inline_costs += 1;
8750                         break;
8751                         }
8752                 case CEE_LDARG_S:
8753                         CHECK_OPSIZE (2);
8754                         CHECK_STACK_OVF (1);
8755                         n = ip [1];
8756                         CHECK_ARG (n);
8757                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8758                         *sp++ = ins;
8759                         ip += 2;
8760                         break;
8761                 case CEE_LDARGA_S:
8762                         CHECK_OPSIZE (2);
8763                         CHECK_STACK_OVF (1);
8764                         n = ip [1];
8765                         CHECK_ARG (n);
8766                         NEW_ARGLOADA (cfg, ins, n);
8767                         MONO_ADD_INS (cfg->cbb, ins);
8768                         *sp++ = ins;
8769                         ip += 2;
8770                         break;
8771                 case CEE_STARG_S:
8772                         CHECK_OPSIZE (2);
8773                         CHECK_STACK (1);
8774                         --sp;
8775                         n = ip [1];
8776                         CHECK_ARG (n);
8777                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
8778                                 UNVERIFIED;
8779                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
8780                         ip += 2;
8781                         break;
8782                 case CEE_LDLOC_S:
8783                         CHECK_OPSIZE (2);
8784                         CHECK_STACK_OVF (1);
8785                         n = ip [1];
8786                         CHECK_LOCAL (n);
8787                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8788                         *sp++ = ins;
8789                         ip += 2;
8790                         break;
8791                 case CEE_LDLOCA_S: {
8792                         unsigned char *tmp_ip;
8793                         CHECK_OPSIZE (2);
8794                         CHECK_STACK_OVF (1);
8795                         CHECK_LOCAL (ip [1]);
8796
8797                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
8798                                 ip = tmp_ip;
8799                                 inline_costs += 1;
8800                                 break;
8801                         }
8802
8803                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
8804                         *sp++ = ins;
8805                         ip += 2;
8806                         break;
8807                 }
8808                 case CEE_STLOC_S:
8809                         CHECK_OPSIZE (2);
8810                         CHECK_STACK (1);
8811                         --sp;
8812                         CHECK_LOCAL (ip [1]);
8813                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
8814                                 UNVERIFIED;
8815                         emit_stloc_ir (cfg, sp, header, ip [1]);
8816                         ip += 2;
8817                         inline_costs += 1;
8818                         break;
8819                 case CEE_LDNULL:
8820                         CHECK_STACK_OVF (1);
8821                         EMIT_NEW_PCONST (cfg, ins, NULL);
8822                         ins->type = STACK_OBJ;
8823                         ++ip;
8824                         *sp++ = ins;
8825                         break;
8826                 case CEE_LDC_I4_M1:
8827                         CHECK_STACK_OVF (1);
8828                         EMIT_NEW_ICONST (cfg, ins, -1);
8829                         ++ip;
8830                         *sp++ = ins;
8831                         break;
8832                 case CEE_LDC_I4_0:
8833                 case CEE_LDC_I4_1:
8834                 case CEE_LDC_I4_2:
8835                 case CEE_LDC_I4_3:
8836                 case CEE_LDC_I4_4:
8837                 case CEE_LDC_I4_5:
8838                 case CEE_LDC_I4_6:
8839                 case CEE_LDC_I4_7:
8840                 case CEE_LDC_I4_8:
8841                         CHECK_STACK_OVF (1);
8842                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
8843                         ++ip;
8844                         *sp++ = ins;
8845                         break;
8846                 case CEE_LDC_I4_S:
8847                         CHECK_OPSIZE (2);
8848                         CHECK_STACK_OVF (1);
8849                         ++ip;
8850                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
8851                         ++ip;
8852                         *sp++ = ins;
8853                         break;
8854                 case CEE_LDC_I4:
8855                         CHECK_OPSIZE (5);
8856                         CHECK_STACK_OVF (1);
8857                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
8858                         ip += 5;
8859                         *sp++ = ins;
8860                         break;
8861                 case CEE_LDC_I8:
8862                         CHECK_OPSIZE (9);
8863                         CHECK_STACK_OVF (1);
8864                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
8865                         ins->type = STACK_I8;
8866                         ins->dreg = alloc_dreg (cfg, STACK_I8);
8867                         ++ip;
8868                         ins->inst_l = (gint64)read64 (ip);
8869                         MONO_ADD_INS (cfg->cbb, ins);
8870                         ip += 8;
8871                         *sp++ = ins;
8872                         break;
8873                 case CEE_LDC_R4: {
8874                         float *f;
8875                         gboolean use_aotconst = FALSE;
8876
8877 #ifdef TARGET_POWERPC
8878                         /* FIXME: Clean this up */
8879                         if (cfg->compile_aot)
8880                                 use_aotconst = TRUE;
8881 #endif
8882
8883                         /* FIXME: we should really allocate this only late in the compilation process */
8884                         f = (float *)mono_domain_alloc (cfg->domain, sizeof (float));
8885                         CHECK_OPSIZE (5);
8886                         CHECK_STACK_OVF (1);
8887
8888                         if (use_aotconst) {
8889                                 MonoInst *cons;
8890                                 int dreg;
8891
8892                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
8893
8894                                 dreg = alloc_freg (cfg);
8895                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
8896                                 ins->type = cfg->r4_stack_type;
8897                         } else {
8898                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
8899                                 ins->type = cfg->r4_stack_type;
8900                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8901                                 ins->inst_p0 = f;
8902                                 MONO_ADD_INS (cfg->cbb, ins);
8903                         }
8904                         ++ip;
8905                         readr4 (ip, f);
8906                         ip += 4;
8907                         *sp++ = ins;                    
8908                         break;
8909                 }
8910                 case CEE_LDC_R8: {
8911                         double *d;
8912                         gboolean use_aotconst = FALSE;
8913
8914 #ifdef TARGET_POWERPC
8915                         /* FIXME: Clean this up */
8916                         if (cfg->compile_aot)
8917                                 use_aotconst = TRUE;
8918 #endif
8919
8920                         /* FIXME: we should really allocate this only late in the compilation process */
8921                         d = (double *)mono_domain_alloc (cfg->domain, sizeof (double));
8922                         CHECK_OPSIZE (9);
8923                         CHECK_STACK_OVF (1);
8924
8925                         if (use_aotconst) {
8926                                 MonoInst *cons;
8927                                 int dreg;
8928
8929                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
8930
8931                                 dreg = alloc_freg (cfg);
8932                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
8933                                 ins->type = STACK_R8;
8934                         } else {
8935                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
8936                                 ins->type = STACK_R8;
8937                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8938                                 ins->inst_p0 = d;
8939                                 MONO_ADD_INS (cfg->cbb, ins);
8940                         }
8941                         ++ip;
8942                         readr8 (ip, d);
8943                         ip += 8;
8944                         *sp++ = ins;
8945                         break;
8946                 }
8947                 case CEE_DUP: {
8948                         MonoInst *temp, *store;
8949                         CHECK_STACK (1);
8950                         CHECK_STACK_OVF (1);
8951                         sp--;
8952                         ins = *sp;
8953
8954                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
8955                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
8956
8957                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8958                         *sp++ = ins;
8959
8960                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8961                         *sp++ = ins;
8962
8963                         ++ip;
8964                         inline_costs += 2;
8965                         break;
8966                 }
8967                 case CEE_POP:
8968                         CHECK_STACK (1);
8969                         ip++;
8970                         --sp;
8971
8972 #ifdef TARGET_X86
8973                         if (sp [0]->type == STACK_R8)
8974                                 /* we need to pop the value from the x86 FP stack */
8975                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
8976 #endif
8977                         break;
8978                 case CEE_JMP: {
8979                         MonoCallInst *call;
8980                         MonoMethodSignature *fsig;
8981                         int i, n;
8982
8983                         INLINE_FAILURE ("jmp");
8984                         GSHAREDVT_FAILURE (*ip);
8985
8986                         CHECK_OPSIZE (5);
8987                         if (stack_start != sp)
8988                                 UNVERIFIED;
8989                         token = read32 (ip + 1);
8990                         /* FIXME: check the signature matches */
8991                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8992                         CHECK_CFG_ERROR;
8993  
8994                         if (cfg->gshared && mono_method_check_context_used (cmethod))
8995                                 GENERIC_SHARING_FAILURE (CEE_JMP);
8996
8997                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
8998
8999                         fsig = mono_method_signature (cmethod);
9000                         n = fsig->param_count + fsig->hasthis;
9001                         if (cfg->llvm_only) {
9002                                 MonoInst **args;
9003
9004                                 args = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
9005                                 for (i = 0; i < n; ++i)
9006                                         EMIT_NEW_ARGLOAD (cfg, args [i], i);
9007                                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, TRUE, args, NULL, NULL, NULL);
9008                                 /*
9009                                  * The code in mono-basic-block.c treats the rest of the code as dead, but we
9010                                  * have to emit a normal return since llvm expects it.
9011                                  */
9012                                 if (cfg->ret)
9013                                         emit_setret (cfg, ins);
9014                                 MONO_INST_NEW (cfg, ins, OP_BR);
9015                                 ins->inst_target_bb = end_bblock;
9016                                 MONO_ADD_INS (cfg->cbb, ins);
9017                                 link_bblock (cfg, cfg->cbb, end_bblock);
9018                                 ip += 5;
9019                                 break;
9020                         } else if (cfg->backend->have_op_tail_call) {
9021                                 /* Handle tail calls similarly to calls */
9022                                 DISABLE_AOT (cfg);
9023
9024                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
9025                                 call->method = cmethod;
9026                                 call->tail_call = TRUE;
9027                                 call->signature = mono_method_signature (cmethod);
9028                                 call->args = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
9029                                 call->inst.inst_p0 = cmethod;
9030                                 for (i = 0; i < n; ++i)
9031                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
9032
9033                                 mono_arch_emit_call (cfg, call);
9034                                 cfg->param_area = MAX(cfg->param_area, call->stack_usage);
9035                                 MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
9036                         } else {
9037                                 for (i = 0; i < num_args; ++i)
9038                                         /* Prevent arguments from being optimized away */
9039                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
9040
9041                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9042                                 ins = (MonoInst*)call;
9043                                 ins->inst_p0 = cmethod;
9044                                 MONO_ADD_INS (cfg->cbb, ins);
9045                         }
9046
9047                         ip += 5;
9048                         start_new_bblock = 1;
9049                         break;
9050                 }
9051                 case CEE_CALLI: {
9052                         MonoInst *addr;
9053                         MonoMethodSignature *fsig;
9054
9055                         CHECK_OPSIZE (5);
9056                         token = read32 (ip + 1);
9057
9058                         ins = NULL;
9059
9060                         //GSHAREDVT_FAILURE (*ip);
9061                         cmethod = NULL;
9062                         CHECK_STACK (1);
9063                         --sp;
9064                         addr = *sp;
9065                         fsig = mini_get_signature (method, token, generic_context);
9066
9067                         if (method->dynamic && fsig->pinvoke) {
9068                                 MonoInst *args [3];
9069
9070                                 /*
9071                                  * This is a call through a function pointer using a pinvoke
9072                                  * signature. Have to create a wrapper and call that instead.
9073                                  * FIXME: This is very slow, need to create a wrapper at JIT time
9074                                  * instead based on the signature.
9075                                  */
9076                                 EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
9077                                 EMIT_NEW_PCONST (cfg, args [1], fsig);
9078                                 args [2] = addr;
9079                                 addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
9080                         }
9081
9082                         n = fsig->param_count + fsig->hasthis;
9083
9084                         CHECK_STACK (n);
9085
9086                         //g_assert (!virtual_ || fsig->hasthis);
9087
9088                         sp -= n;
9089
9090                         inline_costs += 10 * num_calls++;
9091
9092                         /*
9093                          * Making generic calls out of gsharedvt methods.
9094                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9095                          * patching gshared method addresses into a gsharedvt method.
9096                          */
9097                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
9098                                 /*
9099                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
9100                                  */
9101                                 MonoInst *callee = addr;
9102
9103                                 if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
9104                                         /* Not tested */
9105                                         GSHAREDVT_FAILURE (*ip);
9106
9107                                 if (cfg->llvm_only)
9108                                         // FIXME:
9109                                         GSHAREDVT_FAILURE (*ip);
9110
9111                                 addr = emit_get_rgctx_sig (cfg, context_used,
9112                                                                                           fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
9113                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
9114                                 goto calli_end;
9115                         }
9116
9117                         /* Prevent inlining of methods with indirect calls */
9118                         INLINE_FAILURE ("indirect call");
9119
9120                         if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
9121                                 MonoJumpInfoType info_type;
9122                                 gpointer info_data;
9123
9124                                 /*
9125                                  * Instead of emitting an indirect call, emit a direct call
9126                                  * with the contents of the aotconst as the patch info.
9127                                  */
9128                                 if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
9129                                         info_type = (MonoJumpInfoType)addr->inst_c1;
9130                                         info_data = addr->inst_p0;
9131                                 } else {
9132                                         info_type = (MonoJumpInfoType)addr->inst_right->inst_c1;
9133                                         info_data = addr->inst_right->inst_left;
9134                                 }
9135
9136                                 if (info_type == MONO_PATCH_INFO_ICALL_ADDR || info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
9137                                         ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
9138                                         NULLIFY_INS (addr);
9139                                         goto calli_end;
9140                                 }
9141                         }
9142                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9143
9144                         calli_end:
9145
9146                         /* End of call, INS should contain the result of the call, if any */
9147
9148                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9149                                 g_assert (ins);
9150                                 *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
9151                         }
9152
9153                         CHECK_CFG_EXCEPTION;
9154
9155                         ip += 5;
9156                         ins_flag = 0;
9157                         constrained_class = NULL;
9158                         break;
9159                 }
9160                 case CEE_CALL:
9161                 case CEE_CALLVIRT: {
9162                         MonoInst *addr = NULL;
9163                         MonoMethodSignature *fsig = NULL;
9164                         int array_rank = 0;
9165                         int virtual_ = *ip == CEE_CALLVIRT;
9166                         gboolean pass_imt_from_rgctx = FALSE;
9167                         MonoInst *imt_arg = NULL;
9168                         MonoInst *keep_this_alive = NULL;
9169                         gboolean pass_vtable = FALSE;
9170                         gboolean pass_mrgctx = FALSE;
9171                         MonoInst *vtable_arg = NULL;
9172                         gboolean check_this = FALSE;
9173                         gboolean supported_tail_call = FALSE;
9174                         gboolean tail_call = FALSE;
9175                         gboolean need_seq_point = FALSE;
9176                         guint32 call_opcode = *ip;
9177                         gboolean emit_widen = TRUE;
9178                         gboolean push_res = TRUE;
9179                         gboolean skip_ret = FALSE;
9180                         gboolean delegate_invoke = FALSE;
9181                         gboolean direct_icall = FALSE;
9182                         gboolean constrained_partial_call = FALSE;
9183                         MonoMethod *cil_method;
9184
9185                         CHECK_OPSIZE (5);
9186                         token = read32 (ip + 1);
9187
9188                         ins = NULL;
9189
9190                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
9191                         CHECK_CFG_ERROR;
9192
9193                         cil_method = cmethod;
9194                                 
9195                         if (constrained_class) {
9196                                 if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
9197                                         if (!mini_is_gsharedvt_klass (constrained_class)) {
9198                                                 g_assert (!cmethod->klass->valuetype);
9199                                                 if (!mini_type_is_reference (&constrained_class->byval_arg))
9200                                                         constrained_partial_call = TRUE;
9201                                         }
9202                                 }
9203
9204                                 if (method->wrapper_type != MONO_WRAPPER_NONE) {
9205                                         if (cfg->verbose_level > 2)
9206                                                 printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_class));
9207                                         if (!((constrained_class->byval_arg.type == MONO_TYPE_VAR ||
9208                                                    constrained_class->byval_arg.type == MONO_TYPE_MVAR) &&
9209                                                   cfg->gshared)) {
9210                                                 cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_class, generic_context, &cfg->error);
9211                                                 CHECK_CFG_ERROR;
9212                                         }
9213                                 } else {
9214                                         if (cfg->verbose_level > 2)
9215                                                 printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_class));
9216
9217                                         if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
9218                                                 /* 
9219                                                  * This is needed since get_method_constrained can't find 
9220                                                  * the method in klass representing a type var.
9221                                                  * The type var is guaranteed to be a reference type in this
9222                                                  * case.
9223                                                  */
9224                                                 if (!mini_is_gsharedvt_klass (constrained_class))
9225                                                         g_assert (!cmethod->klass->valuetype);
9226                                         } else {
9227                                                 cmethod = mono_get_method_constrained_checked (image, token, constrained_class, generic_context, &cil_method, &cfg->error);
9228                                                 CHECK_CFG_ERROR;
9229                                         }
9230                                 }
9231                         }
9232                                         
9233                         if (!cmethod || mono_loader_get_last_error ()) {
9234                                 if (mono_loader_get_last_error ()) {
9235                                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
9236                                         mono_error_set_from_loader_error (&cfg->error);
9237                                         CHECK_CFG_ERROR;
9238                                 } else {
9239                                         LOAD_ERROR;
9240                                 }
9241                         }
9242                         if (!dont_verify && !cfg->skip_visibility) {
9243                                 MonoMethod *target_method = cil_method;
9244                                 if (method->is_inflated) {
9245                                         target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context), &cfg->error);
9246                                         CHECK_CFG_ERROR;
9247                                 }
9248                                 if (!mono_method_can_access_method (method_definition, target_method) &&
9249                                         !mono_method_can_access_method (method, cil_method))
9250                                         METHOD_ACCESS_FAILURE (method, cil_method);
9251                         }
9252
9253                         if (mono_security_core_clr_enabled ())
9254                                 ensure_method_is_allowed_to_call_method (cfg, method, cil_method);
9255
9256                         if (!virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
9257                                 /* MS.NET seems to silently convert this to a callvirt */
9258                                 virtual_ = 1;
9259
9260                         {
9261                                 /*
9262                                  * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
9263                                  * converts to a callvirt.
9264                                  *
9265                                  * tests/bug-515884.il is an example of this behavior
9266                                  */
9267                                 const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
9268                                 const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
9269                                 if (!virtual_ && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
9270                                         virtual_ = 1;
9271                         }
9272
9273                         if (!cmethod->klass->inited)
9274                                 if (!mono_class_init (cmethod->klass))
9275                                         TYPE_LOAD_ERROR (cmethod->klass);
9276
9277                         fsig = mono_method_signature (cmethod);
9278                         if (!fsig)
9279                                 LOAD_ERROR;
9280                         if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
9281                                 mini_class_is_system_array (cmethod->klass)) {
9282                                 array_rank = cmethod->klass->rank;
9283                         } else if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && icall_is_direct_callable (cfg, cmethod)) {
9284                                 direct_icall = TRUE;
9285                         } else if (fsig->pinvoke) {
9286                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
9287                                 fsig = mono_method_signature (wrapper);
9288                         } else if (constrained_class) {
9289                         } else {
9290                                 fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
9291                                 CHECK_CFG_ERROR;
9292                         }
9293
9294                         if (cfg->llvm_only && !cfg->method->wrapper_type)
9295                                 cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, fsig);
9296
9297                         /* See code below */
9298                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
9299                                 MonoBasicBlock *tbb;
9300
9301                                 GET_BBLOCK (cfg, tbb, ip + 5);
9302                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
9303                                         /*
9304                                          * We want to extend the try block to cover the call, but we can't do it if the
9305                                          * call is made directly since its followed by an exception check.
9306                                          */
9307                                         direct_icall = FALSE;
9308                                 }
9309                         }
9310
9311                         mono_save_token_info (cfg, image, token, cil_method);
9312
9313                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip + 5 - header->code)))
9314                                 need_seq_point = TRUE;
9315
9316                         /* Don't support calls made using type arguments for now */
9317                         /*
9318                           if (cfg->gsharedvt) {
9319                           if (mini_is_gsharedvt_signature (fsig))
9320                           GSHAREDVT_FAILURE (*ip);
9321                           }
9322                         */
9323
9324                         if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
9325                                 g_assert_not_reached ();
9326
9327                         n = fsig->param_count + fsig->hasthis;
9328
9329                         if (!cfg->gshared && cmethod->klass->generic_container)
9330                                 UNVERIFIED;
9331
9332                         if (!cfg->gshared)
9333                                 g_assert (!mono_method_check_context_used (cmethod));
9334
9335                         CHECK_STACK (n);
9336
9337                         //g_assert (!virtual_ || fsig->hasthis);
9338
9339                         sp -= n;
9340
9341                         /*
9342                          * We have the `constrained.' prefix opcode.
9343                          */
9344                         if (constrained_class) {
9345                                 if (mini_is_gsharedvt_klass (constrained_class)) {
9346                                         if ((cmethod->klass != mono_defaults.object_class) && constrained_class->valuetype && cmethod->klass->valuetype) {
9347                                                 /* The 'Own method' case below */
9348                                         } else if (cmethod->klass->image != mono_defaults.corlib && !(cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !cmethod->klass->valuetype) {
9349                                                 /* 'The type parameter is instantiated as a reference type' case below. */
9350                                         } else {
9351                                                 ins = handle_constrained_gsharedvt_call (cfg, cmethod, fsig, sp, constrained_class, &emit_widen);
9352                                                 CHECK_CFG_EXCEPTION;
9353                                                 g_assert (ins);
9354                                                 goto call_end;
9355                                         }
9356                                 }
9357
9358                                 if (constrained_partial_call) {
9359                                         gboolean need_box = TRUE;
9360
9361                                         /*
9362                                          * The receiver is a valuetype, but the exact type is not known at compile time. This means the
9363                                          * called method is not known at compile time either. The called method could end up being
9364                                          * one of the methods on the parent classes (object/valuetype/enum), in which case we need
9365                                          * to box the receiver.
9366                                          * A simple solution would be to box always and make a normal virtual call, but that would
9367                                          * be bad performance wise.
9368                                          */
9369                                         if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE && cmethod->klass->generic_class) {
9370                                                 /*
9371                                                  * The parent classes implement no generic interfaces, so the called method will be a vtype method, so no boxing neccessary.
9372                                                  */
9373                                                 need_box = FALSE;
9374                                         }
9375
9376                                         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)) {
9377                                                 /* The called method is not virtual, i.e. Object:GetType (), the receiver is a vtype, has to box */
9378                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9379                                                 ins->klass = constrained_class;
9380                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9381                                                 CHECK_CFG_EXCEPTION;
9382                                         } else if (need_box) {
9383                                                 MonoInst *box_type;
9384                                                 MonoBasicBlock *is_ref_bb, *end_bb;
9385                                                 MonoInst *nonbox_call;
9386
9387                                                 /*
9388                                                  * Determine at runtime whenever the called method is defined on object/valuetype/enum, and emit a boxing call
9389                                                  * if needed.
9390                                                  * FIXME: It is possible to inline the called method in a lot of cases, i.e. for T_INT,
9391                                                  * the no-box case goes to a method in Int32, while the box case goes to a method in Enum.
9392                                                  */
9393                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
9394
9395                                                 NEW_BBLOCK (cfg, is_ref_bb);
9396                                                 NEW_BBLOCK (cfg, end_bb);
9397
9398                                                 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);
9399                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, box_type->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
9400                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
9401
9402                                                 /* Non-ref case */
9403                                                 nonbox_call = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9404
9405                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9406
9407                                                 /* Ref case */
9408                                                 MONO_START_BB (cfg, is_ref_bb);
9409                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9410                                                 ins->klass = constrained_class;
9411                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9412                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9413
9414                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9415
9416                                                 MONO_START_BB (cfg, end_bb);
9417                                                 cfg->cbb = end_bb;
9418
9419                                                 nonbox_call->dreg = ins->dreg;
9420                                                 goto call_end;
9421                                         } else {
9422                                                 g_assert (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
9423                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
9424                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9425                                                 goto call_end;
9426                                         }
9427                                 } else if (constrained_class->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
9428                                         /*
9429                                          * The type parameter is instantiated as a valuetype,
9430                                          * but that type doesn't override the method we're
9431                                          * calling, so we need to box `this'.
9432                                          */
9433                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9434                                         ins->klass = constrained_class;
9435                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9436                                         CHECK_CFG_EXCEPTION;
9437                                 } else if (!constrained_class->valuetype) {
9438                                         int dreg = alloc_ireg_ref (cfg);
9439
9440                                         /*
9441                                          * The type parameter is instantiated as a reference
9442                                          * type.  We have a managed pointer on the stack, so
9443                                          * we need to dereference it here.
9444                                          */
9445                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
9446                                         ins->type = STACK_OBJ;
9447                                         sp [0] = ins;
9448                                 } else {
9449                                         if (cmethod->klass->valuetype) {
9450                                                 /* Own method */
9451                                         } else {
9452                                                 /* Interface method */
9453                                                 int ioffset, slot;
9454
9455                                                 mono_class_setup_vtable (constrained_class);
9456                                                 CHECK_TYPELOAD (constrained_class);
9457                                                 ioffset = mono_class_interface_offset (constrained_class, cmethod->klass);
9458                                                 if (ioffset == -1)
9459                                                         TYPE_LOAD_ERROR (constrained_class);
9460                                                 slot = mono_method_get_vtable_slot (cmethod);
9461                                                 if (slot == -1)
9462                                                         TYPE_LOAD_ERROR (cmethod->klass);
9463                                                 cmethod = constrained_class->vtable [ioffset + slot];
9464
9465                                                 if (cmethod->klass == mono_defaults.enum_class) {
9466                                                         /* Enum implements some interfaces, so treat this as the first case */
9467                                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9468                                                         ins->klass = constrained_class;
9469                                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9470                                                         CHECK_CFG_EXCEPTION;
9471                                                 }
9472                                         }
9473                                         virtual_ = 0;
9474                                 }
9475                                 constrained_class = NULL;
9476                         }
9477
9478                         if (check_call_signature (cfg, fsig, sp))
9479                                 UNVERIFIED;
9480
9481                         if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
9482                                 delegate_invoke = TRUE;
9483
9484                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
9485                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9486                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9487                                         emit_widen = FALSE;
9488                                 }
9489
9490                                 goto call_end;
9491                         }
9492
9493                         /* 
9494                          * If the callee is a shared method, then its static cctor
9495                          * might not get called after the call was patched.
9496                          */
9497                         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)) {
9498                                 emit_class_init (cfg, cmethod->klass);
9499                                 CHECK_TYPELOAD (cmethod->klass);
9500                         }
9501
9502                         check_method_sharing (cfg, cmethod, &pass_vtable, &pass_mrgctx);
9503
9504                         if (cfg->gshared) {
9505                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
9506
9507                                 context_used = mini_method_check_context_used (cfg, cmethod);
9508
9509                                 if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9510                                         /* Generic method interface
9511                                            calls are resolved via a
9512                                            helper function and don't
9513                                            need an imt. */
9514                                         if (!cmethod_context || !cmethod_context->method_inst)
9515                                                 pass_imt_from_rgctx = TRUE;
9516                                 }
9517
9518                                 /*
9519                                  * If a shared method calls another
9520                                  * shared method then the caller must
9521                                  * have a generic sharing context
9522                                  * because the magic trampoline
9523                                  * requires it.  FIXME: We shouldn't
9524                                  * have to force the vtable/mrgctx
9525                                  * variable here.  Instead there
9526                                  * should be a flag in the cfg to
9527                                  * request a generic sharing context.
9528                                  */
9529                                 if (context_used &&
9530                                                 ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
9531                                         mono_get_vtable_var (cfg);
9532                         }
9533
9534                         if (pass_vtable) {
9535                                 if (context_used) {
9536                                         vtable_arg = emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
9537                                 } else {
9538                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
9539
9540                                         CHECK_TYPELOAD (cmethod->klass);
9541                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
9542                                 }
9543                         }
9544
9545                         if (pass_mrgctx) {
9546                                 g_assert (!vtable_arg);
9547
9548                                 if (!cfg->compile_aot) {
9549                                         /* 
9550                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
9551                                          * for type load errors before.
9552                                          */
9553                                         mono_class_setup_vtable (cmethod->klass);
9554                                         CHECK_TYPELOAD (cmethod->klass);
9555                                 }
9556
9557                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
9558
9559                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
9560                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
9561                                          MONO_METHOD_IS_FINAL (cmethod)) &&
9562                                         !mono_class_is_marshalbyref (cmethod->klass)) {
9563                                         if (virtual_)
9564                                                 check_this = TRUE;
9565                                         virtual_ = 0;
9566                                 }
9567                         }
9568
9569                         if (pass_imt_from_rgctx) {
9570                                 g_assert (!pass_vtable);
9571
9572                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9573                                         cmethod, MONO_RGCTX_INFO_METHOD);
9574                         }
9575
9576                         if (check_this)
9577                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9578
9579                         /* Calling virtual generic methods */
9580                         if (virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) &&
9581                             !(MONO_METHOD_IS_FINAL (cmethod) && 
9582                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
9583                             fsig->generic_param_count && 
9584                                 !(cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) &&
9585                                 !cfg->llvm_only) {
9586                                 MonoInst *this_temp, *this_arg_temp, *store;
9587                                 MonoInst *iargs [4];
9588
9589                                 g_assert (fsig->is_inflated);
9590
9591                                 /* Prevent inlining of methods that contain indirect calls */
9592                                 INLINE_FAILURE ("virtual generic call");
9593
9594                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
9595                                         GSHAREDVT_FAILURE (*ip);
9596
9597                                 if (cfg->backend->have_generalized_imt_thunk && cfg->backend->gshared_supported && cmethod->wrapper_type == MONO_WRAPPER_NONE) {
9598                                         g_assert (!imt_arg);
9599                                         if (!context_used)
9600                                                 g_assert (cmethod->is_inflated);
9601                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
9602                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
9603                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, sp [0], imt_arg, NULL);
9604                                 } else {
9605                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
9606                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
9607                                         MONO_ADD_INS (cfg->cbb, store);
9608
9609                                         /* FIXME: This should be a managed pointer */
9610                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
9611
9612                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
9613                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
9614                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
9615                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
9616                                         addr = mono_emit_jit_icall (cfg,
9617                                                                                                 mono_helper_compile_generic_method, iargs);
9618
9619                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
9620
9621                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9622                                 }
9623
9624                                 goto call_end;
9625                         }
9626
9627                         /*
9628                          * Implement a workaround for the inherent races involved in locking:
9629                          * Monitor.Enter ()
9630                          * try {
9631                          * } finally {
9632                          *    Monitor.Exit ()
9633                          * }
9634                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
9635                          * try block, the Exit () won't be executed, see:
9636                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
9637                          * To work around this, we extend such try blocks to include the last x bytes
9638                          * of the Monitor.Enter () call.
9639                          */
9640                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
9641                                 MonoBasicBlock *tbb;
9642
9643                                 GET_BBLOCK (cfg, tbb, ip + 5);
9644                                 /* 
9645                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
9646                                  * from Monitor.Enter like ArgumentNullException.
9647                                  */
9648                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
9649                                         /* Mark this bblock as needing to be extended */
9650                                         tbb->extend_try_block = TRUE;
9651                                 }
9652                         }
9653
9654                         /* Conversion to a JIT intrinsic */
9655                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
9656                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9657                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9658                                         emit_widen = FALSE;
9659                                 }
9660                                 goto call_end;
9661                         }
9662
9663                         /* Inlining */
9664                         if ((cfg->opt & MONO_OPT_INLINE) &&
9665                                 (!virtual_ || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
9666                             mono_method_check_inlining (cfg, cmethod)) {
9667                                 int costs;
9668                                 gboolean always = FALSE;
9669
9670                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
9671                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
9672                                         /* Prevent inlining of methods that call wrappers */
9673                                         INLINE_FAILURE ("wrapper call");
9674                                         cmethod = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
9675                                         always = TRUE;
9676                                 }
9677
9678                                 costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, always);
9679                                 if (costs) {
9680                                         cfg->real_offset += 5;
9681
9682                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9683                                                 /* *sp is already set by inline_method */
9684                                                 sp++;
9685                                                 push_res = FALSE;
9686                                         }
9687
9688                                         inline_costs += costs;
9689
9690                                         goto call_end;
9691                                 }
9692                         }
9693
9694                         /* Tail recursion elimination */
9695                         if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
9696                                 gboolean has_vtargs = FALSE;
9697                                 int i;
9698
9699                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9700                                 INLINE_FAILURE ("tail call");
9701
9702                                 /* keep it simple */
9703                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
9704                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
9705                                                 has_vtargs = TRUE;
9706                                 }
9707
9708                                 if (!has_vtargs) {
9709                                         for (i = 0; i < n; ++i)
9710                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9711                                         MONO_INST_NEW (cfg, ins, OP_BR);
9712                                         MONO_ADD_INS (cfg->cbb, ins);
9713                                         tblock = start_bblock->out_bb [0];
9714                                         link_bblock (cfg, cfg->cbb, tblock);
9715                                         ins->inst_target_bb = tblock;
9716                                         start_new_bblock = 1;
9717
9718                                         /* skip the CEE_RET, too */
9719                                         if (ip_in_bb (cfg, cfg->cbb, ip + 5))
9720                                                 skip_ret = TRUE;
9721                                         push_res = FALSE;
9722                                         goto call_end;
9723                                 }
9724                         }
9725
9726                         inline_costs += 10 * num_calls++;
9727
9728                         /*
9729                          * Making generic calls out of gsharedvt methods.
9730                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9731                          * patching gshared method addresses into a gsharedvt method.
9732                          */
9733                         if (cfg->gsharedvt && (mini_is_gsharedvt_signature (fsig) || cmethod->is_inflated || cmethod->klass->generic_class) &&
9734                                 !(cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY) &&
9735                                 (!(cfg->llvm_only && virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)))) {
9736                                 MonoRgctxInfoType info_type;
9737
9738                                 if (virtual_) {
9739                                         //if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
9740                                                 //GSHAREDVT_FAILURE (*ip);
9741                                         // disable for possible remoting calls
9742                                         if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
9743                                                 GSHAREDVT_FAILURE (*ip);
9744                                         if (fsig->generic_param_count) {
9745                                                 /* virtual generic call */
9746                                                 g_assert (!imt_arg);
9747                                                 /* Same as the virtual generic case above */
9748                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9749                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9750                                                 /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
9751                                                 vtable_arg = NULL;
9752                                         } else if ((cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !imt_arg) {
9753                                                 /* This can happen when we call a fully instantiated iface method */
9754                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9755                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9756                                                 vtable_arg = NULL;
9757                                         }
9758                                 }
9759
9760                                 if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
9761                                         keep_this_alive = sp [0];
9762
9763                                 if (virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
9764                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
9765                                 else
9766                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
9767                                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
9768
9769                                 if (cfg->llvm_only) {
9770                                         // FIXME: Avoid initializing vtable_arg
9771                                         ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
9772                                 } else {
9773                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9774                                 }
9775                                 goto call_end;
9776                         }
9777
9778                         /* Generic sharing */
9779
9780                         /*
9781                          * Use this if the callee is gsharedvt sharable too, since
9782                          * at runtime we might find an instantiation so the call cannot
9783                          * be patched (the 'no_patch' code path in mini-trampolines.c).
9784                          */
9785                         if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
9786                                 (!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
9787                                  !mono_class_generic_sharing_enabled (cmethod->klass)) &&
9788                                 (!virtual_ || MONO_METHOD_IS_FINAL (cmethod) ||
9789                                  !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
9790                                 INLINE_FAILURE ("gshared");
9791
9792                                 g_assert (cfg->gshared && cmethod);
9793                                 g_assert (!addr);
9794
9795                                 /*
9796                                  * We are compiling a call to a
9797                                  * generic method from shared code,
9798                                  * which means that we have to look up
9799                                  * the method in the rgctx and do an
9800                                  * indirect call.
9801                                  */
9802                                 if (fsig->hasthis)
9803                                         MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9804
9805                                 if (cfg->llvm_only) {
9806                                         if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig))
9807                                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER);
9808                                         else
9809                                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9810                                         // FIXME: Avoid initializing imt_arg/vtable_arg
9811                                         ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
9812                                 } else {
9813                                         addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9814                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9815                                 }
9816                                 goto call_end;
9817                         }
9818
9819                         /* Direct calls to icalls */
9820                         if (direct_icall) {
9821                                 MonoMethod *wrapper;
9822                                 int costs;
9823
9824                                 /* Inline the wrapper */
9825                                 wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
9826
9827                                 costs = inline_method (cfg, wrapper, fsig, sp, ip, cfg->real_offset, TRUE);
9828                                 g_assert (costs > 0);
9829                                 cfg->real_offset += 5;
9830
9831                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9832                                         /* *sp is already set by inline_method */
9833                                         sp++;
9834                                         push_res = FALSE;
9835                                 }
9836
9837                                 inline_costs += costs;
9838
9839                                 goto call_end;
9840                         }
9841                                         
9842                         /* Array methods */
9843                         if (array_rank) {
9844                                 MonoInst *addr;
9845
9846                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
9847                                         MonoInst *val = sp [fsig->param_count];
9848
9849                                         if (val->type == STACK_OBJ) {
9850                                                 MonoInst *iargs [2];
9851
9852                                                 iargs [0] = sp [0];
9853                                                 iargs [1] = val;
9854                                                 
9855                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
9856                                         }
9857                                         
9858                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
9859                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
9860                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !(val->opcode == OP_PCONST && val->inst_c0 == 0))
9861                                                 emit_write_barrier (cfg, addr, val);
9862                                         if (cfg->gen_write_barriers && mini_is_gsharedvt_klass (cmethod->klass))
9863                                                 GSHAREDVT_FAILURE (*ip);
9864                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
9865                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9866
9867                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
9868                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
9869                                         if (!cmethod->klass->element_class->valuetype && !readonly)
9870                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
9871                                         CHECK_TYPELOAD (cmethod->klass);
9872                                         
9873                                         readonly = FALSE;
9874                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9875                                         ins = addr;
9876                                 } else {
9877                                         g_assert_not_reached ();
9878                                 }
9879
9880                                 emit_widen = FALSE;
9881                                 goto call_end;
9882                         }
9883
9884                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual_ ? sp [0] : NULL);
9885                         if (ins)
9886                                 goto call_end;
9887
9888                         /* Tail prefix / tail call optimization */
9889
9890                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
9891                         /* FIXME: runtime generic context pointer for jumps? */
9892                         /* FIXME: handle this for generic sharing eventually */
9893                         if ((ins_flag & MONO_INST_TAILCALL) &&
9894                                 !vtable_arg && !cfg->gshared && is_supported_tail_call (cfg, method, cmethod, fsig, call_opcode))
9895                                 supported_tail_call = TRUE;
9896
9897                         if (supported_tail_call) {
9898                                 MonoCallInst *call;
9899
9900                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9901                                 INLINE_FAILURE ("tail call");
9902
9903                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
9904
9905                                 if (cfg->backend->have_op_tail_call) {
9906                                         /* Handle tail calls similarly to normal calls */
9907                                         tail_call = TRUE;
9908                                 } else {
9909                                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
9910
9911                                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9912                                         call->tail_call = TRUE;
9913                                         call->method = cmethod;
9914                                         call->signature = mono_method_signature (cmethod);
9915
9916                                         /*
9917                                          * We implement tail calls by storing the actual arguments into the 
9918                                          * argument variables, then emitting a CEE_JMP.
9919                                          */
9920                                         for (i = 0; i < n; ++i) {
9921                                                 /* Prevent argument from being register allocated */
9922                                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
9923                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9924                                         }
9925                                         ins = (MonoInst*)call;
9926                                         ins->inst_p0 = cmethod;
9927                                         ins->inst_p1 = arg_array [0];
9928                                         MONO_ADD_INS (cfg->cbb, ins);
9929                                         link_bblock (cfg, cfg->cbb, end_bblock);
9930                                         start_new_bblock = 1;
9931
9932                                         // FIXME: Eliminate unreachable epilogs
9933
9934                                         /*
9935                                          * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9936                                          * only reachable from this call.
9937                                          */
9938                                         GET_BBLOCK (cfg, tblock, ip + 5);
9939                                         if (tblock == cfg->cbb || tblock->in_count == 0)
9940                                                 skip_ret = TRUE;
9941                                         push_res = FALSE;
9942
9943                                         goto call_end;
9944                                 }
9945                         }
9946
9947                         /* 
9948                          * Synchronized wrappers.
9949                          * Its hard to determine where to replace a method with its synchronized
9950                          * wrapper without causing an infinite recursion. The current solution is
9951                          * to add the synchronized wrapper in the trampolines, and to
9952                          * change the called method to a dummy wrapper, and resolve that wrapper
9953                          * to the real method in mono_jit_compile_method ().
9954                          */
9955                         if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
9956                                 MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
9957                                 if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
9958                                         cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
9959                         }
9960
9961                         /*
9962                          * Virtual calls in llvm-only mode.
9963                          */
9964                         if (cfg->llvm_only && virtual_ && cmethod && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
9965                                 ins = emit_llvmonly_virtual_call (cfg, cmethod, fsig, context_used, sp);
9966                                 goto call_end;
9967                         }
9968
9969                         /* Common call */
9970                         INLINE_FAILURE ("call");
9971                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual_ ? sp [0] : NULL,
9972                                                                                           imt_arg, vtable_arg);
9973
9974                         if (tail_call && !cfg->llvm_only) {
9975                                 link_bblock (cfg, cfg->cbb, end_bblock);
9976                                 start_new_bblock = 1;
9977
9978                                 // FIXME: Eliminate unreachable epilogs
9979
9980                                 /*
9981                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9982                                  * only reachable from this call.
9983                                  */
9984                                 GET_BBLOCK (cfg, tblock, ip + 5);
9985                                 if (tblock == cfg->cbb || tblock->in_count == 0)
9986                                         skip_ret = TRUE;
9987                                 push_res = FALSE;
9988                         }
9989
9990                         call_end:
9991
9992                         /* End of call, INS should contain the result of the call, if any */
9993
9994                         if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
9995                                 g_assert (ins);
9996                                 if (emit_widen)
9997                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
9998                                 else
9999                                         *sp++ = ins;
10000                         }
10001
10002                         if (keep_this_alive) {
10003                                 MonoInst *dummy_use;
10004
10005                                 /* See mono_emit_method_call_full () */
10006                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
10007                         }
10008
10009                         CHECK_CFG_EXCEPTION;
10010
10011                         ip += 5;
10012                         if (skip_ret) {
10013                                 g_assert (*ip == CEE_RET);
10014                                 ip += 1;
10015                         }
10016                         ins_flag = 0;
10017                         constrained_class = NULL;
10018                         if (need_seq_point)
10019                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10020                         break;
10021                 }
10022                 case CEE_RET:
10023                         if (cfg->method != method) {
10024                                 /* return from inlined method */
10025                                 /* 
10026                                  * If in_count == 0, that means the ret is unreachable due to
10027                                  * being preceeded by a throw. In that case, inline_method () will
10028                                  * handle setting the return value 
10029                                  * (test case: test_0_inline_throw ()).
10030                                  */
10031                                 if (return_var && cfg->cbb->in_count) {
10032                                         MonoType *ret_type = mono_method_signature (method)->ret;
10033
10034                                         MonoInst *store;
10035                                         CHECK_STACK (1);
10036                                         --sp;
10037
10038                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
10039                                                 UNVERIFIED;
10040
10041                                         //g_assert (returnvar != -1);
10042                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
10043                                         cfg->ret_var_set = TRUE;
10044                                 } 
10045                         } else {
10046                                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
10047
10048                                 if (cfg->lmf_var && cfg->cbb->in_count && !cfg->llvm_only)
10049                                         emit_pop_lmf (cfg);
10050
10051                                 if (cfg->ret) {
10052                                         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (method)->ret);
10053
10054                                         if (seq_points && !sym_seq_points) {
10055                                                 /* 
10056                                                  * Place a seq point here too even through the IL stack is not
10057                                                  * empty, so a step over on
10058                                                  * call <FOO>
10059                                                  * ret
10060                                                  * will work correctly.
10061                                                  */
10062                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
10063                                                 MONO_ADD_INS (cfg->cbb, ins);
10064                                         }
10065
10066                                         g_assert (!return_var);
10067                                         CHECK_STACK (1);
10068                                         --sp;
10069
10070                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
10071                                                 UNVERIFIED;
10072
10073                                         emit_setret (cfg, *sp);
10074                                 }
10075                         }
10076                         if (sp != stack_start)
10077                                 UNVERIFIED;
10078                         MONO_INST_NEW (cfg, ins, OP_BR);
10079                         ip++;
10080                         ins->inst_target_bb = end_bblock;
10081                         MONO_ADD_INS (cfg->cbb, ins);
10082                         link_bblock (cfg, cfg->cbb, end_bblock);
10083                         start_new_bblock = 1;
10084                         break;
10085                 case CEE_BR_S:
10086                         CHECK_OPSIZE (2);
10087                         MONO_INST_NEW (cfg, ins, OP_BR);
10088                         ip++;
10089                         target = ip + 1 + (signed char)(*ip);
10090                         ++ip;
10091                         GET_BBLOCK (cfg, tblock, target);
10092                         link_bblock (cfg, cfg->cbb, tblock);
10093                         ins->inst_target_bb = tblock;
10094                         if (sp != stack_start) {
10095                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10096                                 sp = stack_start;
10097                                 CHECK_UNVERIFIABLE (cfg);
10098                         }
10099                         MONO_ADD_INS (cfg->cbb, ins);
10100                         start_new_bblock = 1;
10101                         inline_costs += BRANCH_COST;
10102                         break;
10103                 case CEE_BEQ_S:
10104                 case CEE_BGE_S:
10105                 case CEE_BGT_S:
10106                 case CEE_BLE_S:
10107                 case CEE_BLT_S:
10108                 case CEE_BNE_UN_S:
10109                 case CEE_BGE_UN_S:
10110                 case CEE_BGT_UN_S:
10111                 case CEE_BLE_UN_S:
10112                 case CEE_BLT_UN_S:
10113                         CHECK_OPSIZE (2);
10114                         CHECK_STACK (2);
10115                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
10116                         ip++;
10117                         target = ip + 1 + *(signed char*)ip;
10118                         ip++;
10119
10120                         ADD_BINCOND (NULL);
10121
10122                         sp = stack_start;
10123                         inline_costs += BRANCH_COST;
10124                         break;
10125                 case CEE_BR:
10126                         CHECK_OPSIZE (5);
10127                         MONO_INST_NEW (cfg, ins, OP_BR);
10128                         ip++;
10129
10130                         target = ip + 4 + (gint32)read32(ip);
10131                         ip += 4;
10132                         GET_BBLOCK (cfg, tblock, target);
10133                         link_bblock (cfg, cfg->cbb, tblock);
10134                         ins->inst_target_bb = tblock;
10135                         if (sp != stack_start) {
10136                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10137                                 sp = stack_start;
10138                                 CHECK_UNVERIFIABLE (cfg);
10139                         }
10140
10141                         MONO_ADD_INS (cfg->cbb, ins);
10142
10143                         start_new_bblock = 1;
10144                         inline_costs += BRANCH_COST;
10145                         break;
10146                 case CEE_BRFALSE_S:
10147                 case CEE_BRTRUE_S:
10148                 case CEE_BRFALSE:
10149                 case CEE_BRTRUE: {
10150                         MonoInst *cmp;
10151                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
10152                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
10153                         guint32 opsize = is_short ? 1 : 4;
10154
10155                         CHECK_OPSIZE (opsize);
10156                         CHECK_STACK (1);
10157                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
10158                                 UNVERIFIED;
10159                         ip ++;
10160                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
10161                         ip += opsize;
10162
10163                         sp--;
10164
10165                         GET_BBLOCK (cfg, tblock, target);
10166                         link_bblock (cfg, cfg->cbb, tblock);
10167                         GET_BBLOCK (cfg, tblock, ip);
10168                         link_bblock (cfg, cfg->cbb, tblock);
10169
10170                         if (sp != stack_start) {
10171                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10172                                 CHECK_UNVERIFIABLE (cfg);
10173                         }
10174
10175                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
10176                         cmp->sreg1 = sp [0]->dreg;
10177                         type_from_op (cfg, cmp, sp [0], NULL);
10178                         CHECK_TYPE (cmp);
10179
10180 #if SIZEOF_REGISTER == 4
10181                         if (cmp->opcode == OP_LCOMPARE_IMM) {
10182                                 /* Convert it to OP_LCOMPARE */
10183                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
10184                                 ins->type = STACK_I8;
10185                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
10186                                 ins->inst_l = 0;
10187                                 MONO_ADD_INS (cfg->cbb, ins);
10188                                 cmp->opcode = OP_LCOMPARE;
10189                                 cmp->sreg2 = ins->dreg;
10190                         }
10191 #endif
10192                         MONO_ADD_INS (cfg->cbb, cmp);
10193
10194                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
10195                         type_from_op (cfg, ins, sp [0], NULL);
10196                         MONO_ADD_INS (cfg->cbb, ins);
10197                         ins->inst_many_bb = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
10198                         GET_BBLOCK (cfg, tblock, target);
10199                         ins->inst_true_bb = tblock;
10200                         GET_BBLOCK (cfg, tblock, ip);
10201                         ins->inst_false_bb = tblock;
10202                         start_new_bblock = 2;
10203
10204                         sp = stack_start;
10205                         inline_costs += BRANCH_COST;
10206                         break;
10207                 }
10208                 case CEE_BEQ:
10209                 case CEE_BGE:
10210                 case CEE_BGT:
10211                 case CEE_BLE:
10212                 case CEE_BLT:
10213                 case CEE_BNE_UN:
10214                 case CEE_BGE_UN:
10215                 case CEE_BGT_UN:
10216                 case CEE_BLE_UN:
10217                 case CEE_BLT_UN:
10218                         CHECK_OPSIZE (5);
10219                         CHECK_STACK (2);
10220                         MONO_INST_NEW (cfg, ins, *ip);
10221                         ip++;
10222                         target = ip + 4 + (gint32)read32(ip);
10223                         ip += 4;
10224
10225                         ADD_BINCOND (NULL);
10226
10227                         sp = stack_start;
10228                         inline_costs += BRANCH_COST;
10229                         break;
10230                 case CEE_SWITCH: {
10231                         MonoInst *src1;
10232                         MonoBasicBlock **targets;
10233                         MonoBasicBlock *default_bblock;
10234                         MonoJumpInfoBBTable *table;
10235                         int offset_reg = alloc_preg (cfg);
10236                         int target_reg = alloc_preg (cfg);
10237                         int table_reg = alloc_preg (cfg);
10238                         int sum_reg = alloc_preg (cfg);
10239                         gboolean use_op_switch;
10240
10241                         CHECK_OPSIZE (5);
10242                         CHECK_STACK (1);
10243                         n = read32 (ip + 1);
10244                         --sp;
10245                         src1 = sp [0];
10246                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
10247                                 UNVERIFIED;
10248
10249                         ip += 5;
10250                         CHECK_OPSIZE (n * sizeof (guint32));
10251                         target = ip + n * sizeof (guint32);
10252
10253                         GET_BBLOCK (cfg, default_bblock, target);
10254                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
10255
10256                         targets = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
10257                         for (i = 0; i < n; ++i) {
10258                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
10259                                 targets [i] = tblock;
10260                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
10261                                 ip += 4;
10262                         }
10263
10264                         if (sp != stack_start) {
10265                                 /* 
10266                                  * Link the current bb with the targets as well, so handle_stack_args
10267                                  * will set their in_stack correctly.
10268                                  */
10269                                 link_bblock (cfg, cfg->cbb, default_bblock);
10270                                 for (i = 0; i < n; ++i)
10271                                         link_bblock (cfg, cfg->cbb, targets [i]);
10272
10273                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10274                                 sp = stack_start;
10275                                 CHECK_UNVERIFIABLE (cfg);
10276
10277                                 /* Undo the links */
10278                                 mono_unlink_bblock (cfg, cfg->cbb, default_bblock);
10279                                 for (i = 0; i < n; ++i)
10280                                         mono_unlink_bblock (cfg, cfg->cbb, targets [i]);
10281                         }
10282
10283                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
10284                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
10285
10286                         for (i = 0; i < n; ++i)
10287                                 link_bblock (cfg, cfg->cbb, targets [i]);
10288
10289                         table = (MonoJumpInfoBBTable *)mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
10290                         table->table = targets;
10291                         table->table_size = n;
10292
10293                         use_op_switch = FALSE;
10294 #ifdef TARGET_ARM
10295                         /* ARM implements SWITCH statements differently */
10296                         /* FIXME: Make it use the generic implementation */
10297                         if (!cfg->compile_aot)
10298                                 use_op_switch = TRUE;
10299 #endif
10300
10301                         if (COMPILE_LLVM (cfg))
10302                                 use_op_switch = TRUE;
10303
10304                         cfg->cbb->has_jump_table = 1;
10305
10306                         if (use_op_switch) {
10307                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
10308                                 ins->sreg1 = src1->dreg;
10309                                 ins->inst_p0 = table;
10310                                 ins->inst_many_bb = targets;
10311                                 ins->klass = (MonoClass *)GUINT_TO_POINTER (n);
10312                                 MONO_ADD_INS (cfg->cbb, ins);
10313                         } else {
10314                                 if (sizeof (gpointer) == 8)
10315                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
10316                                 else
10317                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
10318
10319 #if SIZEOF_REGISTER == 8
10320                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
10321                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
10322 #endif
10323
10324                                 if (cfg->compile_aot) {
10325                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
10326                                 } else {
10327                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
10328                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
10329                                         ins->inst_p0 = table;
10330                                         ins->dreg = table_reg;
10331                                         MONO_ADD_INS (cfg->cbb, ins);
10332                                 }
10333
10334                                 /* FIXME: Use load_memindex */
10335                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
10336                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
10337                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
10338                         }
10339                         start_new_bblock = 1;
10340                         inline_costs += (BRANCH_COST * 2);
10341                         break;
10342                 }
10343                 case CEE_LDIND_I1:
10344                 case CEE_LDIND_U1:
10345                 case CEE_LDIND_I2:
10346                 case CEE_LDIND_U2:
10347                 case CEE_LDIND_I4:
10348                 case CEE_LDIND_U4:
10349                 case CEE_LDIND_I8:
10350                 case CEE_LDIND_I:
10351                 case CEE_LDIND_R4:
10352                 case CEE_LDIND_R8:
10353                 case CEE_LDIND_REF:
10354                         CHECK_STACK (1);
10355                         --sp;
10356
10357                         switch (*ip) {
10358                         case CEE_LDIND_R4:
10359                         case CEE_LDIND_R8:
10360                                 dreg = alloc_freg (cfg);
10361                                 break;
10362                         case CEE_LDIND_I8:
10363                                 dreg = alloc_lreg (cfg);
10364                                 break;
10365                         case CEE_LDIND_REF:
10366                                 dreg = alloc_ireg_ref (cfg);
10367                                 break;
10368                         default:
10369                                 dreg = alloc_preg (cfg);
10370                         }
10371
10372                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
10373                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
10374                         if (*ip == CEE_LDIND_R4)
10375                                 ins->type = cfg->r4_stack_type;
10376                         ins->flags |= ins_flag;
10377                         MONO_ADD_INS (cfg->cbb, ins);
10378                         *sp++ = ins;
10379                         if (ins_flag & MONO_INST_VOLATILE) {
10380                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10381                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10382                         }
10383                         ins_flag = 0;
10384                         ++ip;
10385                         break;
10386                 case CEE_STIND_REF:
10387                 case CEE_STIND_I1:
10388                 case CEE_STIND_I2:
10389                 case CEE_STIND_I4:
10390                 case CEE_STIND_I8:
10391                 case CEE_STIND_R4:
10392                 case CEE_STIND_R8:
10393                 case CEE_STIND_I:
10394                         CHECK_STACK (2);
10395                         sp -= 2;
10396
10397                         if (ins_flag & MONO_INST_VOLATILE) {
10398                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
10399                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
10400                         }
10401
10402                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
10403                         ins->flags |= ins_flag;
10404                         ins_flag = 0;
10405
10406                         MONO_ADD_INS (cfg->cbb, ins);
10407
10408                         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)))
10409                                 emit_write_barrier (cfg, sp [0], sp [1]);
10410
10411                         inline_costs += 1;
10412                         ++ip;
10413                         break;
10414
10415                 case CEE_MUL:
10416                         CHECK_STACK (2);
10417
10418                         MONO_INST_NEW (cfg, ins, (*ip));
10419                         sp -= 2;
10420                         ins->sreg1 = sp [0]->dreg;
10421                         ins->sreg2 = sp [1]->dreg;
10422                         type_from_op (cfg, ins, sp [0], sp [1]);
10423                         CHECK_TYPE (ins);
10424                         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type);
10425
10426                         /* Use the immediate opcodes if possible */
10427                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
10428                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
10429                                 if (imm_opcode != -1) {
10430                                         ins->opcode = imm_opcode;
10431                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
10432                                         ins->sreg2 = -1;
10433
10434                                         NULLIFY_INS (sp [1]);
10435                                 }
10436                         }
10437
10438                         MONO_ADD_INS ((cfg)->cbb, (ins));
10439
10440                         *sp++ = mono_decompose_opcode (cfg, ins);
10441                         ip++;
10442                         break;
10443                 case CEE_ADD:
10444                 case CEE_SUB:
10445                 case CEE_DIV:
10446                 case CEE_DIV_UN:
10447                 case CEE_REM:
10448                 case CEE_REM_UN:
10449                 case CEE_AND:
10450                 case CEE_OR:
10451                 case CEE_XOR:
10452                 case CEE_SHL:
10453                 case CEE_SHR:
10454                 case CEE_SHR_UN:
10455                         CHECK_STACK (2);
10456
10457                         MONO_INST_NEW (cfg, ins, (*ip));
10458                         sp -= 2;
10459                         ins->sreg1 = sp [0]->dreg;
10460                         ins->sreg2 = sp [1]->dreg;
10461                         type_from_op (cfg, ins, sp [0], sp [1]);
10462                         CHECK_TYPE (ins);
10463                         add_widen_op (cfg, ins, &sp [0], &sp [1]);
10464                         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type);
10465
10466                         /* FIXME: Pass opcode to is_inst_imm */
10467
10468                         /* Use the immediate opcodes if possible */
10469                         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)) {
10470                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
10471                                 if (imm_opcode != -1) {
10472                                         ins->opcode = imm_opcode;
10473                                         if (sp [1]->opcode == OP_I8CONST) {
10474 #if SIZEOF_REGISTER == 8
10475                                                 ins->inst_imm = sp [1]->inst_l;
10476 #else
10477                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
10478                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
10479 #endif
10480                                         }
10481                                         else
10482                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
10483                                         ins->sreg2 = -1;
10484
10485                                         /* Might be followed by an instruction added by add_widen_op */
10486                                         if (sp [1]->next == NULL)
10487                                                 NULLIFY_INS (sp [1]);
10488                                 }
10489                         }
10490                         MONO_ADD_INS ((cfg)->cbb, (ins));
10491
10492                         *sp++ = mono_decompose_opcode (cfg, ins);
10493                         ip++;
10494                         break;
10495                 case CEE_NEG:
10496                 case CEE_NOT:
10497                 case CEE_CONV_I1:
10498                 case CEE_CONV_I2:
10499                 case CEE_CONV_I4:
10500                 case CEE_CONV_R4:
10501                 case CEE_CONV_R8:
10502                 case CEE_CONV_U4:
10503                 case CEE_CONV_I8:
10504                 case CEE_CONV_U8:
10505                 case CEE_CONV_OVF_I8:
10506                 case CEE_CONV_OVF_U8:
10507                 case CEE_CONV_R_UN:
10508                         CHECK_STACK (1);
10509
10510                         /* Special case this earlier so we have long constants in the IR */
10511                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
10512                                 int data = sp [-1]->inst_c0;
10513                                 sp [-1]->opcode = OP_I8CONST;
10514                                 sp [-1]->type = STACK_I8;
10515 #if SIZEOF_REGISTER == 8
10516                                 if ((*ip) == CEE_CONV_U8)
10517                                         sp [-1]->inst_c0 = (guint32)data;
10518                                 else
10519                                         sp [-1]->inst_c0 = data;
10520 #else
10521                                 sp [-1]->inst_ls_word = data;
10522                                 if ((*ip) == CEE_CONV_U8)
10523                                         sp [-1]->inst_ms_word = 0;
10524                                 else
10525                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
10526 #endif
10527                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
10528                         }
10529                         else {
10530                                 ADD_UNOP (*ip);
10531                         }
10532                         ip++;
10533                         break;
10534                 case CEE_CONV_OVF_I4:
10535                 case CEE_CONV_OVF_I1:
10536                 case CEE_CONV_OVF_I2:
10537                 case CEE_CONV_OVF_I:
10538                 case CEE_CONV_OVF_U:
10539                         CHECK_STACK (1);
10540
10541                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10542                                 ADD_UNOP (CEE_CONV_OVF_I8);
10543                                 ADD_UNOP (*ip);
10544                         } else {
10545                                 ADD_UNOP (*ip);
10546                         }
10547                         ip++;
10548                         break;
10549                 case CEE_CONV_OVF_U1:
10550                 case CEE_CONV_OVF_U2:
10551                 case CEE_CONV_OVF_U4:
10552                         CHECK_STACK (1);
10553
10554                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10555                                 ADD_UNOP (CEE_CONV_OVF_U8);
10556                                 ADD_UNOP (*ip);
10557                         } else {
10558                                 ADD_UNOP (*ip);
10559                         }
10560                         ip++;
10561                         break;
10562                 case CEE_CONV_OVF_I1_UN:
10563                 case CEE_CONV_OVF_I2_UN:
10564                 case CEE_CONV_OVF_I4_UN:
10565                 case CEE_CONV_OVF_I8_UN:
10566                 case CEE_CONV_OVF_U1_UN:
10567                 case CEE_CONV_OVF_U2_UN:
10568                 case CEE_CONV_OVF_U4_UN:
10569                 case CEE_CONV_OVF_U8_UN:
10570                 case CEE_CONV_OVF_I_UN:
10571                 case CEE_CONV_OVF_U_UN:
10572                 case CEE_CONV_U2:
10573                 case CEE_CONV_U1:
10574                 case CEE_CONV_I:
10575                 case CEE_CONV_U:
10576                         CHECK_STACK (1);
10577                         ADD_UNOP (*ip);
10578                         CHECK_CFG_EXCEPTION;
10579                         ip++;
10580                         break;
10581                 case CEE_ADD_OVF:
10582                 case CEE_ADD_OVF_UN:
10583                 case CEE_MUL_OVF:
10584                 case CEE_MUL_OVF_UN:
10585                 case CEE_SUB_OVF:
10586                 case CEE_SUB_OVF_UN:
10587                         CHECK_STACK (2);
10588                         ADD_BINOP (*ip);
10589                         ip++;
10590                         break;
10591                 case CEE_CPOBJ:
10592                         GSHAREDVT_FAILURE (*ip);
10593                         CHECK_OPSIZE (5);
10594                         CHECK_STACK (2);
10595                         token = read32 (ip + 1);
10596                         klass = mini_get_class (method, token, generic_context);
10597                         CHECK_TYPELOAD (klass);
10598                         sp -= 2;
10599                         if (generic_class_is_reference_type (cfg, klass)) {
10600                                 MonoInst *store, *load;
10601                                 int dreg = alloc_ireg_ref (cfg);
10602
10603                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
10604                                 load->flags |= ins_flag;
10605                                 MONO_ADD_INS (cfg->cbb, load);
10606
10607                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
10608                                 store->flags |= ins_flag;
10609                                 MONO_ADD_INS (cfg->cbb, store);
10610
10611                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
10612                                         emit_write_barrier (cfg, sp [0], sp [1]);
10613                         } else {
10614                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10615                         }
10616                         ins_flag = 0;
10617                         ip += 5;
10618                         break;
10619                 case CEE_LDOBJ: {
10620                         int loc_index = -1;
10621                         int stloc_len = 0;
10622
10623                         CHECK_OPSIZE (5);
10624                         CHECK_STACK (1);
10625                         --sp;
10626                         token = read32 (ip + 1);
10627                         klass = mini_get_class (method, token, generic_context);
10628                         CHECK_TYPELOAD (klass);
10629
10630                         /* Optimize the common ldobj+stloc combination */
10631                         switch (ip [5]) {
10632                         case CEE_STLOC_S:
10633                                 loc_index = ip [6];
10634                                 stloc_len = 2;
10635                                 break;
10636                         case CEE_STLOC_0:
10637                         case CEE_STLOC_1:
10638                         case CEE_STLOC_2:
10639                         case CEE_STLOC_3:
10640                                 loc_index = ip [5] - CEE_STLOC_0;
10641                                 stloc_len = 1;
10642                                 break;
10643                         default:
10644                                 break;
10645                         }
10646
10647                         if ((loc_index != -1) && ip_in_bb (cfg, cfg->cbb, ip + 5)) {
10648                                 CHECK_LOCAL (loc_index);
10649
10650                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10651                                 ins->dreg = cfg->locals [loc_index]->dreg;
10652                                 ins->flags |= ins_flag;
10653                                 ip += 5;
10654                                 ip += stloc_len;
10655                                 if (ins_flag & MONO_INST_VOLATILE) {
10656                                         /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10657                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10658                                 }
10659                                 ins_flag = 0;
10660                                 break;
10661                         }
10662
10663                         /* Optimize the ldobj+stobj combination */
10664                         /* The reference case ends up being a load+store anyway */
10665                         /* Skip this if the operation is volatile. */
10666                         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)) {
10667                                 CHECK_STACK (1);
10668
10669                                 sp --;
10670
10671                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10672
10673                                 ip += 5 + 5;
10674                                 ins_flag = 0;
10675                                 break;
10676                         }
10677
10678                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10679                         ins->flags |= ins_flag;
10680                         *sp++ = ins;
10681
10682                         if (ins_flag & MONO_INST_VOLATILE) {
10683                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10684                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10685                         }
10686
10687                         ip += 5;
10688                         ins_flag = 0;
10689                         inline_costs += 1;
10690                         break;
10691                 }
10692                 case CEE_LDSTR:
10693                         CHECK_STACK_OVF (1);
10694                         CHECK_OPSIZE (5);
10695                         n = read32 (ip + 1);
10696
10697                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
10698                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
10699                                 ins->type = STACK_OBJ;
10700                                 *sp = ins;
10701                         }
10702                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
10703                                 MonoInst *iargs [1];
10704                                 char *str = (char *)mono_method_get_wrapper_data (method, n);
10705
10706                                 if (cfg->compile_aot)
10707                                         EMIT_NEW_LDSTRLITCONST (cfg, iargs [0], str);
10708                                 else
10709                                         EMIT_NEW_PCONST (cfg, iargs [0], str);
10710                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
10711                         } else {
10712                                 if (cfg->opt & MONO_OPT_SHARED) {
10713                                         MonoInst *iargs [3];
10714
10715                                         if (cfg->compile_aot) {
10716                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
10717                                         }
10718                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10719                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
10720                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
10721                                         *sp = mono_emit_jit_icall (cfg, mono_ldstr, iargs);
10722                                         mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
10723                                 } else {
10724                                         if (cfg->cbb->out_of_line) {
10725                                                 MonoInst *iargs [2];
10726
10727                                                 if (image == mono_defaults.corlib) {
10728                                                         /* 
10729                                                          * Avoid relocations in AOT and save some space by using a 
10730                                                          * version of helper_ldstr specialized to mscorlib.
10731                                                          */
10732                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
10733                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
10734                                                 } else {
10735                                                         /* Avoid creating the string object */
10736                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
10737                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
10738                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
10739                                                 }
10740                                         } 
10741                                         else
10742                                         if (cfg->compile_aot) {
10743                                                 NEW_LDSTRCONST (cfg, ins, image, n);
10744                                                 *sp = ins;
10745                                                 MONO_ADD_INS (cfg->cbb, ins);
10746                                         } 
10747                                         else {
10748                                                 NEW_PCONST (cfg, ins, NULL);
10749                                                 ins->type = STACK_OBJ;
10750                                                 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
10751                                                 if (!ins->inst_p0)
10752                                                         OUT_OF_MEMORY_FAILURE;
10753
10754                                                 *sp = ins;
10755                                                 MONO_ADD_INS (cfg->cbb, ins);
10756                                         }
10757                                 }
10758                         }
10759
10760                         sp++;
10761                         ip += 5;
10762                         break;
10763                 case CEE_NEWOBJ: {
10764                         MonoInst *iargs [2];
10765                         MonoMethodSignature *fsig;
10766                         MonoInst this_ins;
10767                         MonoInst *alloc;
10768                         MonoInst *vtable_arg = NULL;
10769
10770                         CHECK_OPSIZE (5);
10771                         token = read32 (ip + 1);
10772                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
10773                         CHECK_CFG_ERROR;
10774
10775                         fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
10776                         CHECK_CFG_ERROR;
10777
10778                         mono_save_token_info (cfg, image, token, cmethod);
10779
10780                         if (!mono_class_init (cmethod->klass))
10781                                 TYPE_LOAD_ERROR (cmethod->klass);
10782
10783                         context_used = mini_method_check_context_used (cfg, cmethod);
10784
10785                         if (mono_security_core_clr_enabled ())
10786                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
10787
10788                         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)) {
10789                                 emit_class_init (cfg, cmethod->klass);
10790                                 CHECK_TYPELOAD (cmethod->klass);
10791                         }
10792
10793                         /*
10794                         if (cfg->gsharedvt) {
10795                                 if (mini_is_gsharedvt_variable_signature (sig))
10796                                         GSHAREDVT_FAILURE (*ip);
10797                         }
10798                         */
10799
10800                         n = fsig->param_count;
10801                         CHECK_STACK (n);
10802
10803                         /* 
10804                          * Generate smaller code for the common newobj <exception> instruction in
10805                          * argument checking code.
10806                          */
10807                         if (cfg->cbb->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
10808                                 is_exception_class (cmethod->klass) && n <= 2 &&
10809                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
10810                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
10811                                 MonoInst *iargs [3];
10812
10813                                 sp -= n;
10814
10815                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
10816                                 switch (n) {
10817                                 case 0:
10818                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
10819                                         break;
10820                                 case 1:
10821                                         iargs [1] = sp [0];
10822                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
10823                                         break;
10824                                 case 2:
10825                                         iargs [1] = sp [0];
10826                                         iargs [2] = sp [1];
10827                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
10828                                         break;
10829                                 default:
10830                                         g_assert_not_reached ();
10831                                 }
10832
10833                                 ip += 5;
10834                                 inline_costs += 5;
10835                                 break;
10836                         }
10837
10838                         /* move the args to allow room for 'this' in the first position */
10839                         while (n--) {
10840                                 --sp;
10841                                 sp [1] = sp [0];
10842                         }
10843
10844                         /* check_call_signature () requires sp[0] to be set */
10845                         this_ins.type = STACK_OBJ;
10846                         sp [0] = &this_ins;
10847                         if (check_call_signature (cfg, fsig, sp))
10848                                 UNVERIFIED;
10849
10850                         iargs [0] = NULL;
10851
10852                         if (mini_class_is_system_array (cmethod->klass)) {
10853                                 *sp = emit_get_rgctx_method (cfg, context_used,
10854                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
10855
10856                                 /* Avoid varargs in the common case */
10857                                 if (fsig->param_count == 1)
10858                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
10859                                 else if (fsig->param_count == 2)
10860                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
10861                                 else if (fsig->param_count == 3)
10862                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
10863                                 else if (fsig->param_count == 4)
10864                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
10865                                 else
10866                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
10867                         } else if (cmethod->string_ctor) {
10868                                 g_assert (!context_used);
10869                                 g_assert (!vtable_arg);
10870                                 /* we simply pass a null pointer */
10871                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
10872                                 /* now call the string ctor */
10873                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
10874                         } else {
10875                                 if (cmethod->klass->valuetype) {
10876                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
10877                                         emit_init_rvar (cfg, iargs [0]->dreg, &cmethod->klass->byval_arg);
10878                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
10879
10880                                         alloc = NULL;
10881
10882                                         /* 
10883                                          * The code generated by mini_emit_virtual_call () expects
10884                                          * iargs [0] to be a boxed instance, but luckily the vcall
10885                                          * will be transformed into a normal call there.
10886                                          */
10887                                 } else if (context_used) {
10888                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
10889                                         *sp = alloc;
10890                                 } else {
10891                                         MonoVTable *vtable = NULL;
10892
10893                                         if (!cfg->compile_aot)
10894                                                 vtable = mono_class_vtable (cfg->domain, cmethod->klass);
10895                                         CHECK_TYPELOAD (cmethod->klass);
10896
10897                                         /*
10898                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
10899                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
10900                                          * As a workaround, we call class cctors before allocating objects.
10901                                          */
10902                                         if (mini_field_access_needs_cctor_run (cfg, method, cmethod->klass, vtable) && !(g_slist_find (class_inits, cmethod->klass))) {
10903                                                 emit_class_init (cfg, cmethod->klass);
10904                                                 if (cfg->verbose_level > 2)
10905                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
10906                                                 class_inits = g_slist_prepend (class_inits, cmethod->klass);
10907                                         }
10908
10909                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
10910                                         *sp = alloc;
10911                                 }
10912                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
10913
10914                                 if (alloc)
10915                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
10916
10917                                 /* Now call the actual ctor */
10918                                 handle_ctor_call (cfg, cmethod, fsig, context_used, sp, ip, &inline_costs);
10919                                 CHECK_CFG_EXCEPTION;
10920                         }
10921
10922                         if (alloc == NULL) {
10923                                 /* Valuetype */
10924                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
10925                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
10926                                 *sp++= ins;
10927                         } else {
10928                                 *sp++ = alloc;
10929                         }
10930                         
10931                         ip += 5;
10932                         inline_costs += 5;
10933                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip - header->code)))
10934                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10935                         break;
10936                 }
10937                 case CEE_CASTCLASS:
10938                         CHECK_STACK (1);
10939                         --sp;
10940                         CHECK_OPSIZE (5);
10941                         token = read32 (ip + 1);
10942                         klass = mini_get_class (method, token, generic_context);
10943                         CHECK_TYPELOAD (klass);
10944                         if (sp [0]->type != STACK_OBJ)
10945                                 UNVERIFIED;
10946
10947                         ins = handle_castclass (cfg, klass, *sp, ip, &inline_costs);
10948                         CHECK_CFG_EXCEPTION;
10949
10950                         *sp ++ = ins;
10951                         ip += 5;
10952                         break;
10953                 case CEE_ISINST: {
10954                         CHECK_STACK (1);
10955                         --sp;
10956                         CHECK_OPSIZE (5);
10957                         token = read32 (ip + 1);
10958                         klass = mini_get_class (method, token, generic_context);
10959                         CHECK_TYPELOAD (klass);
10960                         if (sp [0]->type != STACK_OBJ)
10961                                 UNVERIFIED;
10962  
10963                         context_used = mini_class_check_context_used (cfg, klass);
10964
10965                         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
10966                                 MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
10967                                 MonoInst *args [3];
10968                                 int idx;
10969
10970                                 /* obj */
10971                                 args [0] = *sp;
10972
10973                                 /* klass */
10974                                 EMIT_NEW_CLASSCONST (cfg, args [1], klass);
10975
10976                                 /* inline cache*/
10977                                 idx = get_castclass_cache_idx (cfg);
10978                                 args [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
10979
10980                                 *sp++ = mono_emit_method_call (cfg, mono_isinst, args, NULL);
10981                                 ip += 5;
10982                                 inline_costs += 2;
10983                         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
10984                                 MonoMethod *mono_isinst;
10985                                 MonoInst *iargs [1];
10986                                 int costs;
10987
10988                                 mono_isinst = mono_marshal_get_isinst (klass); 
10989                                 iargs [0] = sp [0];
10990
10991                                 costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), 
10992                                                                            iargs, ip, cfg->real_offset, TRUE);
10993                                 CHECK_CFG_EXCEPTION;
10994                                 g_assert (costs > 0);
10995                                 
10996                                 ip += 5;
10997                                 cfg->real_offset += 5;
10998
10999                                 *sp++= iargs [0];
11000
11001                                 inline_costs += costs;
11002                         }
11003                         else {
11004                                 ins = handle_isinst (cfg, klass, *sp, context_used);
11005                                 CHECK_CFG_EXCEPTION;
11006                                 *sp ++ = ins;
11007                                 ip += 5;
11008                         }
11009                         break;
11010                 }
11011                 case CEE_UNBOX_ANY: {
11012                         MonoInst *res, *addr;
11013
11014                         CHECK_STACK (1);
11015                         --sp;
11016                         CHECK_OPSIZE (5);
11017                         token = read32 (ip + 1);
11018                         klass = mini_get_class (method, token, generic_context);
11019                         CHECK_TYPELOAD (klass);
11020
11021                         mono_save_token_info (cfg, image, token, klass);
11022
11023                         context_used = mini_class_check_context_used (cfg, klass);
11024
11025                         if (mini_is_gsharedvt_klass (klass)) {
11026                                 res = handle_unbox_gsharedvt (cfg, klass, *sp);
11027                                 inline_costs += 2;
11028                         } else if (generic_class_is_reference_type (cfg, klass)) {
11029                                 res = handle_castclass (cfg, klass, *sp, ip, &inline_costs);
11030                                 CHECK_CFG_EXCEPTION;
11031                         } else if (mono_class_is_nullable (klass)) {
11032                                 res = handle_unbox_nullable (cfg, *sp, klass, context_used);
11033                         } else {
11034                                 addr = handle_unbox (cfg, klass, sp, context_used);
11035                                 /* LDOBJ */
11036                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11037                                 res = ins;
11038                                 inline_costs += 2;
11039                         }
11040
11041                         *sp ++ = res;
11042                         ip += 5;
11043                         break;
11044                 }
11045                 case CEE_BOX: {
11046                         MonoInst *val;
11047                         MonoClass *enum_class;
11048                         MonoMethod *has_flag;
11049
11050                         CHECK_STACK (1);
11051                         --sp;
11052                         val = *sp;
11053                         CHECK_OPSIZE (5);
11054                         token = read32 (ip + 1);
11055                         klass = mini_get_class (method, token, generic_context);
11056                         CHECK_TYPELOAD (klass);
11057
11058                         mono_save_token_info (cfg, image, token, klass);
11059
11060                         context_used = mini_class_check_context_used (cfg, klass);
11061
11062                         if (generic_class_is_reference_type (cfg, klass)) {
11063                                 *sp++ = val;
11064                                 ip += 5;
11065                                 break;
11066                         }
11067
11068                         if (klass == mono_defaults.void_class)
11069                                 UNVERIFIED;
11070                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
11071                                 UNVERIFIED;
11072                         /* frequent check in generic code: box (struct), brtrue */
11073
11074                         /*
11075                          * Look for:
11076                          *
11077                          *   <push int/long ptr>
11078                          *   <push int/long>
11079                          *   box MyFlags
11080                          *   constrained. MyFlags
11081                          *   callvirt instace bool class [mscorlib] System.Enum::HasFlag (class [mscorlib] System.Enum)
11082                          *
11083                          * If we find this sequence and the operand types on box and constrained
11084                          * are equal, we can emit a specialized instruction sequence instead of
11085                          * the very slow HasFlag () call.
11086                          */
11087                         if ((cfg->opt & MONO_OPT_INTRINS) &&
11088                             /* Cheap checks first. */
11089                             ip + 5 + 6 + 5 < end &&
11090                             ip [5] == CEE_PREFIX1 &&
11091                             ip [6] == CEE_CONSTRAINED_ &&
11092                             ip [11] == CEE_CALLVIRT &&
11093                             ip_in_bb (cfg, cfg->cbb, ip + 5 + 6 + 5) &&
11094                             mono_class_is_enum (klass) &&
11095                             (enum_class = mini_get_class (method, read32 (ip + 7), generic_context)) &&
11096                             (has_flag = mini_get_method (cfg, method, read32 (ip + 12), NULL, generic_context)) &&
11097                             has_flag->klass == mono_defaults.enum_class &&
11098                             !strcmp (has_flag->name, "HasFlag") &&
11099                             has_flag->signature->hasthis &&
11100                             has_flag->signature->param_count == 1) {
11101                                 CHECK_TYPELOAD (enum_class);
11102
11103                                 if (enum_class == klass) {
11104                                         MonoInst *enum_this, *enum_flag;
11105
11106                                         ip += 5 + 6 + 5;
11107                                         --sp;
11108
11109                                         enum_this = sp [0];
11110                                         enum_flag = sp [1];
11111
11112                                         *sp++ = handle_enum_has_flag (cfg, klass, enum_this, enum_flag);
11113                                         break;
11114                                 }
11115                         }
11116
11117                         // FIXME: LLVM can't handle the inconsistent bb linking
11118                         if (!mono_class_is_nullable (klass) &&
11119                                 !mini_is_gsharedvt_klass (klass) &&
11120                                 ip + 5 < end && ip_in_bb (cfg, cfg->cbb, ip + 5) &&
11121                                 (ip [5] == CEE_BRTRUE || 
11122                                  ip [5] == CEE_BRTRUE_S ||
11123                                  ip [5] == CEE_BRFALSE ||
11124                                  ip [5] == CEE_BRFALSE_S)) {
11125                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
11126                                 int dreg;
11127                                 MonoBasicBlock *true_bb, *false_bb;
11128
11129                                 ip += 5;
11130
11131                                 if (cfg->verbose_level > 3) {
11132                                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
11133                                         printf ("<box+brtrue opt>\n");
11134                                 }
11135
11136                                 switch (*ip) {
11137                                 case CEE_BRTRUE_S:
11138                                 case CEE_BRFALSE_S:
11139                                         CHECK_OPSIZE (2);
11140                                         ip++;
11141                                         target = ip + 1 + (signed char)(*ip);
11142                                         ip++;
11143                                         break;
11144                                 case CEE_BRTRUE:
11145                                 case CEE_BRFALSE:
11146                                         CHECK_OPSIZE (5);
11147                                         ip++;
11148                                         target = ip + 4 + (gint)(read32 (ip));
11149                                         ip += 4;
11150                                         break;
11151                                 default:
11152                                         g_assert_not_reached ();
11153                                 }
11154
11155                                 /* 
11156                                  * We need to link both bblocks, since it is needed for handling stack
11157                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
11158                                  * Branching to only one of them would lead to inconsistencies, so
11159                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
11160                                  */
11161                                 GET_BBLOCK (cfg, true_bb, target);
11162                                 GET_BBLOCK (cfg, false_bb, ip);
11163
11164                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
11165                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
11166
11167                                 if (sp != stack_start) {
11168                                         handle_stack_args (cfg, stack_start, sp - stack_start);
11169                                         sp = stack_start;
11170                                         CHECK_UNVERIFIABLE (cfg);
11171                                 }
11172
11173                                 if (COMPILE_LLVM (cfg)) {
11174                                         dreg = alloc_ireg (cfg);
11175                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
11176                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
11177
11178                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
11179                                 } else {
11180                                         /* The JIT can't eliminate the iconst+compare */
11181                                         MONO_INST_NEW (cfg, ins, OP_BR);
11182                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
11183                                         MONO_ADD_INS (cfg->cbb, ins);
11184                                 }
11185
11186                                 start_new_bblock = 1;
11187                                 break;
11188                         }
11189
11190                         *sp++ = handle_box (cfg, val, klass, context_used);
11191
11192                         CHECK_CFG_EXCEPTION;
11193                         ip += 5;
11194                         inline_costs += 1;
11195                         break;
11196                 }
11197                 case CEE_UNBOX: {
11198                         CHECK_STACK (1);
11199                         --sp;
11200                         CHECK_OPSIZE (5);
11201                         token = read32 (ip + 1);
11202                         klass = mini_get_class (method, token, generic_context);
11203                         CHECK_TYPELOAD (klass);
11204
11205                         mono_save_token_info (cfg, image, token, klass);
11206
11207                         context_used = mini_class_check_context_used (cfg, klass);
11208
11209                         if (mono_class_is_nullable (klass)) {
11210                                 MonoInst *val;
11211
11212                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
11213                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
11214
11215                                 *sp++= ins;
11216                         } else {
11217                                 ins = handle_unbox (cfg, klass, sp, context_used);
11218                                 *sp++ = ins;
11219                         }
11220                         ip += 5;
11221                         inline_costs += 2;
11222                         break;
11223                 }
11224                 case CEE_LDFLD:
11225                 case CEE_LDFLDA:
11226                 case CEE_STFLD:
11227                 case CEE_LDSFLD:
11228                 case CEE_LDSFLDA:
11229                 case CEE_STSFLD: {
11230                         MonoClassField *field;
11231 #ifndef DISABLE_REMOTING
11232                         int costs;
11233 #endif
11234                         guint foffset;
11235                         gboolean is_instance;
11236                         int op;
11237                         gpointer addr = NULL;
11238                         gboolean is_special_static;
11239                         MonoType *ftype;
11240                         MonoInst *store_val = NULL;
11241                         MonoInst *thread_ins;
11242
11243                         op = *ip;
11244                         is_instance = (op == CEE_LDFLD || op == CEE_LDFLDA || op == CEE_STFLD);
11245                         if (is_instance) {
11246                                 if (op == CEE_STFLD) {
11247                                         CHECK_STACK (2);
11248                                         sp -= 2;
11249                                         store_val = sp [1];
11250                                 } else {
11251                                         CHECK_STACK (1);
11252                                         --sp;
11253                                 }
11254                                 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
11255                                         UNVERIFIED;
11256                                 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
11257                                         UNVERIFIED;
11258                         } else {
11259                                 if (op == CEE_STSFLD) {
11260                                         CHECK_STACK (1);
11261                                         sp--;
11262                                         store_val = sp [0];
11263                                 }
11264                         }
11265
11266                         CHECK_OPSIZE (5);
11267                         token = read32 (ip + 1);
11268                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
11269                                 field = (MonoClassField *)mono_method_get_wrapper_data (method, token);
11270                                 klass = field->parent;
11271                         }
11272                         else {
11273                                 field = mono_field_from_token_checked (image, token, &klass, generic_context, &cfg->error);
11274                                 CHECK_CFG_ERROR;
11275                         }
11276                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
11277                                 FIELD_ACCESS_FAILURE (method, field);
11278                         mono_class_init (klass);
11279
11280                         /* if the class is Critical then transparent code cannot access it's fields */
11281                         if (!is_instance && mono_security_core_clr_enabled ())
11282                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
11283
11284                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
11285                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
11286                         if (mono_security_core_clr_enabled ())
11287                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
11288                         */
11289
11290                         ftype = mono_field_get_type (field);
11291
11292                         /*
11293                          * LDFLD etc. is usable on static fields as well, so convert those cases to
11294                          * the static case.
11295                          */
11296                         if (is_instance && ftype->attrs & FIELD_ATTRIBUTE_STATIC) {
11297                                 switch (op) {
11298                                 case CEE_LDFLD:
11299                                         op = CEE_LDSFLD;
11300                                         break;
11301                                 case CEE_STFLD:
11302                                         op = CEE_STSFLD;
11303                                         break;
11304                                 case CEE_LDFLDA:
11305                                         op = CEE_LDSFLDA;
11306                                         break;
11307                                 default:
11308                                         g_assert_not_reached ();
11309                                 }
11310                                 is_instance = FALSE;
11311                         }
11312
11313                         context_used = mini_class_check_context_used (cfg, klass);
11314
11315                         /* INSTANCE CASE */
11316
11317                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
11318                         if (op == CEE_STFLD) {
11319                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
11320                                         UNVERIFIED;
11321 #ifndef DISABLE_REMOTING
11322                                 if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
11323                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
11324                                         MonoInst *iargs [5];
11325
11326                                         GSHAREDVT_FAILURE (op);
11327
11328                                         iargs [0] = sp [0];
11329                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11330                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
11331                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
11332                                                     field->offset);
11333                                         iargs [4] = sp [1];
11334
11335                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
11336                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
11337                                                                                            iargs, ip, cfg->real_offset, TRUE);
11338                                                 CHECK_CFG_EXCEPTION;
11339                                                 g_assert (costs > 0);
11340                                                       
11341                                                 cfg->real_offset += 5;
11342
11343                                                 inline_costs += costs;
11344                                         } else {
11345                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
11346                                         }
11347                                 } else
11348 #endif
11349                                 {
11350                                         MonoInst *store;
11351
11352                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
11353
11354                                         if (mini_is_gsharedvt_klass (klass)) {
11355                                                 MonoInst *offset_ins;
11356
11357                                                 context_used = mini_class_check_context_used (cfg, klass);
11358
11359                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11360                                                 /* The value is offset by 1 */
11361                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11362                                                 dreg = alloc_ireg_mp (cfg);
11363                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11364                                                 /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
11365                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
11366                                         } else {
11367                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
11368                                         }
11369                                         if (sp [0]->opcode != OP_LDADDR)
11370                                                 store->flags |= MONO_INST_FAULT;
11371
11372                                 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)) {
11373                                         /* insert call to write barrier */
11374                                         MonoInst *ptr;
11375                                         int dreg;
11376
11377                                         dreg = alloc_ireg_mp (cfg);
11378                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
11379                                         emit_write_barrier (cfg, ptr, sp [1]);
11380                                 }
11381
11382                                         store->flags |= ins_flag;
11383                                 }
11384                                 ins_flag = 0;
11385                                 ip += 5;
11386                                 break;
11387                         }
11388
11389 #ifndef DISABLE_REMOTING
11390                         if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
11391                                 MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
11392                                 MonoInst *iargs [4];
11393
11394                                 GSHAREDVT_FAILURE (op);
11395
11396                                 iargs [0] = sp [0];
11397                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11398                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
11399                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
11400                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
11401                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
11402                                                                                    iargs, ip, cfg->real_offset, TRUE);
11403                                         CHECK_CFG_EXCEPTION;
11404                                         g_assert (costs > 0);
11405                                                       
11406                                         cfg->real_offset += 5;
11407
11408                                         *sp++ = iargs [0];
11409
11410                                         inline_costs += costs;
11411                                 } else {
11412                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
11413                                         *sp++ = ins;
11414                                 }
11415                         } else 
11416 #endif
11417                         if (is_instance) {
11418                                 if (sp [0]->type == STACK_VTYPE) {
11419                                         MonoInst *var;
11420
11421                                         /* Have to compute the address of the variable */
11422
11423                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
11424                                         if (!var)
11425                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
11426                                         else
11427                                                 g_assert (var->klass == klass);
11428                                         
11429                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
11430                                         sp [0] = ins;
11431                                 }
11432
11433                                 if (op == CEE_LDFLDA) {
11434                                         if (sp [0]->type == STACK_OBJ) {
11435                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
11436                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
11437                                         }
11438
11439                                         dreg = alloc_ireg_mp (cfg);
11440
11441                                         if (mini_is_gsharedvt_klass (klass)) {
11442                                                 MonoInst *offset_ins;
11443
11444                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11445                                                 /* The value is offset by 1 */
11446                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11447                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11448                                         } else {
11449                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
11450                                         }
11451                                         ins->klass = mono_class_from_mono_type (field->type);
11452                                         ins->type = STACK_MP;
11453                                         *sp++ = ins;
11454                                 } else {
11455                                         MonoInst *load;
11456
11457                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
11458
11459                                         if (mini_is_gsharedvt_klass (klass)) {
11460                                                 MonoInst *offset_ins;
11461
11462                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11463                                                 /* The value is offset by 1 */
11464                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11465                                                 dreg = alloc_ireg_mp (cfg);
11466                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11467                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
11468                                         } else {
11469                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
11470                                         }
11471                                         load->flags |= ins_flag;
11472                                         if (sp [0]->opcode != OP_LDADDR)
11473                                                 load->flags |= MONO_INST_FAULT;
11474                                         *sp++ = load;
11475                                 }
11476                         }
11477
11478                         if (is_instance) {
11479                                 ins_flag = 0;
11480                                 ip += 5;
11481                                 break;
11482                         }
11483
11484                         /* STATIC CASE */
11485                         context_used = mini_class_check_context_used (cfg, klass);
11486
11487                         if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL)
11488                                 UNVERIFIED;
11489
11490                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
11491                          * to be called here.
11492                          */
11493                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
11494                                 mono_class_vtable (cfg->domain, klass);
11495                                 CHECK_TYPELOAD (klass);
11496                         }
11497                         mono_domain_lock (cfg->domain);
11498                         if (cfg->domain->special_static_fields)
11499                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
11500                         mono_domain_unlock (cfg->domain);
11501
11502                         is_special_static = mono_class_field_is_special_static (field);
11503
11504                         if (is_special_static && ((gsize)addr & 0x80000000) == 0)
11505                                 thread_ins = mono_get_thread_intrinsic (cfg);
11506                         else
11507                                 thread_ins = NULL;
11508
11509                         /* Generate IR to compute the field address */
11510                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && thread_ins && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
11511                                 /*
11512                                  * Fast access to TLS data
11513                                  * Inline version of get_thread_static_data () in
11514                                  * threads.c.
11515                                  */
11516                                 guint32 offset;
11517                                 int idx, static_data_reg, array_reg, dreg;
11518
11519                                 GSHAREDVT_FAILURE (op);
11520
11521                                 MONO_ADD_INS (cfg->cbb, thread_ins);
11522                                 static_data_reg = alloc_ireg (cfg);
11523                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
11524
11525                                 if (cfg->compile_aot) {
11526                                         int offset_reg, offset2_reg, idx_reg;
11527
11528                                         /* For TLS variables, this will return the TLS offset */
11529                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
11530                                         offset_reg = ins->dreg;
11531                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
11532                                         idx_reg = alloc_ireg (cfg);
11533                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, idx_reg, offset_reg, 0x3f);
11534                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
11535                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
11536                                         array_reg = alloc_ireg (cfg);
11537                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
11538                                         offset2_reg = alloc_ireg (cfg);
11539                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, offset2_reg, offset_reg, 6);
11540                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset2_reg, 0x1ffffff);
11541                                         dreg = alloc_ireg (cfg);
11542                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
11543                                 } else {
11544                                         offset = (gsize)addr & 0x7fffffff;
11545                                         idx = offset & 0x3f;
11546
11547                                         array_reg = alloc_ireg (cfg);
11548                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
11549                                         dreg = alloc_ireg (cfg);
11550                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, ((offset >> 6) & 0x1ffffff));
11551                                 }
11552                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
11553                                         (cfg->compile_aot && is_special_static) ||
11554                                         (context_used && is_special_static)) {
11555                                 MonoInst *iargs [2];
11556
11557                                 g_assert (field->parent);
11558                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11559                                 if (context_used) {
11560                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
11561                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
11562                                 } else {
11563                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11564                                 }
11565                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11566                         } else if (context_used) {
11567                                 MonoInst *static_data;
11568
11569                                 /*
11570                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
11571                                         method->klass->name_space, method->klass->name, method->name,
11572                                         depth, field->offset);
11573                                 */
11574
11575                                 if (mono_class_needs_cctor_run (klass, method))
11576                                         emit_class_init (cfg, klass);
11577
11578                                 /*
11579                                  * The pointer we're computing here is
11580                                  *
11581                                  *   super_info.static_data + field->offset
11582                                  */
11583                                 static_data = emit_get_rgctx_klass (cfg, context_used,
11584                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
11585
11586                                 if (mini_is_gsharedvt_klass (klass)) {
11587                                         MonoInst *offset_ins;
11588
11589                                         offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11590                                         /* The value is offset by 1 */
11591                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11592                                         dreg = alloc_ireg_mp (cfg);
11593                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
11594                                 } else if (field->offset == 0) {
11595                                         ins = static_data;
11596                                 } else {
11597                                         int addr_reg = mono_alloc_preg (cfg);
11598                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
11599                                 }
11600                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
11601                                 MonoInst *iargs [2];
11602
11603                                 g_assert (field->parent);
11604                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11605                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11606                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11607                         } else {
11608                                 MonoVTable *vtable = NULL;
11609
11610                                 if (!cfg->compile_aot)
11611                                         vtable = mono_class_vtable (cfg->domain, klass);
11612                                 CHECK_TYPELOAD (klass);
11613
11614                                 if (!addr) {
11615                                         if (mini_field_access_needs_cctor_run (cfg, method, klass, vtable)) {
11616                                                 if (!(g_slist_find (class_inits, klass))) {
11617                                                         emit_class_init (cfg, klass);
11618                                                         if (cfg->verbose_level > 2)
11619                                                                 printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
11620                                                         class_inits = g_slist_prepend (class_inits, klass);
11621                                                 }
11622                                         } else {
11623                                                 if (cfg->run_cctors) {
11624                                                         MonoException *ex;
11625                                                         /* This makes so that inline cannot trigger */
11626                                                         /* .cctors: too many apps depend on them */
11627                                                         /* running with a specific order... */
11628                                                         g_assert (vtable);
11629                                                         if (! vtable->initialized)
11630                                                                 INLINE_FAILURE ("class init");
11631                                                         ex = mono_runtime_class_init_full (vtable, FALSE);
11632                                                         if (ex) {
11633                                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
11634                                                                 mono_error_set_exception_instance (&cfg->error, ex);
11635                                                                 g_assert_not_reached ();
11636                                                                 goto exception_exit;
11637                                                         }
11638                                                 }
11639                                         }
11640                                         if (cfg->compile_aot)
11641                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
11642                                         else {
11643                                                 g_assert (vtable);
11644                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11645                                                 g_assert (addr);
11646                                                 EMIT_NEW_PCONST (cfg, ins, addr);
11647                                         }
11648                                 } else {
11649                                         MonoInst *iargs [1];
11650                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
11651                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
11652                                 }
11653                         }
11654
11655                         /* Generate IR to do the actual load/store operation */
11656
11657                         if ((op == CEE_STFLD || op == CEE_STSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11658                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11659                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11660                         }
11661
11662                         if (op == CEE_LDSFLDA) {
11663                                 ins->klass = mono_class_from_mono_type (ftype);
11664                                 ins->type = STACK_PTR;
11665                                 *sp++ = ins;
11666                         } else if (op == CEE_STSFLD) {
11667                                 MonoInst *store;
11668
11669                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
11670                                 store->flags |= ins_flag;
11671                         } else {
11672                                 gboolean is_const = FALSE;
11673                                 MonoVTable *vtable = NULL;
11674                                 gpointer addr = NULL;
11675
11676                                 if (!context_used) {
11677                                         vtable = mono_class_vtable (cfg->domain, klass);
11678                                         CHECK_TYPELOAD (klass);
11679                                 }
11680                                 if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) ||
11681                                                 (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) {
11682                                         int ro_type = ftype->type;
11683                                         if (!addr)
11684                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11685                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
11686                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
11687                                         }
11688
11689                                         GSHAREDVT_FAILURE (op);
11690
11691                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
11692                                         is_const = TRUE;
11693                                         switch (ro_type) {
11694                                         case MONO_TYPE_BOOLEAN:
11695                                         case MONO_TYPE_U1:
11696                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
11697                                                 sp++;
11698                                                 break;
11699                                         case MONO_TYPE_I1:
11700                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
11701                                                 sp++;
11702                                                 break;                                          
11703                                         case MONO_TYPE_CHAR:
11704                                         case MONO_TYPE_U2:
11705                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
11706                                                 sp++;
11707                                                 break;
11708                                         case MONO_TYPE_I2:
11709                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
11710                                                 sp++;
11711                                                 break;
11712                                                 break;
11713                                         case MONO_TYPE_I4:
11714                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
11715                                                 sp++;
11716                                                 break;                                          
11717                                         case MONO_TYPE_U4:
11718                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
11719                                                 sp++;
11720                                                 break;
11721                                         case MONO_TYPE_I:
11722                                         case MONO_TYPE_U:
11723                                         case MONO_TYPE_PTR:
11724                                         case MONO_TYPE_FNPTR:
11725                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11726                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
11727                                                 sp++;
11728                                                 break;
11729                                         case MONO_TYPE_STRING:
11730                                         case MONO_TYPE_OBJECT:
11731                                         case MONO_TYPE_CLASS:
11732                                         case MONO_TYPE_SZARRAY:
11733                                         case MONO_TYPE_ARRAY:
11734                                                 if (!mono_gc_is_moving ()) {
11735                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11736                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
11737                                                         sp++;
11738                                                 } else {
11739                                                         is_const = FALSE;
11740                                                 }
11741                                                 break;
11742                                         case MONO_TYPE_I8:
11743                                         case MONO_TYPE_U8:
11744                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
11745                                                 sp++;
11746                                                 break;
11747                                         case MONO_TYPE_R4:
11748                                         case MONO_TYPE_R8:
11749                                         case MONO_TYPE_VALUETYPE:
11750                                         default:
11751                                                 is_const = FALSE;
11752                                                 break;
11753                                         }
11754                                 }
11755
11756                                 if (!is_const) {
11757                                         MonoInst *load;
11758
11759                                         CHECK_STACK_OVF (1);
11760
11761                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
11762                                         load->flags |= ins_flag;
11763                                         ins_flag = 0;
11764                                         *sp++ = load;
11765                                 }
11766                         }
11767
11768                         if ((op == CEE_LDFLD || op == CEE_LDSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11769                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
11770                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
11771                         }
11772
11773                         ins_flag = 0;
11774                         ip += 5;
11775                         break;
11776                 }
11777                 case CEE_STOBJ:
11778                         CHECK_STACK (2);
11779                         sp -= 2;
11780                         CHECK_OPSIZE (5);
11781                         token = read32 (ip + 1);
11782                         klass = mini_get_class (method, token, generic_context);
11783                         CHECK_TYPELOAD (klass);
11784                         if (ins_flag & MONO_INST_VOLATILE) {
11785                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11786                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11787                         }
11788                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
11789                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
11790                         ins->flags |= ins_flag;
11791                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
11792                                         generic_class_is_reference_type (cfg, klass)) {
11793                                 /* insert call to write barrier */
11794                                 emit_write_barrier (cfg, sp [0], sp [1]);
11795                         }
11796                         ins_flag = 0;
11797                         ip += 5;
11798                         inline_costs += 1;
11799                         break;
11800
11801                         /*
11802                          * Array opcodes
11803                          */
11804                 case CEE_NEWARR: {
11805                         MonoInst *len_ins;
11806                         const char *data_ptr;
11807                         int data_size = 0;
11808                         guint32 field_token;
11809
11810                         CHECK_STACK (1);
11811                         --sp;
11812
11813                         CHECK_OPSIZE (5);
11814                         token = read32 (ip + 1);
11815
11816                         klass = mini_get_class (method, token, generic_context);
11817                         CHECK_TYPELOAD (klass);
11818
11819                         context_used = mini_class_check_context_used (cfg, klass);
11820
11821                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
11822                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_OVF_U4);
11823                                 ins->sreg1 = sp [0]->dreg;
11824                                 ins->type = STACK_I4;
11825                                 ins->dreg = alloc_ireg (cfg);
11826                                 MONO_ADD_INS (cfg->cbb, ins);
11827                                 *sp = mono_decompose_opcode (cfg, ins);
11828                         }
11829
11830                         if (context_used) {
11831                                 MonoInst *args [3];
11832                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11833                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
11834
11835                                 /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
11836
11837                                 /* vtable */
11838                                 args [0] = emit_get_rgctx_klass (cfg, context_used,
11839                                         array_class, MONO_RGCTX_INFO_VTABLE);
11840                                 /* array len */
11841                                 args [1] = sp [0];
11842
11843                                 if (managed_alloc)
11844                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
11845                                 else
11846                                         ins = mono_emit_jit_icall (cfg, ves_icall_array_new_specific, args);
11847                         } else {
11848                                 if (cfg->opt & MONO_OPT_SHARED) {
11849                                         /* Decompose now to avoid problems with references to the domainvar */
11850                                         MonoInst *iargs [3];
11851
11852                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11853                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11854                                         iargs [2] = sp [0];
11855
11856                                         ins = mono_emit_jit_icall (cfg, mono_array_new, iargs);
11857                                 } else {
11858                                         /* Decompose later since it is needed by abcrem */
11859                                         MonoClass *array_type = mono_array_class_get (klass, 1);
11860                                         mono_class_vtable (cfg->domain, array_type);
11861                                         CHECK_TYPELOAD (array_type);
11862
11863                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
11864                                         ins->dreg = alloc_ireg_ref (cfg);
11865                                         ins->sreg1 = sp [0]->dreg;
11866                                         ins->inst_newa_class = klass;
11867                                         ins->type = STACK_OBJ;
11868                                         ins->klass = array_type;
11869                                         MONO_ADD_INS (cfg->cbb, ins);
11870                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11871                                         cfg->cbb->has_array_access = TRUE;
11872
11873                                         /* Needed so mono_emit_load_get_addr () gets called */
11874                                         mono_get_got_var (cfg);
11875                                 }
11876                         }
11877
11878                         len_ins = sp [0];
11879                         ip += 5;
11880                         *sp++ = ins;
11881                         inline_costs += 1;
11882
11883                         /* 
11884                          * we inline/optimize the initialization sequence if possible.
11885                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
11886                          * for small sizes open code the memcpy
11887                          * ensure the rva field is big enough
11888                          */
11889                         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))) {
11890                                 MonoMethod *memcpy_method = get_memcpy_method ();
11891                                 MonoInst *iargs [3];
11892                                 int add_reg = alloc_ireg_mp (cfg);
11893
11894                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, MONO_STRUCT_OFFSET (MonoArray, vector));
11895                                 if (cfg->compile_aot) {
11896                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
11897                                 } else {
11898                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
11899                                 }
11900                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
11901                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
11902                                 ip += 11;
11903                         }
11904
11905                         break;
11906                 }
11907                 case CEE_LDLEN:
11908                         CHECK_STACK (1);
11909                         --sp;
11910                         if (sp [0]->type != STACK_OBJ)
11911                                 UNVERIFIED;
11912
11913                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
11914                         ins->dreg = alloc_preg (cfg);
11915                         ins->sreg1 = sp [0]->dreg;
11916                         ins->type = STACK_I4;
11917                         /* This flag will be inherited by the decomposition */
11918                         ins->flags |= MONO_INST_FAULT;
11919                         MONO_ADD_INS (cfg->cbb, ins);
11920                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11921                         cfg->cbb->has_array_access = TRUE;
11922                         ip ++;
11923                         *sp++ = ins;
11924                         break;
11925                 case CEE_LDELEMA:
11926                         CHECK_STACK (2);
11927                         sp -= 2;
11928                         CHECK_OPSIZE (5);
11929                         if (sp [0]->type != STACK_OBJ)
11930                                 UNVERIFIED;
11931
11932                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11933
11934                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11935                         CHECK_TYPELOAD (klass);
11936                         /* we need to make sure that this array is exactly the type it needs
11937                          * to be for correctness. the wrappers are lax with their usage
11938                          * so we need to ignore them here
11939                          */
11940                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
11941                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11942                                 mini_emit_check_array_type (cfg, sp [0], array_class);
11943                                 CHECK_TYPELOAD (array_class);
11944                         }
11945
11946                         readonly = FALSE;
11947                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11948                         *sp++ = ins;
11949                         ip += 5;
11950                         break;
11951                 case CEE_LDELEM:
11952                 case CEE_LDELEM_I1:
11953                 case CEE_LDELEM_U1:
11954                 case CEE_LDELEM_I2:
11955                 case CEE_LDELEM_U2:
11956                 case CEE_LDELEM_I4:
11957                 case CEE_LDELEM_U4:
11958                 case CEE_LDELEM_I8:
11959                 case CEE_LDELEM_I:
11960                 case CEE_LDELEM_R4:
11961                 case CEE_LDELEM_R8:
11962                 case CEE_LDELEM_REF: {
11963                         MonoInst *addr;
11964
11965                         CHECK_STACK (2);
11966                         sp -= 2;
11967
11968                         if (*ip == CEE_LDELEM) {
11969                                 CHECK_OPSIZE (5);
11970                                 token = read32 (ip + 1);
11971                                 klass = mini_get_class (method, token, generic_context);
11972                                 CHECK_TYPELOAD (klass);
11973                                 mono_class_init (klass);
11974                         }
11975                         else
11976                                 klass = array_access_to_klass (*ip);
11977
11978                         if (sp [0]->type != STACK_OBJ)
11979                                 UNVERIFIED;
11980
11981                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11982
11983                         if (mini_is_gsharedvt_variable_klass (klass)) {
11984                                 // FIXME-VT: OP_ICONST optimization
11985                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11986                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11987                                 ins->opcode = OP_LOADV_MEMBASE;
11988                         } else if (sp [1]->opcode == OP_ICONST) {
11989                                 int array_reg = sp [0]->dreg;
11990                                 int index_reg = sp [1]->dreg;
11991                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
11992
11993                                 if (SIZEOF_REGISTER == 8 && COMPILE_LLVM (cfg))
11994                                         MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, index_reg);
11995
11996                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
11997                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
11998                         } else {
11999                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
12000                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
12001                         }
12002                         *sp++ = ins;
12003                         if (*ip == CEE_LDELEM)
12004                                 ip += 5;
12005                         else
12006                                 ++ip;
12007                         break;
12008                 }
12009                 case CEE_STELEM_I:
12010                 case CEE_STELEM_I1:
12011                 case CEE_STELEM_I2:
12012                 case CEE_STELEM_I4:
12013                 case CEE_STELEM_I8:
12014                 case CEE_STELEM_R4:
12015                 case CEE_STELEM_R8:
12016                 case CEE_STELEM_REF:
12017                 case CEE_STELEM: {
12018                         CHECK_STACK (3);
12019                         sp -= 3;
12020
12021                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
12022
12023                         if (*ip == CEE_STELEM) {
12024                                 CHECK_OPSIZE (5);
12025                                 token = read32 (ip + 1);
12026                                 klass = mini_get_class (method, token, generic_context);
12027                                 CHECK_TYPELOAD (klass);
12028                                 mono_class_init (klass);
12029                         }
12030                         else
12031                                 klass = array_access_to_klass (*ip);
12032
12033                         if (sp [0]->type != STACK_OBJ)
12034                                 UNVERIFIED;
12035
12036                         emit_array_store (cfg, klass, sp, TRUE);
12037
12038                         if (*ip == CEE_STELEM)
12039                                 ip += 5;
12040                         else
12041                                 ++ip;
12042                         inline_costs += 1;
12043                         break;
12044                 }
12045                 case CEE_CKFINITE: {
12046                         CHECK_STACK (1);
12047                         --sp;
12048
12049                         if (cfg->llvm_only) {
12050                                 MonoInst *iargs [1];
12051
12052                                 iargs [0] = sp [0];
12053                                 *sp++ = mono_emit_jit_icall (cfg, mono_ckfinite, iargs);
12054                         } else  {
12055                                 MONO_INST_NEW (cfg, ins, OP_CKFINITE);
12056                                 ins->sreg1 = sp [0]->dreg;
12057                                 ins->dreg = alloc_freg (cfg);
12058                                 ins->type = STACK_R8;
12059                                 MONO_ADD_INS (cfg->cbb, ins);
12060
12061                                 *sp++ = mono_decompose_opcode (cfg, ins);
12062                         }
12063
12064                         ++ip;
12065                         break;
12066                 }
12067                 case CEE_REFANYVAL: {
12068                         MonoInst *src_var, *src;
12069
12070                         int klass_reg = alloc_preg (cfg);
12071                         int dreg = alloc_preg (cfg);
12072
12073                         GSHAREDVT_FAILURE (*ip);
12074
12075                         CHECK_STACK (1);
12076                         MONO_INST_NEW (cfg, ins, *ip);
12077                         --sp;
12078                         CHECK_OPSIZE (5);
12079                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
12080                         CHECK_TYPELOAD (klass);
12081
12082                         context_used = mini_class_check_context_used (cfg, klass);
12083
12084                         // FIXME:
12085                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12086                         if (!src_var)
12087                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
12088                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
12089                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass));
12090
12091                         if (context_used) {
12092                                 MonoInst *klass_ins;
12093
12094                                 klass_ins = emit_get_rgctx_klass (cfg, context_used,
12095                                                 klass, MONO_RGCTX_INFO_KLASS);
12096
12097                                 // FIXME:
12098                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
12099                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
12100                         } else {
12101                                 mini_emit_class_check (cfg, klass_reg, klass);
12102                         }
12103                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value));
12104                         ins->type = STACK_MP;
12105                         ins->klass = klass;
12106                         *sp++ = ins;
12107                         ip += 5;
12108                         break;
12109                 }
12110                 case CEE_MKREFANY: {
12111                         MonoInst *loc, *addr;
12112
12113                         GSHAREDVT_FAILURE (*ip);
12114
12115                         CHECK_STACK (1);
12116                         MONO_INST_NEW (cfg, ins, *ip);
12117                         --sp;
12118                         CHECK_OPSIZE (5);
12119                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
12120                         CHECK_TYPELOAD (klass);
12121
12122                         context_used = mini_class_check_context_used (cfg, klass);
12123
12124                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
12125                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
12126
12127                         if (context_used) {
12128                                 MonoInst *const_ins;
12129                                 int type_reg = alloc_preg (cfg);
12130
12131                                 const_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
12132                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
12133                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
12134                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
12135                         } else if (cfg->compile_aot) {
12136                                 int const_reg = alloc_preg (cfg);
12137                                 int type_reg = alloc_preg (cfg);
12138
12139                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
12140                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
12141                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
12142                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
12143                         } else {
12144                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), &klass->byval_arg);
12145                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), klass);
12146                         }
12147                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
12148
12149                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
12150                         ins->type = STACK_VTYPE;
12151                         ins->klass = mono_defaults.typed_reference_class;
12152                         *sp++ = ins;
12153                         ip += 5;
12154                         break;
12155                 }
12156                 case CEE_LDTOKEN: {
12157                         gpointer handle;
12158                         MonoClass *handle_class;
12159
12160                         CHECK_STACK_OVF (1);
12161
12162                         CHECK_OPSIZE (5);
12163                         n = read32 (ip + 1);
12164
12165                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
12166                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
12167                                 handle = mono_method_get_wrapper_data (method, n);
12168                                 handle_class = (MonoClass *)mono_method_get_wrapper_data (method, n + 1);
12169                                 if (handle_class == mono_defaults.typehandle_class)
12170                                         handle = &((MonoClass*)handle)->byval_arg;
12171                         }
12172                         else {
12173                                 handle = mono_ldtoken_checked (image, n, &handle_class, generic_context, &cfg->error);
12174                                 CHECK_CFG_ERROR;
12175                         }
12176                         if (!handle)
12177                                 LOAD_ERROR;
12178                         mono_class_init (handle_class);
12179                         if (cfg->gshared) {
12180                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
12181                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
12182                                         /* This case handles ldtoken
12183                                            of an open type, like for
12184                                            typeof(Gen<>). */
12185                                         context_used = 0;
12186                                 } else if (handle_class == mono_defaults.typehandle_class) {
12187                                         context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type ((MonoType *)handle));
12188                                 } else if (handle_class == mono_defaults.fieldhandle_class)
12189                                         context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
12190                                 else if (handle_class == mono_defaults.methodhandle_class)
12191                                         context_used = mini_method_check_context_used (cfg, (MonoMethod *)handle);
12192                                 else
12193                                         g_assert_not_reached ();
12194                         }
12195
12196                         if ((cfg->opt & MONO_OPT_SHARED) &&
12197                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
12198                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
12199                                 MonoInst *addr, *vtvar, *iargs [3];
12200                                 int method_context_used;
12201
12202                                 method_context_used = mini_method_check_context_used (cfg, method);
12203
12204                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
12205
12206                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
12207                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
12208                                 if (method_context_used) {
12209                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
12210                                                 method, MONO_RGCTX_INFO_METHOD);
12211                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
12212                                 } else {
12213                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
12214                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
12215                                 }
12216                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12217
12218                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
12219
12220                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12221                         } else {
12222                                 if ((ip + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 5) && 
12223                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
12224                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
12225                                         (cmethod->klass == mono_defaults.systemtype_class) &&
12226                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
12227                                         MonoClass *tclass = mono_class_from_mono_type ((MonoType *)handle);
12228
12229                                         mono_class_init (tclass);
12230                                         if (context_used) {
12231                                                 ins = emit_get_rgctx_klass (cfg, context_used,
12232                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
12233                                         } else if (cfg->compile_aot) {
12234                                                 if (method->wrapper_type) {
12235                                                         mono_error_init (&error); //got to do it since there are multiple conditionals below
12236                                                         if (mono_class_get_checked (tclass->image, tclass->type_token, &error) == tclass && !generic_context) {
12237                                                                 /* Special case for static synchronized wrappers */
12238                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
12239                                                         } else {
12240                                                                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
12241                                                                 /* FIXME: n is not a normal token */
12242                                                                 DISABLE_AOT (cfg);
12243                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12244                                                         }
12245                                                 } else {
12246                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
12247                                                 }
12248                                         } else {
12249                                                 MonoError error;
12250                                                 MonoReflectionType *rt = mono_type_get_object_checked (cfg->domain, (MonoType *)handle, &error);
12251                                                 mono_error_raise_exception (&error); /* FIXME don't raise here */
12252
12253                                                 EMIT_NEW_PCONST (cfg, ins, rt);
12254                                         }
12255                                         ins->type = STACK_OBJ;
12256                                         ins->klass = cmethod->klass;
12257                                         ip += 5;
12258                                 } else {
12259                                         MonoInst *addr, *vtvar;
12260
12261                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
12262
12263                                         if (context_used) {
12264                                                 if (handle_class == mono_defaults.typehandle_class) {
12265                                                         ins = emit_get_rgctx_klass (cfg, context_used,
12266                                                                         mono_class_from_mono_type ((MonoType *)handle),
12267                                                                         MONO_RGCTX_INFO_TYPE);
12268                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
12269                                                         ins = emit_get_rgctx_method (cfg, context_used,
12270                                                                         (MonoMethod *)handle, MONO_RGCTX_INFO_METHOD);
12271                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
12272                                                         ins = emit_get_rgctx_field (cfg, context_used,
12273                                                                         (MonoClassField *)handle, MONO_RGCTX_INFO_CLASS_FIELD);
12274                                                 } else {
12275                                                         g_assert_not_reached ();
12276                                                 }
12277                                         } else if (cfg->compile_aot) {
12278                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n, generic_context);
12279                                         } else {
12280                                                 EMIT_NEW_PCONST (cfg, ins, handle);
12281                                         }
12282                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12283                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
12284                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12285                                 }
12286                         }
12287
12288                         *sp++ = ins;
12289                         ip += 5;
12290                         break;
12291                 }
12292                 case CEE_THROW:
12293                         CHECK_STACK (1);
12294                         MONO_INST_NEW (cfg, ins, OP_THROW);
12295                         --sp;
12296                         ins->sreg1 = sp [0]->dreg;
12297                         ip++;
12298                         cfg->cbb->out_of_line = TRUE;
12299                         MONO_ADD_INS (cfg->cbb, ins);
12300                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
12301                         MONO_ADD_INS (cfg->cbb, ins);
12302                         sp = stack_start;
12303                         
12304                         link_bblock (cfg, cfg->cbb, end_bblock);
12305                         start_new_bblock = 1;
12306                         /* This can complicate code generation for llvm since the return value might not be defined */
12307                         if (COMPILE_LLVM (cfg))
12308                                 INLINE_FAILURE ("throw");
12309                         break;
12310                 case CEE_ENDFINALLY:
12311                         /* mono_save_seq_point_info () depends on this */
12312                         if (sp != stack_start)
12313                                 emit_seq_point (cfg, method, ip, FALSE, FALSE);
12314                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
12315                         MONO_ADD_INS (cfg->cbb, ins);
12316                         ip++;
12317                         start_new_bblock = 1;
12318
12319                         /*
12320                          * Control will leave the method so empty the stack, otherwise
12321                          * the next basic block will start with a nonempty stack.
12322                          */
12323                         while (sp != stack_start) {
12324                                 sp--;
12325                         }
12326                         break;
12327                 case CEE_LEAVE:
12328                 case CEE_LEAVE_S: {
12329                         GList *handlers;
12330
12331                         if (*ip == CEE_LEAVE) {
12332                                 CHECK_OPSIZE (5);
12333                                 target = ip + 5 + (gint32)read32(ip + 1);
12334                         } else {
12335                                 CHECK_OPSIZE (2);
12336                                 target = ip + 2 + (signed char)(ip [1]);
12337                         }
12338
12339                         /* empty the stack */
12340                         while (sp != stack_start) {
12341                                 sp--;
12342                         }
12343
12344                         /* 
12345                          * If this leave statement is in a catch block, check for a
12346                          * pending exception, and rethrow it if necessary.
12347                          * We avoid doing this in runtime invoke wrappers, since those are called
12348                          * by native code which excepts the wrapper to catch all exceptions.
12349                          */
12350                         for (i = 0; i < header->num_clauses; ++i) {
12351                                 MonoExceptionClause *clause = &header->clauses [i];
12352
12353                                 /* 
12354                                  * Use <= in the final comparison to handle clauses with multiple
12355                                  * leave statements, like in bug #78024.
12356                                  * The ordering of the exception clauses guarantees that we find the
12357                                  * innermost clause.
12358                                  */
12359                                 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) {
12360                                         MonoInst *exc_ins;
12361                                         MonoBasicBlock *dont_throw;
12362
12363                                         /*
12364                                           MonoInst *load;
12365
12366                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
12367                                         */
12368
12369                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
12370
12371                                         NEW_BBLOCK (cfg, dont_throw);
12372
12373                                         /*
12374                                          * Currently, we always rethrow the abort exception, despite the 
12375                                          * fact that this is not correct. See thread6.cs for an example. 
12376                                          * But propagating the abort exception is more important than 
12377                                          * getting the sematics right.
12378                                          */
12379                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
12380                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
12381                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
12382
12383                                         MONO_START_BB (cfg, dont_throw);
12384                                 }
12385                         }
12386
12387 #ifdef ENABLE_LLVM
12388                         cfg->cbb->try_end = (intptr_t)(ip - header->code);
12389 #endif
12390
12391                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
12392                                 GList *tmp;
12393                                 MonoExceptionClause *clause;
12394
12395                                 for (tmp = handlers; tmp; tmp = tmp->next) {
12396                                         clause = (MonoExceptionClause *)tmp->data;
12397                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
12398                                         g_assert (tblock);
12399                                         link_bblock (cfg, cfg->cbb, tblock);
12400                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
12401                                         ins->inst_target_bb = tblock;
12402                                         ins->inst_eh_block = clause;
12403                                         MONO_ADD_INS (cfg->cbb, ins);
12404                                         cfg->cbb->has_call_handler = 1;
12405                                         if (COMPILE_LLVM (cfg)) {
12406                                                 MonoBasicBlock *target_bb;
12407
12408                                                 /* 
12409                                                  * Link the finally bblock with the target, since it will
12410                                                  * conceptually branch there.
12411                                                  */
12412                                                 GET_BBLOCK (cfg, tblock, cfg->cil_start + clause->handler_offset + clause->handler_len - 1);
12413                                                 GET_BBLOCK (cfg, target_bb, target);
12414                                                 link_bblock (cfg, tblock, target_bb);
12415                                         }
12416                                 }
12417                                 g_list_free (handlers);
12418                         } 
12419
12420                         MONO_INST_NEW (cfg, ins, OP_BR);
12421                         MONO_ADD_INS (cfg->cbb, ins);
12422                         GET_BBLOCK (cfg, tblock, target);
12423                         link_bblock (cfg, cfg->cbb, tblock);
12424                         ins->inst_target_bb = tblock;
12425
12426                         start_new_bblock = 1;
12427
12428                         if (*ip == CEE_LEAVE)
12429                                 ip += 5;
12430                         else
12431                                 ip += 2;
12432
12433                         break;
12434                 }
12435
12436                         /*
12437                          * Mono specific opcodes
12438                          */
12439                 case MONO_CUSTOM_PREFIX: {
12440
12441                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
12442
12443                         CHECK_OPSIZE (2);
12444                         switch (ip [1]) {
12445                         case CEE_MONO_ICALL: {
12446                                 gpointer func;
12447                                 MonoJitICallInfo *info;
12448
12449                                 token = read32 (ip + 2);
12450                                 func = mono_method_get_wrapper_data (method, token);
12451                                 info = mono_find_jit_icall_by_addr (func);
12452                                 if (!info)
12453                                         g_error ("Could not find icall address in wrapper %s", mono_method_full_name (method, 1));
12454                                 g_assert (info);
12455
12456                                 CHECK_STACK (info->sig->param_count);
12457                                 sp -= info->sig->param_count;
12458
12459                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
12460                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
12461                                         *sp++ = ins;
12462
12463                                 ip += 6;
12464                                 inline_costs += 10 * num_calls++;
12465
12466                                 break;
12467                         }
12468                         case CEE_MONO_LDPTR_CARD_TABLE:
12469                         case CEE_MONO_LDPTR_NURSERY_START:
12470                         case CEE_MONO_LDPTR_NURSERY_BITS:
12471                         case CEE_MONO_LDPTR_INT_REQ_FLAG: {
12472                                 CHECK_STACK_OVF (1);
12473
12474                                 switch (ip [1]) {
12475                                         case CEE_MONO_LDPTR_CARD_TABLE:
12476                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
12477                                                 break;
12478                                         case CEE_MONO_LDPTR_NURSERY_START:
12479                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_START, NULL);
12480                                                 break;
12481                                         case CEE_MONO_LDPTR_NURSERY_BITS:
12482                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_BITS, NULL);
12483                                                 break;
12484                                         case CEE_MONO_LDPTR_INT_REQ_FLAG:
12485                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
12486                                                 break;
12487                                 }
12488
12489                                 *sp++ = ins;
12490                                 ip += 2;
12491                                 inline_costs += 10 * num_calls++;
12492                                 break;
12493                         }
12494                         case CEE_MONO_LDPTR: {
12495                                 gpointer ptr;
12496
12497                                 CHECK_STACK_OVF (1);
12498                                 CHECK_OPSIZE (6);
12499                                 token = read32 (ip + 2);
12500
12501                                 ptr = mono_method_get_wrapper_data (method, token);
12502                                 EMIT_NEW_PCONST (cfg, ins, ptr);
12503                                 *sp++ = ins;
12504                                 ip += 6;
12505                                 inline_costs += 10 * num_calls++;
12506                                 /* Can't embed random pointers into AOT code */
12507                                 DISABLE_AOT (cfg);
12508                                 break;
12509                         }
12510                         case CEE_MONO_JIT_ICALL_ADDR: {
12511                                 MonoJitICallInfo *callinfo;
12512                                 gpointer ptr;
12513
12514                                 CHECK_STACK_OVF (1);
12515                                 CHECK_OPSIZE (6);
12516                                 token = read32 (ip + 2);
12517
12518                                 ptr = mono_method_get_wrapper_data (method, token);
12519                                 callinfo = mono_find_jit_icall_by_addr (ptr);
12520                                 g_assert (callinfo);
12521                                 EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
12522                                 *sp++ = ins;
12523                                 ip += 6;
12524                                 inline_costs += 10 * num_calls++;
12525                                 break;
12526                         }
12527                         case CEE_MONO_ICALL_ADDR: {
12528                                 MonoMethod *cmethod;
12529                                 gpointer ptr;
12530
12531                                 CHECK_STACK_OVF (1);
12532                                 CHECK_OPSIZE (6);
12533                                 token = read32 (ip + 2);
12534
12535                                 cmethod = (MonoMethod *)mono_method_get_wrapper_data (method, token);
12536
12537                                 if (cfg->compile_aot) {
12538                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
12539                                 } else {
12540                                         ptr = mono_lookup_internal_call (cmethod);
12541                                         g_assert (ptr);
12542                                         EMIT_NEW_PCONST (cfg, ins, ptr);
12543                                 }
12544                                 *sp++ = ins;
12545                                 ip += 6;
12546                                 break;
12547                         }
12548                         case CEE_MONO_VTADDR: {
12549                                 MonoInst *src_var, *src;
12550
12551                                 CHECK_STACK (1);
12552                                 --sp;
12553
12554                                 // FIXME:
12555                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12556                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
12557                                 *sp++ = src;
12558                                 ip += 2;
12559                                 break;
12560                         }
12561                         case CEE_MONO_NEWOBJ: {
12562                                 MonoInst *iargs [2];
12563
12564                                 CHECK_STACK_OVF (1);
12565                                 CHECK_OPSIZE (6);
12566                                 token = read32 (ip + 2);
12567                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12568                                 mono_class_init (klass);
12569                                 NEW_DOMAINCONST (cfg, iargs [0]);
12570                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
12571                                 NEW_CLASSCONST (cfg, iargs [1], klass);
12572                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
12573                                 *sp++ = mono_emit_jit_icall (cfg, ves_icall_object_new, iargs);
12574                                 ip += 6;
12575                                 inline_costs += 10 * num_calls++;
12576                                 break;
12577                         }
12578                         case CEE_MONO_OBJADDR:
12579                                 CHECK_STACK (1);
12580                                 --sp;
12581                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
12582                                 ins->dreg = alloc_ireg_mp (cfg);
12583                                 ins->sreg1 = sp [0]->dreg;
12584                                 ins->type = STACK_MP;
12585                                 MONO_ADD_INS (cfg->cbb, ins);
12586                                 *sp++ = ins;
12587                                 ip += 2;
12588                                 break;
12589                         case CEE_MONO_LDNATIVEOBJ:
12590                                 /*
12591                                  * Similar to LDOBJ, but instead load the unmanaged 
12592                                  * representation of the vtype to the stack.
12593                                  */
12594                                 CHECK_STACK (1);
12595                                 CHECK_OPSIZE (6);
12596                                 --sp;
12597                                 token = read32 (ip + 2);
12598                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12599                                 g_assert (klass->valuetype);
12600                                 mono_class_init (klass);
12601
12602                                 {
12603                                         MonoInst *src, *dest, *temp;
12604
12605                                         src = sp [0];
12606                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
12607                                         temp->backend.is_pinvoke = 1;
12608                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
12609                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
12610
12611                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
12612                                         dest->type = STACK_VTYPE;
12613                                         dest->klass = klass;
12614
12615                                         *sp ++ = dest;
12616                                         ip += 6;
12617                                 }
12618                                 break;
12619                         case CEE_MONO_RETOBJ: {
12620                                 /*
12621                                  * Same as RET, but return the native representation of a vtype
12622                                  * to the caller.
12623                                  */
12624                                 g_assert (cfg->ret);
12625                                 g_assert (mono_method_signature (method)->pinvoke); 
12626                                 CHECK_STACK (1);
12627                                 --sp;
12628                                 
12629                                 CHECK_OPSIZE (6);
12630                                 token = read32 (ip + 2);    
12631                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12632
12633                                 if (!cfg->vret_addr) {
12634                                         g_assert (cfg->ret_var_is_local);
12635
12636                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
12637                                 } else {
12638                                         EMIT_NEW_RETLOADA (cfg, ins);
12639                                 }
12640                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
12641                                 
12642                                 if (sp != stack_start)
12643                                         UNVERIFIED;
12644                                 
12645                                 MONO_INST_NEW (cfg, ins, OP_BR);
12646                                 ins->inst_target_bb = end_bblock;
12647                                 MONO_ADD_INS (cfg->cbb, ins);
12648                                 link_bblock (cfg, cfg->cbb, end_bblock);
12649                                 start_new_bblock = 1;
12650                                 ip += 6;
12651                                 break;
12652                         }
12653                         case CEE_MONO_CISINST:
12654                         case CEE_MONO_CCASTCLASS: {
12655                                 int token;
12656                                 CHECK_STACK (1);
12657                                 --sp;
12658                                 CHECK_OPSIZE (6);
12659                                 token = read32 (ip + 2);
12660                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12661                                 if (ip [1] == CEE_MONO_CISINST)
12662                                         ins = handle_cisinst (cfg, klass, sp [0]);
12663                                 else
12664                                         ins = handle_ccastclass (cfg, klass, sp [0]);
12665                                 *sp++ = ins;
12666                                 ip += 6;
12667                                 break;
12668                         }
12669                         case CEE_MONO_SAVE_LMF:
12670                         case CEE_MONO_RESTORE_LMF:
12671                                 ip += 2;
12672                                 break;
12673                         case CEE_MONO_CLASSCONST:
12674                                 CHECK_STACK_OVF (1);
12675                                 CHECK_OPSIZE (6);
12676                                 token = read32 (ip + 2);
12677                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
12678                                 *sp++ = ins;
12679                                 ip += 6;
12680                                 inline_costs += 10 * num_calls++;
12681                                 break;
12682                         case CEE_MONO_NOT_TAKEN:
12683                                 cfg->cbb->out_of_line = TRUE;
12684                                 ip += 2;
12685                                 break;
12686                         case CEE_MONO_TLS: {
12687                                 MonoTlsKey key;
12688
12689                                 CHECK_STACK_OVF (1);
12690                                 CHECK_OPSIZE (6);
12691                                 key = (MonoTlsKey)read32 (ip + 2);
12692                                 g_assert (key < TLS_KEY_NUM);
12693
12694                                 ins = mono_create_tls_get (cfg, key);
12695                                 if (!ins) {
12696                                         if (cfg->compile_aot) {
12697                                                 DISABLE_AOT (cfg);
12698                                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
12699                                                 ins->dreg = alloc_preg (cfg);
12700                                                 ins->type = STACK_PTR;
12701                                         } else {
12702                                                 g_assert_not_reached ();
12703                                         }
12704                                 }
12705                                 ins->type = STACK_PTR;
12706                                 MONO_ADD_INS (cfg->cbb, ins);
12707                                 *sp++ = ins;
12708                                 ip += 6;
12709                                 break;
12710                         }
12711                         case CEE_MONO_DYN_CALL: {
12712                                 MonoCallInst *call;
12713
12714                                 /* It would be easier to call a trampoline, but that would put an
12715                                  * extra frame on the stack, confusing exception handling. So
12716                                  * implement it inline using an opcode for now.
12717                                  */
12718
12719                                 if (!cfg->dyn_call_var) {
12720                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12721                                         /* prevent it from being register allocated */
12722                                         cfg->dyn_call_var->flags |= MONO_INST_VOLATILE;
12723                                 }
12724
12725                                 /* Has to use a call inst since it local regalloc expects it */
12726                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
12727                                 ins = (MonoInst*)call;
12728                                 sp -= 2;
12729                                 ins->sreg1 = sp [0]->dreg;
12730                                 ins->sreg2 = sp [1]->dreg;
12731                                 MONO_ADD_INS (cfg->cbb, ins);
12732
12733                                 cfg->param_area = MAX (cfg->param_area, cfg->backend->dyn_call_param_area);
12734
12735                                 ip += 2;
12736                                 inline_costs += 10 * num_calls++;
12737
12738                                 break;
12739                         }
12740                         case CEE_MONO_MEMORY_BARRIER: {
12741                                 CHECK_OPSIZE (6);
12742                                 emit_memory_barrier (cfg, (int)read32 (ip + 2));
12743                                 ip += 6;
12744                                 break;
12745                         }
12746                         case CEE_MONO_JIT_ATTACH: {
12747                                 MonoInst *args [16], *domain_ins;
12748                                 MonoInst *ad_ins, *jit_tls_ins;
12749                                 MonoBasicBlock *next_bb = NULL, *call_bb = NULL;
12750
12751                                 cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12752
12753                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12754                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12755
12756                                 ad_ins = mono_get_domain_intrinsic (cfg);
12757                                 jit_tls_ins = mono_get_jit_tls_intrinsic (cfg);
12758
12759                                 if (cfg->backend->have_tls_get && ad_ins && jit_tls_ins) {
12760                                         NEW_BBLOCK (cfg, next_bb);
12761                                         NEW_BBLOCK (cfg, call_bb);
12762
12763                                         if (cfg->compile_aot) {
12764                                                 /* AOT code is only used in the root domain */
12765                                                 EMIT_NEW_PCONST (cfg, domain_ins, NULL);
12766                                         } else {
12767                                                 EMIT_NEW_PCONST (cfg, domain_ins, cfg->domain);
12768                                         }
12769                                         MONO_ADD_INS (cfg->cbb, ad_ins);
12770                                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, ad_ins->dreg, domain_ins->dreg);
12771                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, call_bb);
12772
12773                                         MONO_ADD_INS (cfg->cbb, jit_tls_ins);
12774                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, jit_tls_ins->dreg, 0);
12775                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, call_bb);
12776
12777                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, next_bb);
12778                                         MONO_START_BB (cfg, call_bb);
12779                                 }
12780
12781                                 if (cfg->compile_aot) {
12782                                         /* AOT code is only used in the root domain */
12783                                         EMIT_NEW_PCONST (cfg, args [0], NULL);
12784                                 } else {
12785                                         EMIT_NEW_PCONST (cfg, args [0], cfg->domain);
12786                                 }
12787                                 ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
12788                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12789
12790                                 if (next_bb)
12791                                         MONO_START_BB (cfg, next_bb);
12792                                 ip += 2;
12793                                 break;
12794                         }
12795                         case CEE_MONO_JIT_DETACH: {
12796                                 MonoInst *args [16];
12797
12798                                 /* Restore the original domain */
12799                                 dreg = alloc_ireg (cfg);
12800                                 EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->orig_domain_var->dreg);
12801                                 mono_emit_jit_icall (cfg, mono_jit_set_domain, args);
12802                                 ip += 2;
12803                                 break;
12804                         }
12805                         case CEE_MONO_CALLI_EXTRA_ARG: {
12806                                 MonoInst *addr;
12807                                 MonoMethodSignature *fsig;
12808                                 MonoInst *arg;
12809
12810                                 /*
12811                                  * This is the same as CEE_CALLI, but passes an additional argument
12812                                  * to the called method in llvmonly mode.
12813                                  * This is only used by delegate invoke wrappers to call the
12814                                  * actual delegate method.
12815                                  */
12816                                 g_assert (method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE);
12817
12818                                 CHECK_OPSIZE (6);
12819                                 token = read32 (ip + 2);
12820
12821                                 ins = NULL;
12822
12823                                 cmethod = NULL;
12824                                 CHECK_STACK (1);
12825                                 --sp;
12826                                 addr = *sp;
12827                                 fsig = mini_get_signature (method, token, generic_context);
12828
12829                                 if (cfg->llvm_only)
12830                                         cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, fsig);
12831
12832                                 n = fsig->param_count + fsig->hasthis + 1;
12833
12834                                 CHECK_STACK (n);
12835
12836                                 sp -= n;
12837                                 arg = sp [n - 1];
12838
12839                                 if (cfg->llvm_only) {
12840                                         /*
12841                                          * The lowest bit of 'arg' determines whenever the callee uses the gsharedvt
12842                                          * cconv. This is set by mono_init_delegate ().
12843                                          */
12844                                         if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig)) {
12845                                                 MonoInst *callee = addr;
12846                                                 MonoInst *call, *localloc_ins;
12847                                                 MonoBasicBlock *is_gsharedvt_bb, *end_bb;
12848                                                 int low_bit_reg = alloc_preg (cfg);
12849
12850                                                 NEW_BBLOCK (cfg, is_gsharedvt_bb);
12851                                                 NEW_BBLOCK (cfg, end_bb);
12852
12853                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, low_bit_reg, arg->dreg, 1);
12854                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_bit_reg, 0);
12855                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_gsharedvt_bb);
12856
12857                                                 /* Normal case: callee uses a normal cconv, have to add an out wrapper */
12858                                                 addr = emit_get_rgctx_sig (cfg, context_used,
12859                                                                                                    fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
12860                                                 /*
12861                                                  * ADDR points to a gsharedvt-out wrapper, have to pass <callee, arg> as an extra arg.
12862                                                  */
12863                                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
12864                                                 ins->dreg = alloc_preg (cfg);
12865                                                 ins->inst_imm = 2 * SIZEOF_VOID_P;
12866                                                 MONO_ADD_INS (cfg->cbb, ins);
12867                                                 localloc_ins = ins;
12868                                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12869                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, 0, callee->dreg);
12870                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, SIZEOF_VOID_P, arg->dreg);
12871
12872                                                 call = emit_extra_arg_calli (cfg, fsig, sp, localloc_ins->dreg, addr);
12873                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12874
12875                                                 /* Gsharedvt case: callee uses a gsharedvt cconv, no conversion is needed */
12876                                                 MONO_START_BB (cfg, is_gsharedvt_bb);
12877                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PXOR_IMM, arg->dreg, arg->dreg, 1);
12878                                                 ins = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
12879                                                 ins->dreg = call->dreg;
12880
12881                                                 MONO_START_BB (cfg, end_bb);
12882                                         } else {
12883                                                 /* Caller uses a normal calling conv */
12884
12885                                                 MonoInst *callee = addr;
12886                                                 MonoInst *call, *localloc_ins;
12887                                                 MonoBasicBlock *is_gsharedvt_bb, *end_bb;
12888                                                 int low_bit_reg = alloc_preg (cfg);
12889
12890                                                 NEW_BBLOCK (cfg, is_gsharedvt_bb);
12891                                                 NEW_BBLOCK (cfg, end_bb);
12892
12893                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, low_bit_reg, arg->dreg, 1);
12894                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_bit_reg, 0);
12895                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_gsharedvt_bb);
12896
12897                                                 /* Normal case: callee uses a normal cconv, no conversion is needed */
12898                                                 call = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
12899                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12900                                                 /* Gsharedvt case: callee uses a gsharedvt cconv, have to add an in wrapper */
12901                                                 MONO_START_BB (cfg, is_gsharedvt_bb);
12902                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PXOR_IMM, arg->dreg, arg->dreg, 1);
12903                                                 NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER, fsig);
12904                                                 MONO_ADD_INS (cfg->cbb, addr);
12905                                                 /*
12906                                                  * ADDR points to a gsharedvt-in wrapper, have to pass <callee, arg> as an extra arg.
12907                                                  */
12908                                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
12909                                                 ins->dreg = alloc_preg (cfg);
12910                                                 ins->inst_imm = 2 * SIZEOF_VOID_P;
12911                                                 MONO_ADD_INS (cfg->cbb, ins);
12912                                                 localloc_ins = ins;
12913                                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12914                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, 0, callee->dreg);
12915                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, SIZEOF_VOID_P, arg->dreg);
12916
12917                                                 ins = emit_extra_arg_calli (cfg, fsig, sp, localloc_ins->dreg, addr);
12918                                                 ins->dreg = call->dreg;
12919                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12920
12921                                                 MONO_START_BB (cfg, end_bb);
12922                                         }
12923                                 } else {
12924                                         /* Same as CEE_CALLI */
12925                                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
12926                                                 /*
12927                                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
12928                                                  */
12929                                                 MonoInst *callee = addr;
12930
12931                                                 addr = emit_get_rgctx_sig (cfg, context_used,
12932                                                                                                    fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
12933                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
12934                                         } else {
12935                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
12936                                         }
12937                                 }
12938
12939                                 if (!MONO_TYPE_IS_VOID (fsig->ret))
12940                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
12941
12942                                 CHECK_CFG_EXCEPTION;
12943
12944                                 ip += 6;
12945                                 ins_flag = 0;
12946                                 constrained_class = NULL;
12947                                 break;
12948                         }
12949                         default:
12950                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
12951                                 break;
12952                         }
12953                         break;
12954                 }
12955
12956                 case CEE_PREFIX1: {
12957                         CHECK_OPSIZE (2);
12958                         switch (ip [1]) {
12959                         case CEE_ARGLIST: {
12960                                 /* somewhat similar to LDTOKEN */
12961                                 MonoInst *addr, *vtvar;
12962                                 CHECK_STACK_OVF (1);
12963                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
12964
12965                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12966                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
12967
12968                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12969                                 ins->type = STACK_VTYPE;
12970                                 ins->klass = mono_defaults.argumenthandle_class;
12971                                 *sp++ = ins;
12972                                 ip += 2;
12973                                 break;
12974                         }
12975                         case CEE_CEQ:
12976                         case CEE_CGT:
12977                         case CEE_CGT_UN:
12978                         case CEE_CLT:
12979                         case CEE_CLT_UN: {
12980                                 MonoInst *cmp, *arg1, *arg2;
12981
12982                                 CHECK_STACK (2);
12983                                 sp -= 2;
12984                                 arg1 = sp [0];
12985                                 arg2 = sp [1];
12986
12987                                 /*
12988                                  * The following transforms:
12989                                  *    CEE_CEQ    into OP_CEQ
12990                                  *    CEE_CGT    into OP_CGT
12991                                  *    CEE_CGT_UN into OP_CGT_UN
12992                                  *    CEE_CLT    into OP_CLT
12993                                  *    CEE_CLT_UN into OP_CLT_UN
12994                                  */
12995                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
12996
12997                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
12998                                 cmp->sreg1 = arg1->dreg;
12999                                 cmp->sreg2 = arg2->dreg;
13000                                 type_from_op (cfg, cmp, arg1, arg2);
13001                                 CHECK_TYPE (cmp);
13002                                 add_widen_op (cfg, cmp, &arg1, &arg2);
13003                                 if ((arg1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((arg1->type == STACK_PTR) || (arg1->type == STACK_OBJ) || (arg1->type == STACK_MP))))
13004                                         cmp->opcode = OP_LCOMPARE;
13005                                 else if (arg1->type == STACK_R4)
13006                                         cmp->opcode = OP_RCOMPARE;
13007                                 else if (arg1->type == STACK_R8)
13008                                         cmp->opcode = OP_FCOMPARE;
13009                                 else
13010                                         cmp->opcode = OP_ICOMPARE;
13011                                 MONO_ADD_INS (cfg->cbb, cmp);
13012                                 ins->type = STACK_I4;
13013                                 ins->dreg = alloc_dreg (cfg, (MonoStackType)ins->type);
13014                                 type_from_op (cfg, ins, arg1, arg2);
13015
13016                                 if (cmp->opcode == OP_FCOMPARE || cmp->opcode == OP_RCOMPARE) {
13017                                         /*
13018                                          * The backends expect the fceq opcodes to do the
13019                                          * comparison too.
13020                                          */
13021                                         ins->sreg1 = cmp->sreg1;
13022                                         ins->sreg2 = cmp->sreg2;
13023                                         NULLIFY_INS (cmp);
13024                                 }
13025                                 MONO_ADD_INS (cfg->cbb, ins);
13026                                 *sp++ = ins;
13027                                 ip += 2;
13028                                 break;
13029                         }
13030                         case CEE_LDFTN: {
13031                                 MonoInst *argconst;
13032                                 MonoMethod *cil_method;
13033
13034                                 CHECK_STACK_OVF (1);
13035                                 CHECK_OPSIZE (6);
13036                                 n = read32 (ip + 2);
13037                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
13038                                 CHECK_CFG_ERROR;
13039
13040                                 mono_class_init (cmethod->klass);
13041
13042                                 mono_save_token_info (cfg, image, n, cmethod);
13043
13044                                 context_used = mini_method_check_context_used (cfg, cmethod);
13045
13046                                 cil_method = cmethod;
13047                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
13048                                         METHOD_ACCESS_FAILURE (method, cil_method);
13049
13050                                 if (mono_security_core_clr_enabled ())
13051                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
13052
13053                                 /* 
13054                                  * Optimize the common case of ldftn+delegate creation
13055                                  */
13056                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
13057                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
13058                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
13059                                                 MonoInst *target_ins, *handle_ins;
13060                                                 MonoMethod *invoke;
13061                                                 int invoke_context_used;
13062
13063                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
13064                                                 if (!invoke || !mono_method_signature (invoke))
13065                                                         LOAD_ERROR;
13066
13067                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
13068
13069                                                 target_ins = sp [-1];
13070
13071                                                 if (mono_security_core_clr_enabled ())
13072                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
13073
13074                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
13075                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
13076                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
13077                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
13078                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
13079                                                         }
13080                                                 }
13081
13082                                                 /* FIXME: SGEN support */
13083                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
13084                                                         ip += 6;
13085                                                         if (cfg->verbose_level > 3)
13086                                                                 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));
13087                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, FALSE))) {
13088                                                                 sp --;
13089                                                                 *sp = handle_ins;
13090                                                                 CHECK_CFG_EXCEPTION;
13091                                                                 ip += 5;
13092                                                                 sp ++;
13093                                                                 break;
13094                                                         }
13095                                                         ip -= 6;
13096                                                 }
13097                                         }
13098                                 }
13099
13100                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
13101                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
13102                                 *sp++ = ins;
13103                                 
13104                                 ip += 6;
13105                                 inline_costs += 10 * num_calls++;
13106                                 break;
13107                         }
13108                         case CEE_LDVIRTFTN: {
13109                                 MonoInst *args [2];
13110
13111                                 CHECK_STACK (1);
13112                                 CHECK_OPSIZE (6);
13113                                 n = read32 (ip + 2);
13114                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
13115                                 CHECK_CFG_ERROR;
13116
13117                                 mono_class_init (cmethod->klass);
13118  
13119                                 context_used = mini_method_check_context_used (cfg, cmethod);
13120
13121                                 if (mono_security_core_clr_enabled ())
13122                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
13123
13124                                 /*
13125                                  * Optimize the common case of ldvirtftn+delegate creation
13126                                  */
13127                                 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)) {
13128                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
13129                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
13130                                                 MonoInst *target_ins, *handle_ins;
13131                                                 MonoMethod *invoke;
13132                                                 int invoke_context_used;
13133                                                 gboolean is_virtual = cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL;
13134
13135                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
13136                                                 if (!invoke || !mono_method_signature (invoke))
13137                                                         LOAD_ERROR;
13138
13139                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
13140
13141                                                 target_ins = sp [-1];
13142
13143                                                 if (mono_security_core_clr_enabled ())
13144                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
13145
13146                                                 /* FIXME: SGEN support */
13147                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
13148                                                         ip += 6;
13149                                                         if (cfg->verbose_level > 3)
13150                                                                 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));
13151                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, is_virtual))) {
13152                                                                 sp -= 2;
13153                                                                 *sp = handle_ins;
13154                                                                 CHECK_CFG_EXCEPTION;
13155                                                                 ip += 5;
13156                                                                 sp ++;
13157                                                                 break;
13158                                                         }
13159                                                         ip -= 6;
13160                                                 }
13161                                         }
13162                                 }
13163
13164                                 --sp;
13165                                 args [0] = *sp;
13166
13167                                 args [1] = emit_get_rgctx_method (cfg, context_used,
13168                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
13169
13170                                 if (context_used)
13171                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
13172                                 else
13173                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
13174
13175                                 ip += 6;
13176                                 inline_costs += 10 * num_calls++;
13177                                 break;
13178                         }
13179                         case CEE_LDARG:
13180                                 CHECK_STACK_OVF (1);
13181                                 CHECK_OPSIZE (4);
13182                                 n = read16 (ip + 2);
13183                                 CHECK_ARG (n);
13184                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
13185                                 *sp++ = ins;
13186                                 ip += 4;
13187                                 break;
13188                         case CEE_LDARGA:
13189                                 CHECK_STACK_OVF (1);
13190                                 CHECK_OPSIZE (4);
13191                                 n = read16 (ip + 2);
13192                                 CHECK_ARG (n);
13193                                 NEW_ARGLOADA (cfg, ins, n);
13194                                 MONO_ADD_INS (cfg->cbb, ins);
13195                                 *sp++ = ins;
13196                                 ip += 4;
13197                                 break;
13198                         case CEE_STARG:
13199                                 CHECK_STACK (1);
13200                                 --sp;
13201                                 CHECK_OPSIZE (4);
13202                                 n = read16 (ip + 2);
13203                                 CHECK_ARG (n);
13204                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
13205                                         UNVERIFIED;
13206                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
13207                                 ip += 4;
13208                                 break;
13209                         case CEE_LDLOC:
13210                                 CHECK_STACK_OVF (1);
13211                                 CHECK_OPSIZE (4);
13212                                 n = read16 (ip + 2);
13213                                 CHECK_LOCAL (n);
13214                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
13215                                 *sp++ = ins;
13216                                 ip += 4;
13217                                 break;
13218                         case CEE_LDLOCA: {
13219                                 unsigned char *tmp_ip;
13220                                 CHECK_STACK_OVF (1);
13221                                 CHECK_OPSIZE (4);
13222                                 n = read16 (ip + 2);
13223                                 CHECK_LOCAL (n);
13224
13225                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
13226                                         ip = tmp_ip;
13227                                         inline_costs += 1;
13228                                         break;
13229                                 }                       
13230                                 
13231                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
13232                                 *sp++ = ins;
13233                                 ip += 4;
13234                                 break;
13235                         }
13236                         case CEE_STLOC:
13237                                 CHECK_STACK (1);
13238                                 --sp;
13239                                 CHECK_OPSIZE (4);
13240                                 n = read16 (ip + 2);
13241                                 CHECK_LOCAL (n);
13242                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
13243                                         UNVERIFIED;
13244                                 emit_stloc_ir (cfg, sp, header, n);
13245                                 ip += 4;
13246                                 inline_costs += 1;
13247                                 break;
13248                         case CEE_LOCALLOC:
13249                                 CHECK_STACK (1);
13250                                 --sp;
13251                                 if (sp != stack_start) 
13252                                         UNVERIFIED;
13253                                 if (cfg->method != method) 
13254                                         /* 
13255                                          * Inlining this into a loop in a parent could lead to 
13256                                          * stack overflows which is different behavior than the
13257                                          * non-inlined case, thus disable inlining in this case.
13258                                          */
13259                                         INLINE_FAILURE("localloc");
13260
13261                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
13262                                 ins->dreg = alloc_preg (cfg);
13263                                 ins->sreg1 = sp [0]->dreg;
13264                                 ins->type = STACK_PTR;
13265                                 MONO_ADD_INS (cfg->cbb, ins);
13266
13267                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
13268                                 if (init_locals)
13269                                         ins->flags |= MONO_INST_INIT;
13270
13271                                 *sp++ = ins;
13272                                 ip += 2;
13273                                 break;
13274                         case CEE_ENDFILTER: {
13275                                 MonoExceptionClause *clause, *nearest;
13276                                 int cc;
13277
13278                                 CHECK_STACK (1);
13279                                 --sp;
13280                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
13281                                         UNVERIFIED;
13282                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
13283                                 ins->sreg1 = (*sp)->dreg;
13284                                 MONO_ADD_INS (cfg->cbb, ins);
13285                                 start_new_bblock = 1;
13286                                 ip += 2;
13287
13288                                 nearest = NULL;
13289                                 for (cc = 0; cc < header->num_clauses; ++cc) {
13290                                         clause = &header->clauses [cc];
13291                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
13292                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
13293                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset)))
13294                                                 nearest = clause;
13295                                 }
13296                                 g_assert (nearest);
13297                                 if ((ip - header->code) != nearest->handler_offset)
13298                                         UNVERIFIED;
13299
13300                                 break;
13301                         }
13302                         case CEE_UNALIGNED_:
13303                                 ins_flag |= MONO_INST_UNALIGNED;
13304                                 /* FIXME: record alignment? we can assume 1 for now */
13305                                 CHECK_OPSIZE (3);
13306                                 ip += 3;
13307                                 break;
13308                         case CEE_VOLATILE_:
13309                                 ins_flag |= MONO_INST_VOLATILE;
13310                                 ip += 2;
13311                                 break;
13312                         case CEE_TAIL_:
13313                                 ins_flag   |= MONO_INST_TAILCALL;
13314                                 cfg->flags |= MONO_CFG_HAS_TAIL;
13315                                 /* Can't inline tail calls at this time */
13316                                 inline_costs += 100000;
13317                                 ip += 2;
13318                                 break;
13319                         case CEE_INITOBJ:
13320                                 CHECK_STACK (1);
13321                                 --sp;
13322                                 CHECK_OPSIZE (6);
13323                                 token = read32 (ip + 2);
13324                                 klass = mini_get_class (method, token, generic_context);
13325                                 CHECK_TYPELOAD (klass);
13326                                 if (generic_class_is_reference_type (cfg, klass))
13327                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
13328                                 else
13329                                         mini_emit_initobj (cfg, *sp, NULL, klass);
13330                                 ip += 6;
13331                                 inline_costs += 1;
13332                                 break;
13333                         case CEE_CONSTRAINED_:
13334                                 CHECK_OPSIZE (6);
13335                                 token = read32 (ip + 2);
13336                                 constrained_class = mini_get_class (method, token, generic_context);
13337                                 CHECK_TYPELOAD (constrained_class);
13338                                 ip += 6;
13339                                 break;
13340                         case CEE_CPBLK:
13341                         case CEE_INITBLK: {
13342                                 MonoInst *iargs [3];
13343                                 CHECK_STACK (3);
13344                                 sp -= 3;
13345
13346                                 /* Skip optimized paths for volatile operations. */
13347                                 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)) {
13348                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
13349                                 } 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)) {
13350                                         /* emit_memset only works when val == 0 */
13351                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
13352                                 } else {
13353                                         MonoInst *call;
13354                                         iargs [0] = sp [0];
13355                                         iargs [1] = sp [1];
13356                                         iargs [2] = sp [2];
13357                                         if (ip [1] == CEE_CPBLK) {
13358                                                 /*
13359                                                  * FIXME: It's unclear whether we should be emitting both the acquire
13360                                                  * and release barriers for cpblk. It is technically both a load and
13361                                                  * store operation, so it seems like that's the sensible thing to do.
13362                                                  *
13363                                                  * FIXME: We emit full barriers on both sides of the operation for
13364                                                  * simplicity. We should have a separate atomic memcpy method instead.
13365                                                  */
13366                                                 MonoMethod *memcpy_method = get_memcpy_method ();
13367
13368                                                 if (ins_flag & MONO_INST_VOLATILE)
13369                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
13370
13371                                                 call = mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
13372                                                 call->flags |= ins_flag;
13373
13374                                                 if (ins_flag & MONO_INST_VOLATILE)
13375                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
13376                                         } else {
13377                                                 MonoMethod *memset_method = get_memset_method ();
13378                                                 if (ins_flag & MONO_INST_VOLATILE) {
13379                                                         /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
13380                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
13381                                                 }
13382                                                 call = mono_emit_method_call (cfg, memset_method, iargs, NULL);
13383                                                 call->flags |= ins_flag;
13384                                         }
13385                                 }
13386                                 ip += 2;
13387                                 ins_flag = 0;
13388                                 inline_costs += 1;
13389                                 break;
13390                         }
13391                         case CEE_NO_:
13392                                 CHECK_OPSIZE (3);
13393                                 if (ip [2] & 0x1)
13394                                         ins_flag |= MONO_INST_NOTYPECHECK;
13395                                 if (ip [2] & 0x2)
13396                                         ins_flag |= MONO_INST_NORANGECHECK;
13397                                 /* we ignore the no-nullcheck for now since we
13398                                  * really do it explicitly only when doing callvirt->call
13399                                  */
13400                                 ip += 3;
13401                                 break;
13402                         case CEE_RETHROW: {
13403                                 MonoInst *load;
13404                                 int handler_offset = -1;
13405
13406                                 for (i = 0; i < header->num_clauses; ++i) {
13407                                         MonoExceptionClause *clause = &header->clauses [i];
13408                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
13409                                                 handler_offset = clause->handler_offset;
13410                                                 break;
13411                                         }
13412                                 }
13413
13414                                 cfg->cbb->flags |= BB_EXCEPTION_UNSAFE;
13415
13416                                 if (handler_offset == -1)
13417                                         UNVERIFIED;
13418
13419                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
13420                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
13421                                 ins->sreg1 = load->dreg;
13422                                 MONO_ADD_INS (cfg->cbb, ins);
13423
13424                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
13425                                 MONO_ADD_INS (cfg->cbb, ins);
13426
13427                                 sp = stack_start;
13428                                 link_bblock (cfg, cfg->cbb, end_bblock);
13429                                 start_new_bblock = 1;
13430                                 ip += 2;
13431                                 break;
13432                         }
13433                         case CEE_SIZEOF: {
13434                                 guint32 val;
13435                                 int ialign;
13436
13437                                 CHECK_STACK_OVF (1);
13438                                 CHECK_OPSIZE (6);
13439                                 token = read32 (ip + 2);
13440                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !image_is_dynamic (method->klass->image) && !generic_context) {
13441                                         MonoType *type = mono_type_create_from_typespec_checked (image, token, &cfg->error);
13442                                         CHECK_CFG_ERROR;
13443
13444                                         val = mono_type_size (type, &ialign);
13445                                 } else {
13446                                         MonoClass *klass = mini_get_class (method, token, generic_context);
13447                                         CHECK_TYPELOAD (klass);
13448
13449                                         val = mono_type_size (&klass->byval_arg, &ialign);
13450
13451                                         if (mini_is_gsharedvt_klass (klass))
13452                                                 GSHAREDVT_FAILURE (*ip);
13453                                 }
13454                                 EMIT_NEW_ICONST (cfg, ins, val);
13455                                 *sp++= ins;
13456                                 ip += 6;
13457                                 break;
13458                         }
13459                         case CEE_REFANYTYPE: {
13460                                 MonoInst *src_var, *src;
13461
13462                                 GSHAREDVT_FAILURE (*ip);
13463
13464                                 CHECK_STACK (1);
13465                                 --sp;
13466
13467                                 // FIXME:
13468                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
13469                                 if (!src_var)
13470                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
13471                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
13472                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type));
13473                                 *sp++ = ins;
13474                                 ip += 2;
13475                                 break;
13476                         }
13477                         case CEE_READONLY_:
13478                                 readonly = TRUE;
13479                                 ip += 2;
13480                                 break;
13481
13482                         case CEE_UNUSED56:
13483                         case CEE_UNUSED57:
13484                         case CEE_UNUSED70:
13485                         case CEE_UNUSED:
13486                         case CEE_UNUSED99:
13487                                 UNVERIFIED;
13488                                 
13489                         default:
13490                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
13491                                 UNVERIFIED;
13492                         }
13493                         break;
13494                 }
13495                 case CEE_UNUSED58:
13496                 case CEE_UNUSED1:
13497                         UNVERIFIED;
13498
13499                 default:
13500                         g_warning ("opcode 0x%02x not handled", *ip);
13501                         UNVERIFIED;
13502                 }
13503         }
13504         if (start_new_bblock != 1)
13505                 UNVERIFIED;
13506
13507         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
13508         if (cfg->cbb->next_bb) {
13509                 /* This could already be set because of inlining, #693905 */
13510                 MonoBasicBlock *bb = cfg->cbb;
13511
13512                 while (bb->next_bb)
13513                         bb = bb->next_bb;
13514                 bb->next_bb = end_bblock;
13515         } else {
13516                 cfg->cbb->next_bb = end_bblock;
13517         }
13518
13519         if (cfg->method == method && cfg->domainvar) {
13520                 MonoInst *store;
13521                 MonoInst *get_domain;
13522
13523                 cfg->cbb = init_localsbb;
13524
13525                 if ((get_domain = mono_get_domain_intrinsic (cfg))) {
13526                         MONO_ADD_INS (cfg->cbb, get_domain);
13527                 } else {
13528                         get_domain = mono_emit_jit_icall (cfg, mono_domain_get, NULL);
13529                 }
13530                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
13531                 MONO_ADD_INS (cfg->cbb, store);
13532         }
13533
13534 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
13535         if (cfg->compile_aot)
13536                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
13537                 mono_get_got_var (cfg);
13538 #endif
13539
13540         if (cfg->method == method && cfg->got_var)
13541                 mono_emit_load_got_addr (cfg);
13542
13543         if (init_localsbb) {
13544                 cfg->cbb = init_localsbb;
13545                 cfg->ip = NULL;
13546                 for (i = 0; i < header->num_locals; ++i) {
13547                         emit_init_local (cfg, i, header->locals [i], init_locals);
13548                 }
13549         }
13550
13551         if (cfg->init_ref_vars && cfg->method == method) {
13552                 /* Emit initialization for ref vars */
13553                 // FIXME: Avoid duplication initialization for IL locals.
13554                 for (i = 0; i < cfg->num_varinfo; ++i) {
13555                         MonoInst *ins = cfg->varinfo [i];
13556
13557                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
13558                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
13559                 }
13560         }
13561
13562         if (cfg->lmf_var && cfg->method == method && !cfg->llvm_only) {
13563                 cfg->cbb = init_localsbb;
13564                 emit_push_lmf (cfg);
13565         }
13566
13567         cfg->cbb = init_localsbb;
13568         emit_instrumentation_call (cfg, mono_profiler_method_enter);
13569
13570         if (seq_points) {
13571                 MonoBasicBlock *bb;
13572
13573                 /*
13574                  * Make seq points at backward branch targets interruptable.
13575                  */
13576                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
13577                         if (bb->code && bb->in_count > 1 && bb->code->opcode == OP_SEQ_POINT)
13578                                 bb->code->flags |= MONO_INST_SINGLE_STEP_LOC;
13579         }
13580
13581         /* Add a sequence point for method entry/exit events */
13582         if (seq_points && cfg->gen_sdb_seq_points) {
13583                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
13584                 MONO_ADD_INS (init_localsbb, ins);
13585                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
13586                 MONO_ADD_INS (cfg->bb_exit, ins);
13587         }
13588
13589         /*
13590          * Add seq points for IL offsets which have line number info, but wasn't generated a seq point during JITting because
13591          * the code they refer to was dead (#11880).
13592          */
13593         if (sym_seq_points) {
13594                 for (i = 0; i < header->code_size; ++i) {
13595                         if (mono_bitset_test_fast (seq_point_locs, i) && !mono_bitset_test_fast (seq_point_set_locs, i)) {
13596                                 MonoInst *ins;
13597
13598                                 NEW_SEQ_POINT (cfg, ins, i, FALSE);
13599                                 mono_add_seq_point (cfg, NULL, ins, SEQ_POINT_NATIVE_OFFSET_DEAD_CODE);
13600                         }
13601                 }
13602         }
13603
13604         cfg->ip = NULL;
13605
13606         if (cfg->method == method) {
13607                 MonoBasicBlock *bb;
13608                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13609                         bb->region = mono_find_block_region (cfg, bb->real_offset);
13610                         if (cfg->spvars)
13611                                 mono_create_spvar_for_region (cfg, bb->region);
13612                         if (cfg->verbose_level > 2)
13613                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
13614                 }
13615         }
13616
13617         if (inline_costs < 0) {
13618                 char *mname;
13619
13620                 /* Method is too large */
13621                 mname = mono_method_full_name (method, TRUE);
13622                 mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Method %s is too complex.", mname));
13623                 g_free (mname);
13624         }
13625
13626         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
13627                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
13628
13629         goto cleanup;
13630
13631 mono_error_exit:
13632         g_assert (!mono_error_ok (&cfg->error));
13633         goto cleanup;
13634  
13635  exception_exit:
13636         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
13637         goto cleanup;
13638
13639  unverified:
13640         set_exception_type_from_invalid_il (cfg, method, ip);
13641         goto cleanup;
13642
13643  cleanup:
13644         g_slist_free (class_inits);
13645         mono_basic_block_free (original_bb);
13646         cfg->dont_inline = g_list_remove (cfg->dont_inline, method);
13647         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
13648         if (cfg->exception_type)
13649                 return -1;
13650         else
13651                 return inline_costs;
13652 }
13653
13654 static int
13655 store_membase_reg_to_store_membase_imm (int opcode)
13656 {
13657         switch (opcode) {
13658         case OP_STORE_MEMBASE_REG:
13659                 return OP_STORE_MEMBASE_IMM;
13660         case OP_STOREI1_MEMBASE_REG:
13661                 return OP_STOREI1_MEMBASE_IMM;
13662         case OP_STOREI2_MEMBASE_REG:
13663                 return OP_STOREI2_MEMBASE_IMM;
13664         case OP_STOREI4_MEMBASE_REG:
13665                 return OP_STOREI4_MEMBASE_IMM;
13666         case OP_STOREI8_MEMBASE_REG:
13667                 return OP_STOREI8_MEMBASE_IMM;
13668         default:
13669                 g_assert_not_reached ();
13670         }
13671
13672         return -1;
13673 }               
13674
13675 int
13676 mono_op_to_op_imm (int opcode)
13677 {
13678         switch (opcode) {
13679         case OP_IADD:
13680                 return OP_IADD_IMM;
13681         case OP_ISUB:
13682                 return OP_ISUB_IMM;
13683         case OP_IDIV:
13684                 return OP_IDIV_IMM;
13685         case OP_IDIV_UN:
13686                 return OP_IDIV_UN_IMM;
13687         case OP_IREM:
13688                 return OP_IREM_IMM;
13689         case OP_IREM_UN:
13690                 return OP_IREM_UN_IMM;
13691         case OP_IMUL:
13692                 return OP_IMUL_IMM;
13693         case OP_IAND:
13694                 return OP_IAND_IMM;
13695         case OP_IOR:
13696                 return OP_IOR_IMM;
13697         case OP_IXOR:
13698                 return OP_IXOR_IMM;
13699         case OP_ISHL:
13700                 return OP_ISHL_IMM;
13701         case OP_ISHR:
13702                 return OP_ISHR_IMM;
13703         case OP_ISHR_UN:
13704                 return OP_ISHR_UN_IMM;
13705
13706         case OP_LADD:
13707                 return OP_LADD_IMM;
13708         case OP_LSUB:
13709                 return OP_LSUB_IMM;
13710         case OP_LAND:
13711                 return OP_LAND_IMM;
13712         case OP_LOR:
13713                 return OP_LOR_IMM;
13714         case OP_LXOR:
13715                 return OP_LXOR_IMM;
13716         case OP_LSHL:
13717                 return OP_LSHL_IMM;
13718         case OP_LSHR:
13719                 return OP_LSHR_IMM;
13720         case OP_LSHR_UN:
13721                 return OP_LSHR_UN_IMM;
13722 #if SIZEOF_REGISTER == 8
13723         case OP_LREM:
13724                 return OP_LREM_IMM;
13725 #endif
13726
13727         case OP_COMPARE:
13728                 return OP_COMPARE_IMM;
13729         case OP_ICOMPARE:
13730                 return OP_ICOMPARE_IMM;
13731         case OP_LCOMPARE:
13732                 return OP_LCOMPARE_IMM;
13733
13734         case OP_STORE_MEMBASE_REG:
13735                 return OP_STORE_MEMBASE_IMM;
13736         case OP_STOREI1_MEMBASE_REG:
13737                 return OP_STOREI1_MEMBASE_IMM;
13738         case OP_STOREI2_MEMBASE_REG:
13739                 return OP_STOREI2_MEMBASE_IMM;
13740         case OP_STOREI4_MEMBASE_REG:
13741                 return OP_STOREI4_MEMBASE_IMM;
13742
13743 #if defined(TARGET_X86) || defined (TARGET_AMD64)
13744         case OP_X86_PUSH:
13745                 return OP_X86_PUSH_IMM;
13746         case OP_X86_COMPARE_MEMBASE_REG:
13747                 return OP_X86_COMPARE_MEMBASE_IMM;
13748 #endif
13749 #if defined(TARGET_AMD64)
13750         case OP_AMD64_ICOMPARE_MEMBASE_REG:
13751                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13752 #endif
13753         case OP_VOIDCALL_REG:
13754                 return OP_VOIDCALL;
13755         case OP_CALL_REG:
13756                 return OP_CALL;
13757         case OP_LCALL_REG:
13758                 return OP_LCALL;
13759         case OP_FCALL_REG:
13760                 return OP_FCALL;
13761         case OP_LOCALLOC:
13762                 return OP_LOCALLOC_IMM;
13763         }
13764
13765         return -1;
13766 }
13767
13768 static int
13769 ldind_to_load_membase (int opcode)
13770 {
13771         switch (opcode) {
13772         case CEE_LDIND_I1:
13773                 return OP_LOADI1_MEMBASE;
13774         case CEE_LDIND_U1:
13775                 return OP_LOADU1_MEMBASE;
13776         case CEE_LDIND_I2:
13777                 return OP_LOADI2_MEMBASE;
13778         case CEE_LDIND_U2:
13779                 return OP_LOADU2_MEMBASE;
13780         case CEE_LDIND_I4:
13781                 return OP_LOADI4_MEMBASE;
13782         case CEE_LDIND_U4:
13783                 return OP_LOADU4_MEMBASE;
13784         case CEE_LDIND_I:
13785                 return OP_LOAD_MEMBASE;
13786         case CEE_LDIND_REF:
13787                 return OP_LOAD_MEMBASE;
13788         case CEE_LDIND_I8:
13789                 return OP_LOADI8_MEMBASE;
13790         case CEE_LDIND_R4:
13791                 return OP_LOADR4_MEMBASE;
13792         case CEE_LDIND_R8:
13793                 return OP_LOADR8_MEMBASE;
13794         default:
13795                 g_assert_not_reached ();
13796         }
13797
13798         return -1;
13799 }
13800
13801 static int
13802 stind_to_store_membase (int opcode)
13803 {
13804         switch (opcode) {
13805         case CEE_STIND_I1:
13806                 return OP_STOREI1_MEMBASE_REG;
13807         case CEE_STIND_I2:
13808                 return OP_STOREI2_MEMBASE_REG;
13809         case CEE_STIND_I4:
13810                 return OP_STOREI4_MEMBASE_REG;
13811         case CEE_STIND_I:
13812         case CEE_STIND_REF:
13813                 return OP_STORE_MEMBASE_REG;
13814         case CEE_STIND_I8:
13815                 return OP_STOREI8_MEMBASE_REG;
13816         case CEE_STIND_R4:
13817                 return OP_STORER4_MEMBASE_REG;
13818         case CEE_STIND_R8:
13819                 return OP_STORER8_MEMBASE_REG;
13820         default:
13821                 g_assert_not_reached ();
13822         }
13823
13824         return -1;
13825 }
13826
13827 int
13828 mono_load_membase_to_load_mem (int opcode)
13829 {
13830         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
13831 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13832         switch (opcode) {
13833         case OP_LOAD_MEMBASE:
13834                 return OP_LOAD_MEM;
13835         case OP_LOADU1_MEMBASE:
13836                 return OP_LOADU1_MEM;
13837         case OP_LOADU2_MEMBASE:
13838                 return OP_LOADU2_MEM;
13839         case OP_LOADI4_MEMBASE:
13840                 return OP_LOADI4_MEM;
13841         case OP_LOADU4_MEMBASE:
13842                 return OP_LOADU4_MEM;
13843 #if SIZEOF_REGISTER == 8
13844         case OP_LOADI8_MEMBASE:
13845                 return OP_LOADI8_MEM;
13846 #endif
13847         }
13848 #endif
13849
13850         return -1;
13851 }
13852
13853 static inline int
13854 op_to_op_dest_membase (int store_opcode, int opcode)
13855 {
13856 #if defined(TARGET_X86)
13857         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
13858                 return -1;
13859
13860         switch (opcode) {
13861         case OP_IADD:
13862                 return OP_X86_ADD_MEMBASE_REG;
13863         case OP_ISUB:
13864                 return OP_X86_SUB_MEMBASE_REG;
13865         case OP_IAND:
13866                 return OP_X86_AND_MEMBASE_REG;
13867         case OP_IOR:
13868                 return OP_X86_OR_MEMBASE_REG;
13869         case OP_IXOR:
13870                 return OP_X86_XOR_MEMBASE_REG;
13871         case OP_ADD_IMM:
13872         case OP_IADD_IMM:
13873                 return OP_X86_ADD_MEMBASE_IMM;
13874         case OP_SUB_IMM:
13875         case OP_ISUB_IMM:
13876                 return OP_X86_SUB_MEMBASE_IMM;
13877         case OP_AND_IMM:
13878         case OP_IAND_IMM:
13879                 return OP_X86_AND_MEMBASE_IMM;
13880         case OP_OR_IMM:
13881         case OP_IOR_IMM:
13882                 return OP_X86_OR_MEMBASE_IMM;
13883         case OP_XOR_IMM:
13884         case OP_IXOR_IMM:
13885                 return OP_X86_XOR_MEMBASE_IMM;
13886         case OP_MOVE:
13887                 return OP_NOP;
13888         }
13889 #endif
13890
13891 #if defined(TARGET_AMD64)
13892         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
13893                 return -1;
13894
13895         switch (opcode) {
13896         case OP_IADD:
13897                 return OP_X86_ADD_MEMBASE_REG;
13898         case OP_ISUB:
13899                 return OP_X86_SUB_MEMBASE_REG;
13900         case OP_IAND:
13901                 return OP_X86_AND_MEMBASE_REG;
13902         case OP_IOR:
13903                 return OP_X86_OR_MEMBASE_REG;
13904         case OP_IXOR:
13905                 return OP_X86_XOR_MEMBASE_REG;
13906         case OP_IADD_IMM:
13907                 return OP_X86_ADD_MEMBASE_IMM;
13908         case OP_ISUB_IMM:
13909                 return OP_X86_SUB_MEMBASE_IMM;
13910         case OP_IAND_IMM:
13911                 return OP_X86_AND_MEMBASE_IMM;
13912         case OP_IOR_IMM:
13913                 return OP_X86_OR_MEMBASE_IMM;
13914         case OP_IXOR_IMM:
13915                 return OP_X86_XOR_MEMBASE_IMM;
13916         case OP_LADD:
13917                 return OP_AMD64_ADD_MEMBASE_REG;
13918         case OP_LSUB:
13919                 return OP_AMD64_SUB_MEMBASE_REG;
13920         case OP_LAND:
13921                 return OP_AMD64_AND_MEMBASE_REG;
13922         case OP_LOR:
13923                 return OP_AMD64_OR_MEMBASE_REG;
13924         case OP_LXOR:
13925                 return OP_AMD64_XOR_MEMBASE_REG;
13926         case OP_ADD_IMM:
13927         case OP_LADD_IMM:
13928                 return OP_AMD64_ADD_MEMBASE_IMM;
13929         case OP_SUB_IMM:
13930         case OP_LSUB_IMM:
13931                 return OP_AMD64_SUB_MEMBASE_IMM;
13932         case OP_AND_IMM:
13933         case OP_LAND_IMM:
13934                 return OP_AMD64_AND_MEMBASE_IMM;
13935         case OP_OR_IMM:
13936         case OP_LOR_IMM:
13937                 return OP_AMD64_OR_MEMBASE_IMM;
13938         case OP_XOR_IMM:
13939         case OP_LXOR_IMM:
13940                 return OP_AMD64_XOR_MEMBASE_IMM;
13941         case OP_MOVE:
13942                 return OP_NOP;
13943         }
13944 #endif
13945
13946         return -1;
13947 }
13948
13949 static inline int
13950 op_to_op_store_membase (int store_opcode, int opcode)
13951 {
13952 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13953         switch (opcode) {
13954         case OP_ICEQ:
13955                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13956                         return OP_X86_SETEQ_MEMBASE;
13957         case OP_CNE:
13958                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13959                         return OP_X86_SETNE_MEMBASE;
13960         }
13961 #endif
13962
13963         return -1;
13964 }
13965
13966 static inline int
13967 op_to_op_src1_membase (MonoCompile *cfg, int load_opcode, int opcode)
13968 {
13969 #ifdef TARGET_X86
13970         /* FIXME: This has sign extension issues */
13971         /*
13972         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13973                 return OP_X86_COMPARE_MEMBASE8_IMM;
13974         */
13975
13976         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13977                 return -1;
13978
13979         switch (opcode) {
13980         case OP_X86_PUSH:
13981                 return OP_X86_PUSH_MEMBASE;
13982         case OP_COMPARE_IMM:
13983         case OP_ICOMPARE_IMM:
13984                 return OP_X86_COMPARE_MEMBASE_IMM;
13985         case OP_COMPARE:
13986         case OP_ICOMPARE:
13987                 return OP_X86_COMPARE_MEMBASE_REG;
13988         }
13989 #endif
13990
13991 #ifdef TARGET_AMD64
13992         /* FIXME: This has sign extension issues */
13993         /*
13994         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13995                 return OP_X86_COMPARE_MEMBASE8_IMM;
13996         */
13997
13998         switch (opcode) {
13999         case OP_X86_PUSH:
14000                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
14001                         return OP_X86_PUSH_MEMBASE;
14002                 break;
14003                 /* FIXME: This only works for 32 bit immediates
14004         case OP_COMPARE_IMM:
14005         case OP_LCOMPARE_IMM:
14006                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
14007                         return OP_AMD64_COMPARE_MEMBASE_IMM;
14008                 */
14009         case OP_ICOMPARE_IMM:
14010                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
14011                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
14012                 break;
14013         case OP_COMPARE:
14014         case OP_LCOMPARE:
14015                 if (cfg->backend->ilp32 && load_opcode == OP_LOAD_MEMBASE)
14016                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
14017                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
14018                         return OP_AMD64_COMPARE_MEMBASE_REG;
14019                 break;
14020         case OP_ICOMPARE:
14021                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
14022                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
14023                 break;
14024         }
14025 #endif
14026
14027         return -1;
14028 }
14029
14030 static inline int
14031 op_to_op_src2_membase (MonoCompile *cfg, int load_opcode, int opcode)
14032 {
14033 #ifdef TARGET_X86
14034         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
14035                 return -1;
14036         
14037         switch (opcode) {
14038         case OP_COMPARE:
14039         case OP_ICOMPARE:
14040                 return OP_X86_COMPARE_REG_MEMBASE;
14041         case OP_IADD:
14042                 return OP_X86_ADD_REG_MEMBASE;
14043         case OP_ISUB:
14044                 return OP_X86_SUB_REG_MEMBASE;
14045         case OP_IAND:
14046                 return OP_X86_AND_REG_MEMBASE;
14047         case OP_IOR:
14048                 return OP_X86_OR_REG_MEMBASE;
14049         case OP_IXOR:
14050                 return OP_X86_XOR_REG_MEMBASE;
14051         }
14052 #endif
14053
14054 #ifdef TARGET_AMD64
14055         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && cfg->backend->ilp32)) {
14056                 switch (opcode) {
14057                 case OP_ICOMPARE:
14058                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
14059                 case OP_IADD:
14060                         return OP_X86_ADD_REG_MEMBASE;
14061                 case OP_ISUB:
14062                         return OP_X86_SUB_REG_MEMBASE;
14063                 case OP_IAND:
14064                         return OP_X86_AND_REG_MEMBASE;
14065                 case OP_IOR:
14066                         return OP_X86_OR_REG_MEMBASE;
14067                 case OP_IXOR:
14068                         return OP_X86_XOR_REG_MEMBASE;
14069                 }
14070         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32)) {
14071                 switch (opcode) {
14072                 case OP_COMPARE:
14073                 case OP_LCOMPARE:
14074                         return OP_AMD64_COMPARE_REG_MEMBASE;
14075                 case OP_LADD:
14076                         return OP_AMD64_ADD_REG_MEMBASE;
14077                 case OP_LSUB:
14078                         return OP_AMD64_SUB_REG_MEMBASE;
14079                 case OP_LAND:
14080                         return OP_AMD64_AND_REG_MEMBASE;
14081                 case OP_LOR:
14082                         return OP_AMD64_OR_REG_MEMBASE;
14083                 case OP_LXOR:
14084                         return OP_AMD64_XOR_REG_MEMBASE;
14085                 }
14086         }
14087 #endif
14088
14089         return -1;
14090 }
14091
14092 int
14093 mono_op_to_op_imm_noemul (int opcode)
14094 {
14095         switch (opcode) {
14096 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
14097         case OP_LSHR:
14098         case OP_LSHL:
14099         case OP_LSHR_UN:
14100                 return -1;
14101 #endif
14102 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
14103         case OP_IDIV:
14104         case OP_IDIV_UN:
14105         case OP_IREM:
14106         case OP_IREM_UN:
14107                 return -1;
14108 #endif
14109 #if defined(MONO_ARCH_EMULATE_MUL_DIV)
14110         case OP_IMUL:
14111                 return -1;
14112 #endif
14113         default:
14114                 return mono_op_to_op_imm (opcode);
14115         }
14116 }
14117
14118 /**
14119  * mono_handle_global_vregs:
14120  *
14121  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
14122  * for them.
14123  */
14124 void
14125 mono_handle_global_vregs (MonoCompile *cfg)
14126 {
14127         gint32 *vreg_to_bb;
14128         MonoBasicBlock *bb;
14129         int i, pos;
14130
14131         vreg_to_bb = (gint32 *)mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
14132
14133 #ifdef MONO_ARCH_SIMD_INTRINSICS
14134         if (cfg->uses_simd_intrinsics)
14135                 mono_simd_simplify_indirection (cfg);
14136 #endif
14137
14138         /* Find local vregs used in more than one bb */
14139         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
14140                 MonoInst *ins = bb->code;       
14141                 int block_num = bb->block_num;
14142
14143                 if (cfg->verbose_level > 2)
14144                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
14145
14146                 cfg->cbb = bb;
14147                 for (; ins; ins = ins->next) {
14148                         const char *spec = INS_INFO (ins->opcode);
14149                         int regtype = 0, regindex;
14150                         gint32 prev_bb;
14151
14152                         if (G_UNLIKELY (cfg->verbose_level > 2))
14153                                 mono_print_ins (ins);
14154
14155                         g_assert (ins->opcode >= MONO_CEE_LAST);
14156
14157                         for (regindex = 0; regindex < 4; regindex ++) {
14158                                 int vreg = 0;
14159
14160                                 if (regindex == 0) {
14161                                         regtype = spec [MONO_INST_DEST];
14162                                         if (regtype == ' ')
14163                                                 continue;
14164                                         vreg = ins->dreg;
14165                                 } else if (regindex == 1) {
14166                                         regtype = spec [MONO_INST_SRC1];
14167                                         if (regtype == ' ')
14168                                                 continue;
14169                                         vreg = ins->sreg1;
14170                                 } else if (regindex == 2) {
14171                                         regtype = spec [MONO_INST_SRC2];
14172                                         if (regtype == ' ')
14173                                                 continue;
14174                                         vreg = ins->sreg2;
14175                                 } else if (regindex == 3) {
14176                                         regtype = spec [MONO_INST_SRC3];
14177                                         if (regtype == ' ')
14178                                                 continue;
14179                                         vreg = ins->sreg3;
14180                                 }
14181
14182 #if SIZEOF_REGISTER == 4
14183                                 /* In the LLVM case, the long opcodes are not decomposed */
14184                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
14185                                         /*
14186                                          * Since some instructions reference the original long vreg,
14187                                          * and some reference the two component vregs, it is quite hard
14188                                          * to determine when it needs to be global. So be conservative.
14189                                          */
14190                                         if (!get_vreg_to_inst (cfg, vreg)) {
14191                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
14192
14193                                                 if (cfg->verbose_level > 2)
14194                                                         printf ("LONG VREG R%d made global.\n", vreg);
14195                                         }
14196
14197                                         /*
14198                                          * Make the component vregs volatile since the optimizations can
14199                                          * get confused otherwise.
14200                                          */
14201                                         get_vreg_to_inst (cfg, MONO_LVREG_LS (vreg))->flags |= MONO_INST_VOLATILE;
14202                                         get_vreg_to_inst (cfg, MONO_LVREG_MS (vreg))->flags |= MONO_INST_VOLATILE;
14203                                 }
14204 #endif
14205
14206                                 g_assert (vreg != -1);
14207
14208                                 prev_bb = vreg_to_bb [vreg];
14209                                 if (prev_bb == 0) {
14210                                         /* 0 is a valid block num */
14211                                         vreg_to_bb [vreg] = block_num + 1;
14212                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
14213                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
14214                                                 continue;
14215
14216                                         if (!get_vreg_to_inst (cfg, vreg)) {
14217                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14218                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
14219
14220                                                 switch (regtype) {
14221                                                 case 'i':
14222                                                         if (vreg_is_ref (cfg, vreg))
14223                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg);
14224                                                         else
14225                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
14226                                                         break;
14227                                                 case 'l':
14228                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
14229                                                         break;
14230                                                 case 'f':
14231                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
14232                                                         break;
14233                                                 case 'v':
14234                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
14235                                                         break;
14236                                                 default:
14237                                                         g_assert_not_reached ();
14238                                                 }
14239                                         }
14240
14241                                         /* Flag as having been used in more than one bb */
14242                                         vreg_to_bb [vreg] = -1;
14243                                 }
14244                         }
14245                 }
14246         }
14247
14248         /* If a variable is used in only one bblock, convert it into a local vreg */
14249         for (i = 0; i < cfg->num_varinfo; i++) {
14250                 MonoInst *var = cfg->varinfo [i];
14251                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
14252
14253                 switch (var->type) {
14254                 case STACK_I4:
14255                 case STACK_OBJ:
14256                 case STACK_PTR:
14257                 case STACK_MP:
14258                 case STACK_VTYPE:
14259 #if SIZEOF_REGISTER == 8
14260                 case STACK_I8:
14261 #endif
14262 #if !defined(TARGET_X86)
14263                 /* Enabling this screws up the fp stack on x86 */
14264                 case STACK_R8:
14265 #endif
14266                         if (mono_arch_is_soft_float ())
14267                                 break;
14268
14269                         /*
14270                         if (var->type == STACK_VTYPE && cfg->gsharedvt && mini_is_gsharedvt_variable_type (var->inst_vtype))
14271                                 break;
14272                         */
14273
14274                         /* Arguments are implicitly global */
14275                         /* Putting R4 vars into registers doesn't work currently */
14276                         /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
14277                         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) {
14278                                 /* 
14279                                  * Make that the variable's liveness interval doesn't contain a call, since
14280                                  * that would cause the lvreg to be spilled, making the whole optimization
14281                                  * useless.
14282                                  */
14283                                 /* This is too slow for JIT compilation */
14284 #if 0
14285                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
14286                                         MonoInst *ins;
14287                                         int def_index, call_index, ins_index;
14288                                         gboolean spilled = FALSE;
14289
14290                                         def_index = -1;
14291                                         call_index = -1;
14292                                         ins_index = 0;
14293                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
14294                                                 const char *spec = INS_INFO (ins->opcode);
14295
14296                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
14297                                                         def_index = ins_index;
14298
14299                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
14300                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
14301                                                         if (call_index > def_index) {
14302                                                                 spilled = TRUE;
14303                                                                 break;
14304                                                         }
14305                                                 }
14306
14307                                                 if (MONO_IS_CALL (ins))
14308                                                         call_index = ins_index;
14309
14310                                                 ins_index ++;
14311                                         }
14312
14313                                         if (spilled)
14314                                                 break;
14315                                 }
14316 #endif
14317
14318                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14319                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
14320                                 var->flags |= MONO_INST_IS_DEAD;
14321                                 cfg->vreg_to_inst [var->dreg] = NULL;
14322                         }
14323                         break;
14324                 }
14325         }
14326
14327         /* 
14328          * Compress the varinfo and vars tables so the liveness computation is faster and
14329          * takes up less space.
14330          */
14331         pos = 0;
14332         for (i = 0; i < cfg->num_varinfo; ++i) {
14333                 MonoInst *var = cfg->varinfo [i];
14334                 if (pos < i && cfg->locals_start == i)
14335                         cfg->locals_start = pos;
14336                 if (!(var->flags & MONO_INST_IS_DEAD)) {
14337                         if (pos < i) {
14338                                 cfg->varinfo [pos] = cfg->varinfo [i];
14339                                 cfg->varinfo [pos]->inst_c0 = pos;
14340                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
14341                                 cfg->vars [pos].idx = pos;
14342 #if SIZEOF_REGISTER == 4
14343                                 if (cfg->varinfo [pos]->type == STACK_I8) {
14344                                         /* Modify the two component vars too */
14345                                         MonoInst *var1;
14346
14347                                         var1 = get_vreg_to_inst (cfg, MONO_LVREG_LS (cfg->varinfo [pos]->dreg));
14348                                         var1->inst_c0 = pos;
14349                                         var1 = get_vreg_to_inst (cfg, MONO_LVREG_MS (cfg->varinfo [pos]->dreg));
14350                                         var1->inst_c0 = pos;
14351                                 }
14352 #endif
14353                         }
14354                         pos ++;
14355                 }
14356         }
14357         cfg->num_varinfo = pos;
14358         if (cfg->locals_start > cfg->num_varinfo)
14359                 cfg->locals_start = cfg->num_varinfo;
14360 }
14361
14362 /*
14363  * mono_allocate_gsharedvt_vars:
14364  *
14365  *   Allocate variables with gsharedvt types to entries in the MonoGSharedVtMethodRuntimeInfo.entries array.
14366  * Initialize cfg->gsharedvt_vreg_to_idx with the mapping between vregs and indexes.
14367  */
14368 void
14369 mono_allocate_gsharedvt_vars (MonoCompile *cfg)
14370 {
14371         int i;
14372
14373         cfg->gsharedvt_vreg_to_idx = (int *)mono_mempool_alloc0 (cfg->mempool, sizeof (int) * cfg->next_vreg);
14374
14375         for (i = 0; i < cfg->num_varinfo; ++i) {
14376                 MonoInst *ins = cfg->varinfo [i];
14377                 int idx;
14378
14379                 if (mini_is_gsharedvt_variable_type (ins->inst_vtype)) {
14380                         if (i >= cfg->locals_start) {
14381                                 /* Local */
14382                                 idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
14383                                 cfg->gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
14384                                 ins->opcode = OP_GSHAREDVT_LOCAL;
14385                                 ins->inst_imm = idx;
14386                         } else {
14387                                 /* Arg */
14388                                 cfg->gsharedvt_vreg_to_idx [ins->dreg] = -1;
14389                                 ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
14390                         }
14391                 }
14392         }
14393 }
14394
14395 /**
14396  * mono_spill_global_vars:
14397  *
14398  *   Generate spill code for variables which are not allocated to registers, 
14399  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
14400  * code is generated which could be optimized by the local optimization passes.
14401  */
14402 void
14403 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
14404 {
14405         MonoBasicBlock *bb;
14406         char spec2 [16];
14407         int orig_next_vreg;
14408         guint32 *vreg_to_lvreg;
14409         guint32 *lvregs;
14410         guint32 i, lvregs_len;
14411         gboolean dest_has_lvreg = FALSE;
14412         MonoStackType stacktypes [128];
14413         MonoInst **live_range_start, **live_range_end;
14414         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
14415
14416         *need_local_opts = FALSE;
14417
14418         memset (spec2, 0, sizeof (spec2));
14419
14420         /* FIXME: Move this function to mini.c */
14421         stacktypes ['i'] = STACK_PTR;
14422         stacktypes ['l'] = STACK_I8;
14423         stacktypes ['f'] = STACK_R8;
14424 #ifdef MONO_ARCH_SIMD_INTRINSICS
14425         stacktypes ['x'] = STACK_VTYPE;
14426 #endif
14427
14428 #if SIZEOF_REGISTER == 4
14429         /* Create MonoInsts for longs */
14430         for (i = 0; i < cfg->num_varinfo; i++) {
14431                 MonoInst *ins = cfg->varinfo [i];
14432
14433                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
14434                         switch (ins->type) {
14435                         case STACK_R8:
14436                         case STACK_I8: {
14437                                 MonoInst *tree;
14438
14439                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
14440                                         break;
14441
14442                                 g_assert (ins->opcode == OP_REGOFFSET);
14443
14444                                 tree = get_vreg_to_inst (cfg, MONO_LVREG_LS (ins->dreg));
14445                                 g_assert (tree);
14446                                 tree->opcode = OP_REGOFFSET;
14447                                 tree->inst_basereg = ins->inst_basereg;
14448                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
14449
14450                                 tree = get_vreg_to_inst (cfg, MONO_LVREG_MS (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_MS_WORD_OFFSET;
14455                                 break;
14456                         }
14457                         default:
14458                                 break;
14459                         }
14460                 }
14461         }
14462 #endif
14463
14464         if (cfg->compute_gc_maps) {
14465                 /* registers need liveness info even for !non refs */
14466                 for (i = 0; i < cfg->num_varinfo; i++) {
14467                         MonoInst *ins = cfg->varinfo [i];
14468
14469                         if (ins->opcode == OP_REGVAR)
14470                                 ins->flags |= MONO_INST_GC_TRACK;
14471                 }
14472         }
14473                 
14474         /* FIXME: widening and truncation */
14475
14476         /*
14477          * As an optimization, when a variable allocated to the stack is first loaded into 
14478          * an lvreg, we will remember the lvreg and use it the next time instead of loading
14479          * the variable again.
14480          */
14481         orig_next_vreg = cfg->next_vreg;
14482         vreg_to_lvreg = (guint32 *)mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
14483         lvregs = (guint32 *)mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
14484         lvregs_len = 0;
14485
14486         /* 
14487          * These arrays contain the first and last instructions accessing a given
14488          * variable.
14489          * Since we emit bblocks in the same order we process them here, and we
14490          * don't split live ranges, these will precisely describe the live range of
14491          * the variable, i.e. the instruction range where a valid value can be found
14492          * in the variables location.
14493          * The live range is computed using the liveness info computed by the liveness pass.
14494          * We can't use vmv->range, since that is an abstract live range, and we need
14495          * one which is instruction precise.
14496          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
14497          */
14498         /* FIXME: Only do this if debugging info is requested */
14499         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
14500         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
14501         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
14502         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
14503         
14504         /* Add spill loads/stores */
14505         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
14506                 MonoInst *ins;
14507
14508                 if (cfg->verbose_level > 2)
14509                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
14510
14511                 /* Clear vreg_to_lvreg array */
14512                 for (i = 0; i < lvregs_len; i++)
14513                         vreg_to_lvreg [lvregs [i]] = 0;
14514                 lvregs_len = 0;
14515
14516                 cfg->cbb = bb;
14517                 MONO_BB_FOR_EACH_INS (bb, ins) {
14518                         const char *spec = INS_INFO (ins->opcode);
14519                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
14520                         gboolean store, no_lvreg;
14521                         int sregs [MONO_MAX_SRC_REGS];
14522
14523                         if (G_UNLIKELY (cfg->verbose_level > 2))
14524                                 mono_print_ins (ins);
14525
14526                         if (ins->opcode == OP_NOP)
14527                                 continue;
14528
14529                         /* 
14530                          * We handle LDADDR here as well, since it can only be decomposed
14531                          * when variable addresses are known.
14532                          */
14533                         if (ins->opcode == OP_LDADDR) {
14534                                 MonoInst *var = (MonoInst *)ins->inst_p0;
14535
14536                                 if (var->opcode == OP_VTARG_ADDR) {
14537                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
14538                                         MonoInst *vtaddr = var->inst_left;
14539                                         if (vtaddr->opcode == OP_REGVAR) {
14540                                                 ins->opcode = OP_MOVE;
14541                                                 ins->sreg1 = vtaddr->dreg;
14542                                         }
14543                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
14544                                                 ins->opcode = OP_LOAD_MEMBASE;
14545                                                 ins->inst_basereg = vtaddr->inst_basereg;
14546                                                 ins->inst_offset = vtaddr->inst_offset;
14547                                         } else
14548                                                 NOT_IMPLEMENTED;
14549                                 } else if (cfg->gsharedvt && cfg->gsharedvt_vreg_to_idx [var->dreg] < 0) {
14550                                         /* gsharedvt arg passed by ref */
14551                                         g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
14552
14553                                         ins->opcode = OP_LOAD_MEMBASE;
14554                                         ins->inst_basereg = var->inst_basereg;
14555                                         ins->inst_offset = var->inst_offset;
14556                                 } else if (cfg->gsharedvt && cfg->gsharedvt_vreg_to_idx [var->dreg]) {
14557                                         MonoInst *load, *load2, *load3;
14558                                         int idx = cfg->gsharedvt_vreg_to_idx [var->dreg] - 1;
14559                                         int reg1, reg2, reg3;
14560                                         MonoInst *info_var = cfg->gsharedvt_info_var;
14561                                         MonoInst *locals_var = cfg->gsharedvt_locals_var;
14562
14563                                         /*
14564                                          * gsharedvt local.
14565                                          * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
14566                                          */
14567
14568                                         g_assert (var->opcode == OP_GSHAREDVT_LOCAL);
14569
14570                                         g_assert (info_var);
14571                                         g_assert (locals_var);
14572
14573                                         /* Mark the instruction used to compute the locals var as used */
14574                                         cfg->gsharedvt_locals_var_ins = NULL;
14575
14576                                         /* Load the offset */
14577                                         if (info_var->opcode == OP_REGOFFSET) {
14578                                                 reg1 = alloc_ireg (cfg);
14579                                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, reg1, info_var->inst_basereg, info_var->inst_offset);
14580                                         } else if (info_var->opcode == OP_REGVAR) {
14581                                                 load = NULL;
14582                                                 reg1 = info_var->dreg;
14583                                         } else {
14584                                                 g_assert_not_reached ();
14585                                         }
14586                                         reg2 = alloc_ireg (cfg);
14587                                         NEW_LOAD_MEMBASE (cfg, load2, OP_LOADI4_MEMBASE, reg2, reg1, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
14588                                         /* Load the locals area address */
14589                                         reg3 = alloc_ireg (cfg);
14590                                         if (locals_var->opcode == OP_REGOFFSET) {
14591                                                 NEW_LOAD_MEMBASE (cfg, load3, OP_LOAD_MEMBASE, reg3, locals_var->inst_basereg, locals_var->inst_offset);
14592                                         } else if (locals_var->opcode == OP_REGVAR) {
14593                                                 NEW_UNALU (cfg, load3, OP_MOVE, reg3, locals_var->dreg);
14594                                         } else {
14595                                                 g_assert_not_reached ();
14596                                         }
14597                                         /* Compute the address */
14598                                         ins->opcode = OP_PADD;
14599                                         ins->sreg1 = reg3;
14600                                         ins->sreg2 = reg2;
14601
14602                                         mono_bblock_insert_before_ins (bb, ins, load3);
14603                                         mono_bblock_insert_before_ins (bb, load3, load2);
14604                                         if (load)
14605                                                 mono_bblock_insert_before_ins (bb, load2, load);
14606                                 } else {
14607                                         g_assert (var->opcode == OP_REGOFFSET);
14608
14609                                         ins->opcode = OP_ADD_IMM;
14610                                         ins->sreg1 = var->inst_basereg;
14611                                         ins->inst_imm = var->inst_offset;
14612                                 }
14613
14614                                 *need_local_opts = TRUE;
14615                                 spec = INS_INFO (ins->opcode);
14616                         }
14617
14618                         if (ins->opcode < MONO_CEE_LAST) {
14619                                 mono_print_ins (ins);
14620                                 g_assert_not_reached ();
14621                         }
14622
14623                         /*
14624                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
14625                          * src register.
14626                          * FIXME:
14627                          */
14628                         if (MONO_IS_STORE_MEMBASE (ins)) {
14629                                 tmp_reg = ins->dreg;
14630                                 ins->dreg = ins->sreg2;
14631                                 ins->sreg2 = tmp_reg;
14632                                 store = TRUE;
14633
14634                                 spec2 [MONO_INST_DEST] = ' ';
14635                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14636                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14637                                 spec2 [MONO_INST_SRC3] = ' ';
14638                                 spec = spec2;
14639                         } else if (MONO_IS_STORE_MEMINDEX (ins))
14640                                 g_assert_not_reached ();
14641                         else
14642                                 store = FALSE;
14643                         no_lvreg = FALSE;
14644
14645                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
14646                                 printf ("\t %.3s %d", spec, ins->dreg);
14647                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
14648                                 for (srcindex = 0; srcindex < num_sregs; ++srcindex)
14649                                         printf (" %d", sregs [srcindex]);
14650                                 printf ("\n");
14651                         }
14652
14653                         /***************/
14654                         /*    DREG     */
14655                         /***************/
14656                         regtype = spec [MONO_INST_DEST];
14657                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
14658                         prev_dreg = -1;
14659
14660                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
14661                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
14662                                 MonoInst *store_ins;
14663                                 int store_opcode;
14664                                 MonoInst *def_ins = ins;
14665                                 int dreg = ins->dreg; /* The original vreg */
14666
14667                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
14668
14669                                 if (var->opcode == OP_REGVAR) {
14670                                         ins->dreg = var->dreg;
14671                                 } 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)) {
14672                                         /* 
14673                                          * Instead of emitting a load+store, use a _membase opcode.
14674                                          */
14675                                         g_assert (var->opcode == OP_REGOFFSET);
14676                                         if (ins->opcode == OP_MOVE) {
14677                                                 NULLIFY_INS (ins);
14678                                                 def_ins = NULL;
14679                                         } else {
14680                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
14681                                                 ins->inst_basereg = var->inst_basereg;
14682                                                 ins->inst_offset = var->inst_offset;
14683                                                 ins->dreg = -1;
14684                                         }
14685                                         spec = INS_INFO (ins->opcode);
14686                                 } else {
14687                                         guint32 lvreg;
14688
14689                                         g_assert (var->opcode == OP_REGOFFSET);
14690
14691                                         prev_dreg = ins->dreg;
14692
14693                                         /* Invalidate any previous lvreg for this vreg */
14694                                         vreg_to_lvreg [ins->dreg] = 0;
14695
14696                                         lvreg = 0;
14697
14698                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
14699                                                 regtype = 'l';
14700                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
14701                                         }
14702
14703                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
14704
14705 #if SIZEOF_REGISTER != 8
14706                                         if (regtype == 'l') {
14707                                                 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));
14708                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14709                                                 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));
14710                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14711                                                 def_ins = store_ins;
14712                                         }
14713                                         else
14714 #endif
14715                                         {
14716                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
14717
14718                                                 /* Try to fuse the store into the instruction itself */
14719                                                 /* FIXME: Add more instructions */
14720                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
14721                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
14722                                                         ins->inst_imm = ins->inst_c0;
14723                                                         ins->inst_destbasereg = var->inst_basereg;
14724                                                         ins->inst_offset = var->inst_offset;
14725                                                         spec = INS_INFO (ins->opcode);
14726                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE) || (ins->opcode == OP_RMOVE))) {
14727                                                         ins->opcode = store_opcode;
14728                                                         ins->inst_destbasereg = var->inst_basereg;
14729                                                         ins->inst_offset = var->inst_offset;
14730
14731                                                         no_lvreg = TRUE;
14732
14733                                                         tmp_reg = ins->dreg;
14734                                                         ins->dreg = ins->sreg2;
14735                                                         ins->sreg2 = tmp_reg;
14736                                                         store = TRUE;
14737
14738                                                         spec2 [MONO_INST_DEST] = ' ';
14739                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14740                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14741                                                         spec2 [MONO_INST_SRC3] = ' ';
14742                                                         spec = spec2;
14743                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
14744                                                         // FIXME: The backends expect the base reg to be in inst_basereg
14745                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
14746                                                         ins->dreg = -1;
14747                                                         ins->inst_basereg = var->inst_basereg;
14748                                                         ins->inst_offset = var->inst_offset;
14749                                                         spec = INS_INFO (ins->opcode);
14750                                                 } else {
14751                                                         /* printf ("INS: "); mono_print_ins (ins); */
14752                                                         /* Create a store instruction */
14753                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
14754
14755                                                         /* Insert it after the instruction */
14756                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
14757
14758                                                         def_ins = store_ins;
14759
14760                                                         /* 
14761                                                          * We can't assign ins->dreg to var->dreg here, since the
14762                                                          * sregs could use it. So set a flag, and do it after
14763                                                          * the sregs.
14764                                                          */
14765                                                         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)))
14766                                                                 dest_has_lvreg = TRUE;
14767                                                 }
14768                                         }
14769                                 }
14770
14771                                 if (def_ins && !live_range_start [dreg]) {
14772                                         live_range_start [dreg] = def_ins;
14773                                         live_range_start_bb [dreg] = bb;
14774                                 }
14775
14776                                 if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) {
14777                                         MonoInst *tmp;
14778
14779                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
14780                                         tmp->inst_c1 = dreg;
14781                                         mono_bblock_insert_after_ins (bb, def_ins, tmp);
14782                                 }
14783                         }
14784
14785                         /************/
14786                         /*  SREGS   */
14787                         /************/
14788                         num_sregs = mono_inst_get_src_registers (ins, sregs);
14789                         for (srcindex = 0; srcindex < 3; ++srcindex) {
14790                                 regtype = spec [MONO_INST_SRC1 + srcindex];
14791                                 sreg = sregs [srcindex];
14792
14793                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
14794                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
14795                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
14796                                         MonoInst *use_ins = ins;
14797                                         MonoInst *load_ins;
14798                                         guint32 load_opcode;
14799
14800                                         if (var->opcode == OP_REGVAR) {
14801                                                 sregs [srcindex] = var->dreg;
14802                                                 //mono_inst_set_src_registers (ins, sregs);
14803                                                 live_range_end [sreg] = use_ins;
14804                                                 live_range_end_bb [sreg] = bb;
14805
14806                                                 if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14807                                                         MonoInst *tmp;
14808
14809                                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14810                                                         /* var->dreg is a hreg */
14811                                                         tmp->inst_c1 = sreg;
14812                                                         mono_bblock_insert_after_ins (bb, ins, tmp);
14813                                                 }
14814
14815                                                 continue;
14816                                         }
14817
14818                                         g_assert (var->opcode == OP_REGOFFSET);
14819                                                 
14820                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
14821
14822                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
14823
14824                                         if (vreg_to_lvreg [sreg]) {
14825                                                 g_assert (vreg_to_lvreg [sreg] != -1);
14826
14827                                                 /* The variable is already loaded to an lvreg */
14828                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14829                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
14830                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
14831                                                 //mono_inst_set_src_registers (ins, sregs);
14832                                                 continue;
14833                                         }
14834
14835                                         /* Try to fuse the load into the instruction */
14836                                         if ((srcindex == 0) && (op_to_op_src1_membase (cfg, load_opcode, ins->opcode) != -1)) {
14837                                                 ins->opcode = op_to_op_src1_membase (cfg, load_opcode, ins->opcode);
14838                                                 sregs [0] = var->inst_basereg;
14839                                                 //mono_inst_set_src_registers (ins, sregs);
14840                                                 ins->inst_offset = var->inst_offset;
14841                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (cfg, load_opcode, ins->opcode) != -1)) {
14842                                                 ins->opcode = op_to_op_src2_membase (cfg, load_opcode, ins->opcode);
14843                                                 sregs [1] = var->inst_basereg;
14844                                                 //mono_inst_set_src_registers (ins, sregs);
14845                                                 ins->inst_offset = var->inst_offset;
14846                                         } else {
14847                                                 if (MONO_IS_REAL_MOVE (ins)) {
14848                                                         ins->opcode = OP_NOP;
14849                                                         sreg = ins->dreg;
14850                                                 } else {
14851                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
14852
14853                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
14854
14855                                                         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) {
14856                                                                 if (var->dreg == prev_dreg) {
14857                                                                         /*
14858                                                                          * sreg refers to the value loaded by the load
14859                                                                          * emitted below, but we need to use ins->dreg
14860                                                                          * since it refers to the store emitted earlier.
14861                                                                          */
14862                                                                         sreg = ins->dreg;
14863                                                                 }
14864                                                                 g_assert (sreg != -1);
14865                                                                 vreg_to_lvreg [var->dreg] = sreg;
14866                                                                 g_assert (lvregs_len < 1024);
14867                                                                 lvregs [lvregs_len ++] = var->dreg;
14868                                                         }
14869                                                 }
14870
14871                                                 sregs [srcindex] = sreg;
14872                                                 //mono_inst_set_src_registers (ins, sregs);
14873
14874 #if SIZEOF_REGISTER != 8
14875                                                 if (regtype == 'l') {
14876                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, MONO_LVREG_MS (sreg), var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
14877                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14878                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, MONO_LVREG_LS (sreg), var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
14879                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14880                                                         use_ins = load_ins;
14881                                                 }
14882                                                 else
14883 #endif
14884                                                 {
14885 #if SIZEOF_REGISTER == 4
14886                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
14887 #endif
14888                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
14889                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14890                                                         use_ins = load_ins;
14891                                                 }
14892                                         }
14893
14894                                         if (var->dreg < orig_next_vreg) {
14895                                                 live_range_end [var->dreg] = use_ins;
14896                                                 live_range_end_bb [var->dreg] = bb;
14897                                         }
14898
14899                                         if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14900                                                 MonoInst *tmp;
14901
14902                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14903                                                 tmp->inst_c1 = var->dreg;
14904                                                 mono_bblock_insert_after_ins (bb, ins, tmp);
14905                                         }
14906                                 }
14907                         }
14908                         mono_inst_set_src_registers (ins, sregs);
14909
14910                         if (dest_has_lvreg) {
14911                                 g_assert (ins->dreg != -1);
14912                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
14913                                 g_assert (lvregs_len < 1024);
14914                                 lvregs [lvregs_len ++] = prev_dreg;
14915                                 dest_has_lvreg = FALSE;
14916                         }
14917
14918                         if (store) {
14919                                 tmp_reg = ins->dreg;
14920                                 ins->dreg = ins->sreg2;
14921                                 ins->sreg2 = tmp_reg;
14922                         }
14923
14924                         if (MONO_IS_CALL (ins)) {
14925                                 /* Clear vreg_to_lvreg array */
14926                                 for (i = 0; i < lvregs_len; i++)
14927                                         vreg_to_lvreg [lvregs [i]] = 0;
14928                                 lvregs_len = 0;
14929                         } else if (ins->opcode == OP_NOP) {
14930                                 ins->dreg = -1;
14931                                 MONO_INST_NULLIFY_SREGS (ins);
14932                         }
14933
14934                         if (cfg->verbose_level > 2)
14935                                 mono_print_ins_index (1, ins);
14936                 }
14937
14938                 /* Extend the live range based on the liveness info */
14939                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
14940                         for (i = 0; i < cfg->num_varinfo; i ++) {
14941                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
14942
14943                                 if (vreg_is_volatile (cfg, vi->vreg))
14944                                         /* The liveness info is incomplete */
14945                                         continue;
14946
14947                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
14948                                         /* Live from at least the first ins of this bb */
14949                                         live_range_start [vi->vreg] = bb->code;
14950                                         live_range_start_bb [vi->vreg] = bb;
14951                                 }
14952
14953                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
14954                                         /* Live at least until the last ins of this bb */
14955                                         live_range_end [vi->vreg] = bb->last_ins;
14956                                         live_range_end_bb [vi->vreg] = bb;
14957                                 }
14958                         }
14959                 }
14960         }
14961         
14962         /*
14963          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
14964          * by storing the current native offset into MonoMethodVar->live_range_start/end.
14965          */
14966         if (cfg->backend->have_liverange_ops && cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
14967                 for (i = 0; i < cfg->num_varinfo; ++i) {
14968                         int vreg = MONO_VARINFO (cfg, i)->vreg;
14969                         MonoInst *ins;
14970
14971                         if (live_range_start [vreg]) {
14972                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
14973                                 ins->inst_c0 = i;
14974                                 ins->inst_c1 = vreg;
14975                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
14976                         }
14977                         if (live_range_end [vreg]) {
14978                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
14979                                 ins->inst_c0 = i;
14980                                 ins->inst_c1 = vreg;
14981                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
14982                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
14983                                 else
14984                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
14985                         }
14986                 }
14987         }
14988
14989         if (cfg->gsharedvt_locals_var_ins) {
14990                 /* Nullify if unused */
14991                 cfg->gsharedvt_locals_var_ins->opcode = OP_PCONST;
14992                 cfg->gsharedvt_locals_var_ins->inst_imm = 0;
14993         }
14994
14995         g_free (live_range_start);
14996         g_free (live_range_end);
14997         g_free (live_range_start_bb);
14998         g_free (live_range_end_bb);
14999 }
15000
15001 /**
15002  * FIXME:
15003  * - use 'iadd' instead of 'int_add'
15004  * - handling ovf opcodes: decompose in method_to_ir.
15005  * - unify iregs/fregs
15006  *   -> partly done, the missing parts are:
15007  *   - a more complete unification would involve unifying the hregs as well, so
15008  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
15009  *     would no longer map to the machine hregs, so the code generators would need to
15010  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
15011  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
15012  *     fp/non-fp branches speeds it up by about 15%.
15013  * - use sext/zext opcodes instead of shifts
15014  * - add OP_ICALL
15015  * - get rid of TEMPLOADs if possible and use vregs instead
15016  * - clean up usage of OP_P/OP_ opcodes
15017  * - cleanup usage of DUMMY_USE
15018  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
15019  *   stack
15020  * - set the stack type and allocate a dreg in the EMIT_NEW macros
15021  * - get rid of all the <foo>2 stuff when the new JIT is ready.
15022  * - make sure handle_stack_args () is called before the branch is emitted
15023  * - when the new IR is done, get rid of all unused stuff
15024  * - COMPARE/BEQ as separate instructions or unify them ?
15025  *   - keeping them separate allows specialized compare instructions like
15026  *     compare_imm, compare_membase
15027  *   - most back ends unify fp compare+branch, fp compare+ceq
15028  * - integrate mono_save_args into inline_method
15029  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
15030  * - handle long shift opts on 32 bit platforms somehow: they require 
15031  *   3 sregs (2 for arg1 and 1 for arg2)
15032  * - make byref a 'normal' type.
15033  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
15034  *   variable if needed.
15035  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
15036  *   like inline_method.
15037  * - remove inlining restrictions
15038  * - fix LNEG and enable cfold of INEG
15039  * - generalize x86 optimizations like ldelema as a peephole optimization
15040  * - add store_mem_imm for amd64
15041  * - optimize the loading of the interruption flag in the managed->native wrappers
15042  * - avoid special handling of OP_NOP in passes
15043  * - move code inserting instructions into one function/macro.
15044  * - try a coalescing phase after liveness analysis
15045  * - add float -> vreg conversion + local optimizations on !x86
15046  * - figure out how to handle decomposed branches during optimizations, ie.
15047  *   compare+branch, op_jump_table+op_br etc.
15048  * - promote RuntimeXHandles to vregs
15049  * - vtype cleanups:
15050  *   - add a NEW_VARLOADA_VREG macro
15051  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
15052  *   accessing vtype fields.
15053  * - get rid of I8CONST on 64 bit platforms
15054  * - dealing with the increase in code size due to branches created during opcode
15055  *   decomposition:
15056  *   - use extended basic blocks
15057  *     - all parts of the JIT
15058  *     - handle_global_vregs () && local regalloc
15059  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
15060  * - sources of increase in code size:
15061  *   - vtypes
15062  *   - long compares
15063  *   - isinst and castclass
15064  *   - lvregs not allocated to global registers even if used multiple times
15065  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
15066  *   meaningful.
15067  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
15068  * - add all micro optimizations from the old JIT
15069  * - put tree optimizations into the deadce pass
15070  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
15071  *   specific function.
15072  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
15073  *   fcompare + branchCC.
15074  * - create a helper function for allocating a stack slot, taking into account 
15075  *   MONO_CFG_HAS_SPILLUP.
15076  * - merge r68207.
15077  * - merge the ia64 switch changes.
15078  * - optimize mono_regstate2_alloc_int/float.
15079  * - fix the pessimistic handling of variables accessed in exception handler blocks.
15080  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
15081  *   parts of the tree could be separated by other instructions, killing the tree
15082  *   arguments, or stores killing loads etc. Also, should we fold loads into other
15083  *   instructions if the result of the load is used multiple times ?
15084  * - make the REM_IMM optimization in mini-x86.c arch-independent.
15085  * - LAST MERGE: 108395.
15086  * - when returning vtypes in registers, generate IR and append it to the end of the
15087  *   last bb instead of doing it in the epilog.
15088  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
15089  */
15090
15091 /*
15092
15093 NOTES
15094 -----
15095
15096 - When to decompose opcodes:
15097   - earlier: this makes some optimizations hard to implement, since the low level IR
15098   no longer contains the neccessary information. But it is easier to do.
15099   - later: harder to implement, enables more optimizations.
15100 - Branches inside bblocks:
15101   - created when decomposing complex opcodes. 
15102     - branches to another bblock: harmless, but not tracked by the branch 
15103       optimizations, so need to branch to a label at the start of the bblock.
15104     - branches to inside the same bblock: very problematic, trips up the local
15105       reg allocator. Can be fixed by spitting the current bblock, but that is a
15106       complex operation, since some local vregs can become global vregs etc.
15107 - Local/global vregs:
15108   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
15109     local register allocator.
15110   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
15111     structure, created by mono_create_var (). Assigned to hregs or the stack by
15112     the global register allocator.
15113 - When to do optimizations like alu->alu_imm:
15114   - earlier -> saves work later on since the IR will be smaller/simpler
15115   - later -> can work on more instructions
15116 - Handling of valuetypes:
15117   - When a vtype is pushed on the stack, a new temporary is created, an 
15118     instruction computing its address (LDADDR) is emitted and pushed on
15119     the stack. Need to optimize cases when the vtype is used immediately as in
15120     argument passing, stloc etc.
15121 - Instead of the to_end stuff in the old JIT, simply call the function handling
15122   the values on the stack before emitting the last instruction of the bb.
15123 */
15124
15125 #endif /* DISABLE_JIT */