87dad9d0c6fa56137e7524682ab406c4dda1a374
[mono.git] / mono / mini / method-to-ir.c
1 /*
2  * method-to-ir.c: Convert CIL to the JIT internal representation
3  *
4  * Author:
5  *   Paolo Molaro (lupus@ximian.com)
6  *   Dietmar Maurer (dietmar@ximian.com)
7  *
8  * (C) 2002 Ximian, Inc.
9  * Copyright 2003-2010 Novell, Inc (http://www.novell.com)
10  * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
11  */
12
13 #include <config.h>
14
15 #ifndef DISABLE_JIT
16
17 #include <signal.h>
18
19 #ifdef HAVE_UNISTD_H
20 #include <unistd.h>
21 #endif
22
23 #include <math.h>
24 #include <string.h>
25 #include <ctype.h>
26
27 #ifdef HAVE_SYS_TIME_H
28 #include <sys/time.h>
29 #endif
30
31 #ifdef HAVE_ALLOCA_H
32 #include <alloca.h>
33 #endif
34
35 #include <mono/utils/memcheck.h>
36 #include "mini.h"
37 #include <mono/metadata/abi-details.h>
38 #include <mono/metadata/assembly.h>
39 #include <mono/metadata/attrdefs.h>
40 #include <mono/metadata/loader.h>
41 #include <mono/metadata/tabledefs.h>
42 #include <mono/metadata/class.h>
43 #include <mono/metadata/object.h>
44 #include <mono/metadata/exception.h>
45 #include <mono/metadata/opcodes.h>
46 #include <mono/metadata/mono-endian.h>
47 #include <mono/metadata/tokentype.h>
48 #include <mono/metadata/tabledefs.h>
49 #include <mono/metadata/marshal.h>
50 #include <mono/metadata/debug-helpers.h>
51 #include <mono/metadata/mono-debug.h>
52 #include <mono/metadata/mono-debug-debugger.h>
53 #include <mono/metadata/gc-internals.h>
54 #include <mono/metadata/security-manager.h>
55 #include <mono/metadata/threads-types.h>
56 #include <mono/metadata/security-core-clr.h>
57 #include <mono/metadata/profiler-private.h>
58 #include <mono/metadata/profiler.h>
59 #include <mono/metadata/monitor.h>
60 #include <mono/metadata/debug-mono-symfile.h>
61 #include <mono/utils/mono-compiler.h>
62 #include <mono/utils/mono-memory-model.h>
63 #include <mono/utils/mono-error-internals.h>
64 #include <mono/metadata/mono-basic-block.h>
65 #include <mono/metadata/reflection-internals.h>
66
67 #include "trace.h"
68
69 #include "ir-emit.h"
70
71 #include "jit-icalls.h"
72 #include "jit.h"
73 #include "debugger-agent.h"
74 #include "seq-points.h"
75 #include "aot-compiler.h"
76 #include "mini-llvm.h"
77
78 #define BRANCH_COST 10
79 #define INLINE_LENGTH_LIMIT 20
80
81 /* These have 'cfg' as an implicit argument */
82 #define INLINE_FAILURE(msg) do {                                                                        \
83         if ((cfg->method != cfg->current_method) && (cfg->current_method->wrapper_type == MONO_WRAPPER_NONE)) { \
84                 inline_failure (cfg, msg);                                                                              \
85                 goto exception_exit;                                                                                    \
86         } \
87         } while (0)
88 #define CHECK_CFG_EXCEPTION do {\
89                 if (cfg->exception_type != MONO_EXCEPTION_NONE) \
90                         goto exception_exit;                                            \
91         } while (0)
92 #define METHOD_ACCESS_FAILURE(method, cmethod) do {                     \
93                 method_access_failure ((cfg), (method), (cmethod));                     \
94                 goto exception_exit;                                                                            \
95         } while (0)
96 #define FIELD_ACCESS_FAILURE(method, field) do {                                        \
97                 field_access_failure ((cfg), (method), (field));                        \
98                 goto exception_exit;    \
99         } while (0)
100 #define GENERIC_SHARING_FAILURE(opcode) do {            \
101                 if (cfg->gshared) {                                                                     \
102                         gshared_failure (cfg, opcode, __FILE__, __LINE__);      \
103                         goto exception_exit;    \
104                 }                       \
105         } while (0)
106 #define GSHAREDVT_FAILURE(opcode) do {          \
107         if (cfg->gsharedvt) {                                                                                           \
108                 gsharedvt_failure (cfg, opcode, __FILE__, __LINE__);                    \
109                 goto exception_exit;                                                                                    \
110         }                                                                                                                                       \
111         } while (0)
112 #define OUT_OF_MEMORY_FAILURE do {      \
113                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);                \
114                 mono_error_set_out_of_memory (&cfg->error, "");                                 \
115                 goto exception_exit;    \
116         } while (0)
117 #define DISABLE_AOT(cfg) do { \
118                 if ((cfg)->verbose_level >= 2)                                            \
119                         printf ("AOT disabled: %s:%d\n", __FILE__, __LINE__);   \
120                 (cfg)->disable_aot = TRUE;                                                        \
121         } while (0)
122 #define LOAD_ERROR do { \
123                 break_on_unverified ();                                                         \
124                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD); \
125                 goto exception_exit;                                                                    \
126         } while (0)
127
128 #define TYPE_LOAD_ERROR(klass) do { \
129                 cfg->exception_ptr = klass; \
130                 LOAD_ERROR;                                     \
131         } while (0)
132
133 #define CHECK_CFG_ERROR do {\
134                 if (!mono_error_ok (&cfg->error)) { \
135                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);        \
136                         goto mono_error_exit; \
137                 } \
138         } while (0)
139
140 /* Determine whenever 'ins' represents a load of the 'this' argument */
141 #define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && ((ins)->opcode == OP_MOVE) && ((ins)->sreg1 == cfg->args [0]->dreg))
142
143 static int ldind_to_load_membase (int opcode);
144 static int stind_to_store_membase (int opcode);
145
146 int mono_op_to_op_imm (int opcode);
147 int mono_op_to_op_imm_noemul (int opcode);
148
149 MONO_API MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
150
151 static int inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
152                                                   guchar *ip, guint real_offset, gboolean inline_always);
153 static MonoInst*
154 emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used, MonoInst **sp);
155
156 /* helper methods signatures */
157 static MonoMethodSignature *helper_sig_domain_get;
158 static MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline;
159 static MonoMethodSignature *helper_sig_llvmonly_imt_thunk;
160
161
162 /* type loading helpers */
163 static GENERATE_GET_CLASS_WITH_CACHE (runtime_helpers, System.Runtime.CompilerServices, RuntimeHelpers)
164 static GENERATE_TRY_GET_CLASS_WITH_CACHE (debuggable_attribute, System.Diagnostics, DebuggableAttribute)
165
166 /*
167  * Instruction metadata
168  */
169 #ifdef MINI_OP
170 #undef MINI_OP
171 #endif
172 #ifdef MINI_OP3
173 #undef MINI_OP3
174 #endif
175 #define MINI_OP(a,b,dest,src1,src2) dest, src1, src2, ' ',
176 #define MINI_OP3(a,b,dest,src1,src2,src3) dest, src1, src2, src3,
177 #define NONE ' '
178 #define IREG 'i'
179 #define FREG 'f'
180 #define VREG 'v'
181 #define XREG 'x'
182 #if SIZEOF_REGISTER == 8 && SIZEOF_REGISTER == SIZEOF_VOID_P
183 #define LREG IREG
184 #else
185 #define LREG 'l'
186 #endif
187 /* keep in sync with the enum in mini.h */
188 const char
189 ins_info[] = {
190 #include "mini-ops.h"
191 };
192 #undef MINI_OP
193 #undef MINI_OP3
194
195 #define MINI_OP(a,b,dest,src1,src2) ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0)),
196 #define MINI_OP3(a,b,dest,src1,src2,src3) ((src3) != NONE ? 3 : ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0))),
197 /* 
198  * This should contain the index of the last sreg + 1. This is not the same
199  * as the number of sregs for opcodes like IA64_CMP_EQ_IMM.
200  */
201 const gint8 ins_sreg_counts[] = {
202 #include "mini-ops.h"
203 };
204 #undef MINI_OP
205 #undef MINI_OP3
206
207 #define MONO_INIT_VARINFO(vi,id) do { \
208         (vi)->range.first_use.pos.bid = 0xffff; \
209         (vi)->reg = -1; \
210         (vi)->idx = (id); \
211 } while (0)
212
213 guint32
214 mono_alloc_ireg (MonoCompile *cfg)
215 {
216         return alloc_ireg (cfg);
217 }
218
219 guint32
220 mono_alloc_lreg (MonoCompile *cfg)
221 {
222         return alloc_lreg (cfg);
223 }
224
225 guint32
226 mono_alloc_freg (MonoCompile *cfg)
227 {
228         return alloc_freg (cfg);
229 }
230
231 guint32
232 mono_alloc_preg (MonoCompile *cfg)
233 {
234         return alloc_preg (cfg);
235 }
236
237 guint32
238 mono_alloc_dreg (MonoCompile *cfg, MonoStackType stack_type)
239 {
240         return alloc_dreg (cfg, stack_type);
241 }
242
243 /*
244  * mono_alloc_ireg_ref:
245  *
246  *   Allocate an IREG, and mark it as holding a GC ref.
247  */
248 guint32
249 mono_alloc_ireg_ref (MonoCompile *cfg)
250 {
251         return alloc_ireg_ref (cfg);
252 }
253
254 /*
255  * mono_alloc_ireg_mp:
256  *
257  *   Allocate an IREG, and mark it as holding a managed pointer.
258  */
259 guint32
260 mono_alloc_ireg_mp (MonoCompile *cfg)
261 {
262         return alloc_ireg_mp (cfg);
263 }
264
265 /*
266  * mono_alloc_ireg_copy:
267  *
268  *   Allocate an IREG with the same GC type as VREG.
269  */
270 guint32
271 mono_alloc_ireg_copy (MonoCompile *cfg, guint32 vreg)
272 {
273         if (vreg_is_ref (cfg, vreg))
274                 return alloc_ireg_ref (cfg);
275         else if (vreg_is_mp (cfg, vreg))
276                 return alloc_ireg_mp (cfg);
277         else
278                 return alloc_ireg (cfg);
279 }
280
281 guint
282 mono_type_to_regmove (MonoCompile *cfg, MonoType *type)
283 {
284         if (type->byref)
285                 return OP_MOVE;
286
287         type = mini_get_underlying_type (type);
288 handle_enum:
289         switch (type->type) {
290         case MONO_TYPE_I1:
291         case MONO_TYPE_U1:
292                 return OP_MOVE;
293         case MONO_TYPE_I2:
294         case MONO_TYPE_U2:
295                 return OP_MOVE;
296         case MONO_TYPE_I4:
297         case MONO_TYPE_U4:
298                 return OP_MOVE;
299         case MONO_TYPE_I:
300         case MONO_TYPE_U:
301         case MONO_TYPE_PTR:
302         case MONO_TYPE_FNPTR:
303                 return OP_MOVE;
304         case MONO_TYPE_CLASS:
305         case MONO_TYPE_STRING:
306         case MONO_TYPE_OBJECT:
307         case MONO_TYPE_SZARRAY:
308         case MONO_TYPE_ARRAY:    
309                 return OP_MOVE;
310         case MONO_TYPE_I8:
311         case MONO_TYPE_U8:
312 #if SIZEOF_REGISTER == 8
313                 return OP_MOVE;
314 #else
315                 return OP_LMOVE;
316 #endif
317         case MONO_TYPE_R4:
318                 return cfg->r4fp ? OP_RMOVE : OP_FMOVE;
319         case MONO_TYPE_R8:
320                 return OP_FMOVE;
321         case MONO_TYPE_VALUETYPE:
322                 if (type->data.klass->enumtype) {
323                         type = mono_class_enum_basetype (type->data.klass);
324                         goto handle_enum;
325                 }
326                 if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
327                         return OP_XMOVE;
328                 return OP_VMOVE;
329         case MONO_TYPE_TYPEDBYREF:
330                 return OP_VMOVE;
331         case MONO_TYPE_GENERICINST:
332                 type = &type->data.generic_class->container_class->byval_arg;
333                 goto handle_enum;
334         case MONO_TYPE_VAR:
335         case MONO_TYPE_MVAR:
336                 g_assert (cfg->gshared);
337                 if (mini_type_var_is_vt (type))
338                         return OP_VMOVE;
339                 else
340                         return mono_type_to_regmove (cfg, mini_get_underlying_type (type));
341         default:
342                 g_error ("unknown type 0x%02x in type_to_regstore", type->type);
343         }
344         return -1;
345 }
346
347 void
348 mono_print_bb (MonoBasicBlock *bb, const char *msg)
349 {
350         int i;
351         MonoInst *tree;
352
353         printf ("\n%s %d: [IN: ", msg, bb->block_num);
354         for (i = 0; i < bb->in_count; ++i)
355                 printf (" BB%d(%d)", bb->in_bb [i]->block_num, bb->in_bb [i]->dfn);
356         printf (", OUT: ");
357         for (i = 0; i < bb->out_count; ++i)
358                 printf (" BB%d(%d)", bb->out_bb [i]->block_num, bb->out_bb [i]->dfn);
359         printf (" ]\n");
360         for (tree = bb->code; tree; tree = tree->next)
361                 mono_print_ins_index (-1, tree);
362 }
363
364 void
365 mono_create_helper_signatures (void)
366 {
367         helper_sig_domain_get = mono_create_icall_signature ("ptr");
368         helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
369         helper_sig_llvmonly_imt_thunk = mono_create_icall_signature ("ptr ptr ptr");
370 }
371
372 static MONO_NEVER_INLINE void
373 break_on_unverified (void)
374 {
375         if (mini_get_debug_options ()->break_on_unverified)
376                 G_BREAKPOINT ();
377 }
378
379 static MONO_NEVER_INLINE void
380 method_access_failure (MonoCompile *cfg, MonoMethod *method, MonoMethod *cil_method)
381 {
382         char *method_fname = mono_method_full_name (method, TRUE);
383         char *cil_method_fname = mono_method_full_name (cil_method, TRUE);
384         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
385         mono_error_set_generic_error (&cfg->error, "System", "MethodAccessException", "Method `%s' is inaccessible from method `%s'\n", cil_method_fname, method_fname);
386         g_free (method_fname);
387         g_free (cil_method_fname);
388 }
389
390 static MONO_NEVER_INLINE void
391 field_access_failure (MonoCompile *cfg, MonoMethod *method, MonoClassField *field)
392 {
393         char *method_fname = mono_method_full_name (method, TRUE);
394         char *field_fname = mono_field_full_name (field);
395         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
396         mono_error_set_generic_error (&cfg->error, "System", "FieldAccessException", "Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname);
397         g_free (method_fname);
398         g_free (field_fname);
399 }
400
401 static MONO_NEVER_INLINE void
402 inline_failure (MonoCompile *cfg, const char *msg)
403 {
404         if (cfg->verbose_level >= 2)
405                 printf ("inline failed: %s\n", msg);
406         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INLINE_FAILED);
407 }
408
409 static MONO_NEVER_INLINE void
410 gshared_failure (MonoCompile *cfg, int opcode, const char *file, int line)
411 {
412         if (cfg->verbose_level > 2)                                                                                     \
413                 printf ("sharing failed for method %s.%s.%s/%d opcode %s line %d\n", cfg->current_method->klass->name_space, cfg->current_method->klass->name, cfg->current_method->name, cfg->current_method->signature->param_count, mono_opcode_name ((opcode)), line);
414         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
415 }
416
417 static MONO_NEVER_INLINE void
418 gsharedvt_failure (MonoCompile *cfg, int opcode, const char *file, int line)
419 {
420         cfg->exception_message = g_strdup_printf ("gsharedvt failed for method %s.%s.%s/%d opcode %s %s:%d", cfg->current_method->klass->name_space, cfg->current_method->klass->name, cfg->current_method->name, cfg->current_method->signature->param_count, mono_opcode_name ((opcode)), file, line);
421         if (cfg->verbose_level >= 2)
422                 printf ("%s\n", cfg->exception_message);
423         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
424 }
425
426 /*
427  * When using gsharedvt, some instatiations might be verifiable, and some might be not. i.e. 
428  * foo<T> (int i) { ldarg.0; box T; }
429  */
430 #define UNVERIFIED do { \
431         if (cfg->gsharedvt) { \
432                 if (cfg->verbose_level > 2)                                                                     \
433                         printf ("gsharedvt method failed to verify, falling back to instantiation.\n"); \
434                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED); \
435                 goto exception_exit;                                                                                    \
436         }                                                                                                                                       \
437         break_on_unverified ();                                                                                         \
438         goto unverified;                                                                                                        \
439 } while (0)
440
441 #define GET_BBLOCK(cfg,tblock,ip) do {  \
442                 (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
443                 if (!(tblock)) {        \
444                         if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
445             NEW_BBLOCK (cfg, (tblock)); \
446                         (tblock)->cil_code = (ip);      \
447                         ADD_BBLOCK (cfg, (tblock));     \
448                 } \
449         } while (0)
450
451 #if defined(TARGET_X86) || defined(TARGET_AMD64)
452 #define EMIT_NEW_X86_LEA(cfg,dest,sr1,sr2,shift,imm) do { \
453                 MONO_INST_NEW (cfg, dest, OP_X86_LEA); \
454                 (dest)->dreg = alloc_ireg_mp ((cfg)); \
455                 (dest)->sreg1 = (sr1); \
456                 (dest)->sreg2 = (sr2); \
457                 (dest)->inst_imm = (imm); \
458                 (dest)->backend.shift_amount = (shift); \
459                 MONO_ADD_INS ((cfg)->cbb, (dest)); \
460         } while (0)
461 #endif
462
463 /* Emit conversions so both operands of a binary opcode are of the same type */
464 static void
465 add_widen_op (MonoCompile *cfg, MonoInst *ins, MonoInst **arg1_ref, MonoInst **arg2_ref)
466 {
467         MonoInst *arg1 = *arg1_ref;
468         MonoInst *arg2 = *arg2_ref;
469
470         if (cfg->r4fp &&
471                 ((arg1->type == STACK_R4 && arg2->type == STACK_R8) ||
472                  (arg1->type == STACK_R8 && arg2->type == STACK_R4))) {
473                 MonoInst *conv;
474
475                 /* Mixing r4/r8 is allowed by the spec */
476                 if (arg1->type == STACK_R4) {
477                         int dreg = alloc_freg (cfg);
478
479                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg1->dreg);
480                         conv->type = STACK_R8;
481                         ins->sreg1 = dreg;
482                         *arg1_ref = conv;
483                 }
484                 if (arg2->type == STACK_R4) {
485                         int dreg = alloc_freg (cfg);
486
487                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg2->dreg);
488                         conv->type = STACK_R8;
489                         ins->sreg2 = dreg;
490                         *arg2_ref = conv;
491                 }
492         }
493
494 #if SIZEOF_REGISTER == 8
495         /* FIXME: Need to add many more cases */
496         if ((arg1)->type == STACK_PTR && (arg2)->type == STACK_I4) {
497                 MonoInst *widen;
498
499                 int dr = alloc_preg (cfg);
500                 EMIT_NEW_UNALU (cfg, widen, OP_SEXT_I4, dr, (arg2)->dreg);
501                 (ins)->sreg2 = widen->dreg;
502         }
503 #endif
504 }
505
506 #define ADD_BINOP(op) do {      \
507                 MONO_INST_NEW (cfg, ins, (op)); \
508                 sp -= 2;        \
509                 ins->sreg1 = sp [0]->dreg;      \
510                 ins->sreg2 = sp [1]->dreg;      \
511                 type_from_op (cfg, ins, sp [0], sp [1]);        \
512                 CHECK_TYPE (ins);       \
513                 /* Have to insert a widening op */               \
514         add_widen_op (cfg, ins, &sp [0], &sp [1]);               \
515         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type); \
516         MONO_ADD_INS ((cfg)->cbb, (ins)); \
517         *sp++ = mono_decompose_opcode ((cfg), (ins));   \
518         } while (0)
519
520 #define ADD_UNOP(op) do {       \
521                 MONO_INST_NEW (cfg, ins, (op)); \
522                 sp--;   \
523                 ins->sreg1 = sp [0]->dreg;      \
524                 type_from_op (cfg, ins, sp [0], NULL);  \
525                 CHECK_TYPE (ins);       \
526         (ins)->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type); \
527         MONO_ADD_INS ((cfg)->cbb, (ins)); \
528                 *sp++ = mono_decompose_opcode (cfg, ins);       \
529         } while (0)
530
531 #define ADD_BINCOND(next_block) do {    \
532                 MonoInst *cmp;  \
533                 sp -= 2; \
534                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
535                 cmp->sreg1 = sp [0]->dreg;      \
536                 cmp->sreg2 = sp [1]->dreg;      \
537                 type_from_op (cfg, cmp, sp [0], sp [1]);        \
538                 CHECK_TYPE (cmp);       \
539                 add_widen_op (cfg, cmp, &sp [0], &sp [1]);                                              \
540                 type_from_op (cfg, ins, sp [0], sp [1]);                                                        \
541                 ins->inst_many_bb = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);   \
542                 GET_BBLOCK (cfg, tblock, target);               \
543                 link_bblock (cfg, cfg->cbb, tblock);    \
544                 ins->inst_true_bb = tblock;     \
545                 if ((next_block)) {     \
546                         link_bblock (cfg, cfg->cbb, (next_block));      \
547                         ins->inst_false_bb = (next_block);      \
548                         start_new_bblock = 1;   \
549                 } else {        \
550                         GET_BBLOCK (cfg, tblock, ip);           \
551                         link_bblock (cfg, cfg->cbb, tblock);    \
552                         ins->inst_false_bb = tblock;    \
553                         start_new_bblock = 2;   \
554                 }       \
555                 if (sp != stack_start) {                                                                        \
556                     handle_stack_args (cfg, stack_start, sp - stack_start); \
557                         CHECK_UNVERIFIABLE (cfg); \
558                 } \
559         MONO_ADD_INS (cfg->cbb, cmp); \
560                 MONO_ADD_INS (cfg->cbb, ins);   \
561         } while (0)
562
563 /* *
564  * link_bblock: Links two basic blocks
565  *
566  * links two basic blocks in the control flow graph, the 'from'
567  * argument is the starting block and the 'to' argument is the block
568  * the control flow ends to after 'from'.
569  */
570 static void
571 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
572 {
573         MonoBasicBlock **newa;
574         int i, found;
575
576 #if 0
577         if (from->cil_code) {
578                 if (to->cil_code)
579                         printf ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
580                 else
581                         printf ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
582         } else {
583                 if (to->cil_code)
584                         printf ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
585                 else
586                         printf ("edge from entry to exit\n");
587         }
588 #endif
589
590         found = FALSE;
591         for (i = 0; i < from->out_count; ++i) {
592                 if (to == from->out_bb [i]) {
593                         found = TRUE;
594                         break;
595                 }
596         }
597         if (!found) {
598                 newa = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
599                 for (i = 0; i < from->out_count; ++i) {
600                         newa [i] = from->out_bb [i];
601                 }
602                 newa [i] = to;
603                 from->out_count++;
604                 from->out_bb = newa;
605         }
606
607         found = FALSE;
608         for (i = 0; i < to->in_count; ++i) {
609                 if (from == to->in_bb [i]) {
610                         found = TRUE;
611                         break;
612                 }
613         }
614         if (!found) {
615                 newa = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
616                 for (i = 0; i < to->in_count; ++i) {
617                         newa [i] = to->in_bb [i];
618                 }
619                 newa [i] = from;
620                 to->in_count++;
621                 to->in_bb = newa;
622         }
623 }
624
625 void
626 mono_link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
627 {
628         link_bblock (cfg, from, to);
629 }
630
631 /**
632  * mono_find_block_region:
633  *
634  *   We mark each basic block with a region ID. We use that to avoid BB
635  *   optimizations when blocks are in different regions.
636  *
637  * Returns:
638  *   A region token that encodes where this region is, and information
639  *   about the clause owner for this block.
640  *
641  *   The region encodes the try/catch/filter clause that owns this block
642  *   as well as the type.  -1 is a special value that represents a block
643  *   that is in none of try/catch/filter.
644  */
645 static int
646 mono_find_block_region (MonoCompile *cfg, int offset)
647 {
648         MonoMethodHeader *header = cfg->header;
649         MonoExceptionClause *clause;
650         int i;
651
652         for (i = 0; i < header->num_clauses; ++i) {
653                 clause = &header->clauses [i];
654                 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
655                     (offset < (clause->handler_offset)))
656                         return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
657                            
658                 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
659                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
660                                 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
661                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
662                                 return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
663                         else
664                                 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
665                 }
666         }
667         for (i = 0; i < header->num_clauses; ++i) {
668                 clause = &header->clauses [i];
669
670                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
671                         return ((i + 1) << 8) | clause->flags;
672         }
673
674         return -1;
675 }
676
677 static GList*
678 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
679 {
680         MonoMethodHeader *header = cfg->header;
681         MonoExceptionClause *clause;
682         int i;
683         GList *res = NULL;
684
685         for (i = 0; i < header->num_clauses; ++i) {
686                 clause = &header->clauses [i];
687                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
688                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
689                         if (clause->flags == type)
690                                 res = g_list_append (res, clause);
691                 }
692         }
693         return res;
694 }
695
696 static void
697 mono_create_spvar_for_region (MonoCompile *cfg, int region)
698 {
699         MonoInst *var;
700
701         var = (MonoInst *)g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
702         if (var)
703                 return;
704
705         var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
706         /* prevent it from being register allocated */
707         var->flags |= MONO_INST_VOLATILE;
708
709         g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
710 }
711
712 MonoInst *
713 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
714 {
715         return (MonoInst *)g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
716 }
717
718 static MonoInst*
719 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
720 {
721         MonoInst *var;
722
723         var = (MonoInst *)g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
724         if (var)
725                 return var;
726
727         var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
728         /* prevent it from being register allocated */
729         var->flags |= MONO_INST_VOLATILE;
730
731         g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
732
733         return var;
734 }
735
736 /*
737  * Returns the type used in the eval stack when @type is loaded.
738  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
739  */
740 void
741 type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
742 {
743         MonoClass *klass;
744
745         type = mini_get_underlying_type (type);
746         inst->klass = klass = mono_class_from_mono_type (type);
747         if (type->byref) {
748                 inst->type = STACK_MP;
749                 return;
750         }
751
752 handle_enum:
753         switch (type->type) {
754         case MONO_TYPE_VOID:
755                 inst->type = STACK_INV;
756                 return;
757         case MONO_TYPE_I1:
758         case MONO_TYPE_U1:
759         case MONO_TYPE_I2:
760         case MONO_TYPE_U2:
761         case MONO_TYPE_I4:
762         case MONO_TYPE_U4:
763                 inst->type = STACK_I4;
764                 return;
765         case MONO_TYPE_I:
766         case MONO_TYPE_U:
767         case MONO_TYPE_PTR:
768         case MONO_TYPE_FNPTR:
769                 inst->type = STACK_PTR;
770                 return;
771         case MONO_TYPE_CLASS:
772         case MONO_TYPE_STRING:
773         case MONO_TYPE_OBJECT:
774         case MONO_TYPE_SZARRAY:
775         case MONO_TYPE_ARRAY:    
776                 inst->type = STACK_OBJ;
777                 return;
778         case MONO_TYPE_I8:
779         case MONO_TYPE_U8:
780                 inst->type = STACK_I8;
781                 return;
782         case MONO_TYPE_R4:
783                 inst->type = cfg->r4_stack_type;
784                 break;
785         case MONO_TYPE_R8:
786                 inst->type = STACK_R8;
787                 return;
788         case MONO_TYPE_VALUETYPE:
789                 if (type->data.klass->enumtype) {
790                         type = mono_class_enum_basetype (type->data.klass);
791                         goto handle_enum;
792                 } else {
793                         inst->klass = klass;
794                         inst->type = STACK_VTYPE;
795                         return;
796                 }
797         case MONO_TYPE_TYPEDBYREF:
798                 inst->klass = mono_defaults.typed_reference_class;
799                 inst->type = STACK_VTYPE;
800                 return;
801         case MONO_TYPE_GENERICINST:
802                 type = &type->data.generic_class->container_class->byval_arg;
803                 goto handle_enum;
804         case MONO_TYPE_VAR:
805         case MONO_TYPE_MVAR:
806                 g_assert (cfg->gshared);
807                 if (mini_is_gsharedvt_type (type)) {
808                         g_assert (cfg->gsharedvt);
809                         inst->type = STACK_VTYPE;
810                 } else {
811                         type_to_eval_stack_type (cfg, mini_get_underlying_type (type), inst);
812                 }
813                 return;
814         default:
815                 g_error ("unknown type 0x%02x in eval stack type", type->type);
816         }
817 }
818
819 /*
820  * The following tables are used to quickly validate the IL code in type_from_op ().
821  */
822 static const char
823 bin_num_table [STACK_MAX] [STACK_MAX] = {
824         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
825         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
826         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
827         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
828         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV, STACK_R8},
829         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
830         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
831         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
832         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4}
833 };
834
835 static const char 
836 neg_table [] = {
837         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4
838 };
839
840 /* reduce the size of this table */
841 static const char
842 bin_int_table [STACK_MAX] [STACK_MAX] = {
843         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
844         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
845         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
846         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
847         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
848         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
849         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
850         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
851 };
852
853 static const char
854 bin_comp_table [STACK_MAX] [STACK_MAX] = {
855 /*      Inv i  L  p  F  &  O  vt r4 */
856         {0},
857         {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
858         {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
859         {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
860         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* F, R8 */
861         {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
862         {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
863         {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
864         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* r, r4 */
865 };
866
867 /* reduce the size of this table */
868 static const char
869 shift_table [STACK_MAX] [STACK_MAX] = {
870         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
871         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
872         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
873         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
874         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
875         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
876         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
877         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
878 };
879
880 /*
881  * Tables to map from the non-specific opcode to the matching
882  * type-specific opcode.
883  */
884 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
885 static const guint16
886 binops_op_map [STACK_MAX] = {
887         0, OP_IADD-CEE_ADD, OP_LADD-CEE_ADD, OP_PADD-CEE_ADD, OP_FADD-CEE_ADD, OP_PADD-CEE_ADD, 0, 0, OP_RADD-CEE_ADD
888 };
889
890 /* handles from CEE_NEG to CEE_CONV_U8 */
891 static const guint16
892 unops_op_map [STACK_MAX] = {
893         0, OP_INEG-CEE_NEG, OP_LNEG-CEE_NEG, OP_PNEG-CEE_NEG, OP_FNEG-CEE_NEG, OP_PNEG-CEE_NEG, 0, 0, OP_RNEG-CEE_NEG
894 };
895
896 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
897 static const guint16
898 ovfops_op_map [STACK_MAX] = {
899         0, OP_ICONV_TO_U2-CEE_CONV_U2, OP_LCONV_TO_U2-CEE_CONV_U2, OP_PCONV_TO_U2-CEE_CONV_U2, OP_FCONV_TO_U2-CEE_CONV_U2, OP_PCONV_TO_U2-CEE_CONV_U2, OP_PCONV_TO_U2-CEE_CONV_U2, 0, OP_RCONV_TO_U2-CEE_CONV_U2
900 };
901
902 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
903 static const guint16
904 ovf2ops_op_map [STACK_MAX] = {
905         0, OP_ICONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, OP_LCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, OP_PCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, OP_FCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, OP_PCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, 0, 0, OP_RCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN
906 };
907
908 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
909 static const guint16
910 ovf3ops_op_map [STACK_MAX] = {
911         0, OP_ICONV_TO_OVF_I1-CEE_CONV_OVF_I1, OP_LCONV_TO_OVF_I1-CEE_CONV_OVF_I1, OP_PCONV_TO_OVF_I1-CEE_CONV_OVF_I1, OP_FCONV_TO_OVF_I1-CEE_CONV_OVF_I1, OP_PCONV_TO_OVF_I1-CEE_CONV_OVF_I1, 0, 0, OP_RCONV_TO_OVF_I1-CEE_CONV_OVF_I1
912 };
913
914 /* handles from CEE_BEQ to CEE_BLT_UN */
915 static const guint16
916 beqops_op_map [STACK_MAX] = {
917         0, OP_IBEQ-CEE_BEQ, OP_LBEQ-CEE_BEQ, OP_PBEQ-CEE_BEQ, OP_FBEQ-CEE_BEQ, OP_PBEQ-CEE_BEQ, OP_PBEQ-CEE_BEQ, 0, OP_FBEQ-CEE_BEQ
918 };
919
920 /* handles from CEE_CEQ to CEE_CLT_UN */
921 static const guint16
922 ceqops_op_map [STACK_MAX] = {
923         0, OP_ICEQ-OP_CEQ, OP_LCEQ-OP_CEQ, OP_PCEQ-OP_CEQ, OP_FCEQ-OP_CEQ, OP_PCEQ-OP_CEQ, OP_PCEQ-OP_CEQ, 0, OP_RCEQ-OP_CEQ
924 };
925
926 /*
927  * Sets ins->type (the type on the eval stack) according to the
928  * type of the opcode and the arguments to it.
929  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
930  *
931  * FIXME: this function sets ins->type unconditionally in some cases, but
932  * it should set it to invalid for some types (a conv.x on an object)
933  */
934 static void
935 type_from_op (MonoCompile *cfg, MonoInst *ins, MonoInst *src1, MonoInst *src2)
936 {
937         switch (ins->opcode) {
938         /* binops */
939         case CEE_ADD:
940         case CEE_SUB:
941         case CEE_MUL:
942         case CEE_DIV:
943         case CEE_REM:
944                 /* FIXME: check unverifiable args for STACK_MP */
945                 ins->type = bin_num_table [src1->type] [src2->type];
946                 ins->opcode += binops_op_map [ins->type];
947                 break;
948         case CEE_DIV_UN:
949         case CEE_REM_UN:
950         case CEE_AND:
951         case CEE_OR:
952         case CEE_XOR:
953                 ins->type = bin_int_table [src1->type] [src2->type];
954                 ins->opcode += binops_op_map [ins->type];
955                 break;
956         case CEE_SHL:
957         case CEE_SHR:
958         case CEE_SHR_UN:
959                 ins->type = shift_table [src1->type] [src2->type];
960                 ins->opcode += binops_op_map [ins->type];
961                 break;
962         case OP_COMPARE:
963         case OP_LCOMPARE:
964         case OP_ICOMPARE:
965                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
966                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
967                         ins->opcode = OP_LCOMPARE;
968                 else if (src1->type == STACK_R4)
969                         ins->opcode = OP_RCOMPARE;
970                 else if (src1->type == STACK_R8)
971                         ins->opcode = OP_FCOMPARE;
972                 else
973                         ins->opcode = OP_ICOMPARE;
974                 break;
975         case OP_ICOMPARE_IMM:
976                 ins->type = bin_comp_table [src1->type] [src1->type] ? STACK_I4 : STACK_INV;
977                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
978                         ins->opcode = OP_LCOMPARE_IMM;          
979                 break;
980         case CEE_BEQ:
981         case CEE_BGE:
982         case CEE_BGT:
983         case CEE_BLE:
984         case CEE_BLT:
985         case CEE_BNE_UN:
986         case CEE_BGE_UN:
987         case CEE_BGT_UN:
988         case CEE_BLE_UN:
989         case CEE_BLT_UN:
990                 ins->opcode += beqops_op_map [src1->type];
991                 break;
992         case OP_CEQ:
993                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
994                 ins->opcode += ceqops_op_map [src1->type];
995                 break;
996         case OP_CGT:
997         case OP_CGT_UN:
998         case OP_CLT:
999         case OP_CLT_UN:
1000                 ins->type = (bin_comp_table [src1->type] [src2->type] & 1) ? STACK_I4: STACK_INV;
1001                 ins->opcode += ceqops_op_map [src1->type];
1002                 break;
1003         /* unops */
1004         case CEE_NEG:
1005                 ins->type = neg_table [src1->type];
1006                 ins->opcode += unops_op_map [ins->type];
1007                 break;
1008         case CEE_NOT:
1009                 if (src1->type >= STACK_I4 && src1->type <= STACK_PTR)
1010                         ins->type = src1->type;
1011                 else
1012                         ins->type = STACK_INV;
1013                 ins->opcode += unops_op_map [ins->type];
1014                 break;
1015         case CEE_CONV_I1:
1016         case CEE_CONV_I2:
1017         case CEE_CONV_I4:
1018         case CEE_CONV_U4:
1019                 ins->type = STACK_I4;
1020                 ins->opcode += unops_op_map [src1->type];
1021                 break;
1022         case CEE_CONV_R_UN:
1023                 ins->type = STACK_R8;
1024                 switch (src1->type) {
1025                 case STACK_I4:
1026                 case STACK_PTR:
1027                         ins->opcode = OP_ICONV_TO_R_UN;
1028                         break;
1029                 case STACK_I8:
1030                         ins->opcode = OP_LCONV_TO_R_UN; 
1031                         break;
1032                 }
1033                 break;
1034         case CEE_CONV_OVF_I1:
1035         case CEE_CONV_OVF_U1:
1036         case CEE_CONV_OVF_I2:
1037         case CEE_CONV_OVF_U2:
1038         case CEE_CONV_OVF_I4:
1039         case CEE_CONV_OVF_U4:
1040                 ins->type = STACK_I4;
1041                 ins->opcode += ovf3ops_op_map [src1->type];
1042                 break;
1043         case CEE_CONV_OVF_I_UN:
1044         case CEE_CONV_OVF_U_UN:
1045                 ins->type = STACK_PTR;
1046                 ins->opcode += ovf2ops_op_map [src1->type];
1047                 break;
1048         case CEE_CONV_OVF_I1_UN:
1049         case CEE_CONV_OVF_I2_UN:
1050         case CEE_CONV_OVF_I4_UN:
1051         case CEE_CONV_OVF_U1_UN:
1052         case CEE_CONV_OVF_U2_UN:
1053         case CEE_CONV_OVF_U4_UN:
1054                 ins->type = STACK_I4;
1055                 ins->opcode += ovf2ops_op_map [src1->type];
1056                 break;
1057         case CEE_CONV_U:
1058                 ins->type = STACK_PTR;
1059                 switch (src1->type) {
1060                 case STACK_I4:
1061                         ins->opcode = OP_ICONV_TO_U;
1062                         break;
1063                 case STACK_PTR:
1064                 case STACK_MP:
1065 #if SIZEOF_VOID_P == 8
1066                         ins->opcode = OP_LCONV_TO_U;
1067 #else
1068                         ins->opcode = OP_MOVE;
1069 #endif
1070                         break;
1071                 case STACK_I8:
1072                         ins->opcode = OP_LCONV_TO_U;
1073                         break;
1074                 case STACK_R8:
1075                         ins->opcode = OP_FCONV_TO_U;
1076                         break;
1077                 }
1078                 break;
1079         case CEE_CONV_I8:
1080         case CEE_CONV_U8:
1081                 ins->type = STACK_I8;
1082                 ins->opcode += unops_op_map [src1->type];
1083                 break;
1084         case CEE_CONV_OVF_I8:
1085         case CEE_CONV_OVF_U8:
1086                 ins->type = STACK_I8;
1087                 ins->opcode += ovf3ops_op_map [src1->type];
1088                 break;
1089         case CEE_CONV_OVF_U8_UN:
1090         case CEE_CONV_OVF_I8_UN:
1091                 ins->type = STACK_I8;
1092                 ins->opcode += ovf2ops_op_map [src1->type];
1093                 break;
1094         case CEE_CONV_R4:
1095                 ins->type = cfg->r4_stack_type;
1096                 ins->opcode += unops_op_map [src1->type];
1097                 break;
1098         case CEE_CONV_R8:
1099                 ins->type = STACK_R8;
1100                 ins->opcode += unops_op_map [src1->type];
1101                 break;
1102         case OP_CKFINITE:
1103                 ins->type = STACK_R8;           
1104                 break;
1105         case CEE_CONV_U2:
1106         case CEE_CONV_U1:
1107                 ins->type = STACK_I4;
1108                 ins->opcode += ovfops_op_map [src1->type];
1109                 break;
1110         case CEE_CONV_I:
1111         case CEE_CONV_OVF_I:
1112         case CEE_CONV_OVF_U:
1113                 ins->type = STACK_PTR;
1114                 ins->opcode += ovfops_op_map [src1->type];
1115                 break;
1116         case CEE_ADD_OVF:
1117         case CEE_ADD_OVF_UN:
1118         case CEE_MUL_OVF:
1119         case CEE_MUL_OVF_UN:
1120         case CEE_SUB_OVF:
1121         case CEE_SUB_OVF_UN:
1122                 ins->type = bin_num_table [src1->type] [src2->type];
1123                 ins->opcode += ovfops_op_map [src1->type];
1124                 if (ins->type == STACK_R8)
1125                         ins->type = STACK_INV;
1126                 break;
1127         case OP_LOAD_MEMBASE:
1128                 ins->type = STACK_PTR;
1129                 break;
1130         case OP_LOADI1_MEMBASE:
1131         case OP_LOADU1_MEMBASE:
1132         case OP_LOADI2_MEMBASE:
1133         case OP_LOADU2_MEMBASE:
1134         case OP_LOADI4_MEMBASE:
1135         case OP_LOADU4_MEMBASE:
1136                 ins->type = STACK_PTR;
1137                 break;
1138         case OP_LOADI8_MEMBASE:
1139                 ins->type = STACK_I8;
1140                 break;
1141         case OP_LOADR4_MEMBASE:
1142                 ins->type = cfg->r4_stack_type;
1143                 break;
1144         case OP_LOADR8_MEMBASE:
1145                 ins->type = STACK_R8;
1146                 break;
1147         default:
1148                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1149                 break;
1150         }
1151
1152         if (ins->type == STACK_MP)
1153                 ins->klass = mono_defaults.object_class;
1154 }
1155
1156 static const char 
1157 ldind_type [] = {
1158         STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
1159 };
1160
1161 #if 0
1162
1163 static const char
1164 param_table [STACK_MAX] [STACK_MAX] = {
1165         {0},
1166 };
1167
1168 static int
1169 check_values_to_signature (MonoInst *args, MonoType *this_ins, MonoMethodSignature *sig)
1170 {
1171         int i;
1172
1173         if (sig->hasthis) {
1174                 switch (args->type) {
1175                 case STACK_I4:
1176                 case STACK_I8:
1177                 case STACK_R8:
1178                 case STACK_VTYPE:
1179                 case STACK_INV:
1180                         return 0;
1181                 }
1182                 args++;
1183         }
1184         for (i = 0; i < sig->param_count; ++i) {
1185                 switch (args [i].type) {
1186                 case STACK_INV:
1187                         return 0;
1188                 case STACK_MP:
1189                         if (!sig->params [i]->byref)
1190                                 return 0;
1191                         continue;
1192                 case STACK_OBJ:
1193                         if (sig->params [i]->byref)
1194                                 return 0;
1195                         switch (sig->params [i]->type) {
1196                         case MONO_TYPE_CLASS:
1197                         case MONO_TYPE_STRING:
1198                         case MONO_TYPE_OBJECT:
1199                         case MONO_TYPE_SZARRAY:
1200                         case MONO_TYPE_ARRAY:
1201                                 break;
1202                         default:
1203                                 return 0;
1204                         }
1205                         continue;
1206                 case STACK_R8:
1207                         if (sig->params [i]->byref)
1208                                 return 0;
1209                         if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1210                                 return 0;
1211                         continue;
1212                 case STACK_PTR:
1213                 case STACK_I4:
1214                 case STACK_I8:
1215                 case STACK_VTYPE:
1216                         break;
1217                 }
1218                 /*if (!param_table [args [i].type] [sig->params [i]->type])
1219                         return 0;*/
1220         }
1221         return 1;
1222 }
1223 #endif
1224
1225 /*
1226  * When we need a pointer to the current domain many times in a method, we
1227  * call mono_domain_get() once and we store the result in a local variable.
1228  * This function returns the variable that represents the MonoDomain*.
1229  */
1230 inline static MonoInst *
1231 mono_get_domainvar (MonoCompile *cfg)
1232 {
1233         if (!cfg->domainvar)
1234                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1235         return cfg->domainvar;
1236 }
1237
1238 /*
1239  * The got_var contains the address of the Global Offset Table when AOT 
1240  * compiling.
1241  */
1242 MonoInst *
1243 mono_get_got_var (MonoCompile *cfg)
1244 {
1245         if (!cfg->compile_aot || !cfg->backend->need_got_var)
1246                 return NULL;
1247         if (!cfg->got_var) {
1248                 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1249         }
1250         return cfg->got_var;
1251 }
1252
1253 static MonoInst *
1254 mono_get_vtable_var (MonoCompile *cfg)
1255 {
1256         g_assert (cfg->gshared);
1257
1258         if (!cfg->rgctx_var) {
1259                 cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1260                 /* force the var to be stack allocated */
1261                 cfg->rgctx_var->flags |= MONO_INST_VOLATILE;
1262         }
1263
1264         return cfg->rgctx_var;
1265 }
1266
1267 static MonoType*
1268 type_from_stack_type (MonoInst *ins) {
1269         switch (ins->type) {
1270         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1271         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1272         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1273         case STACK_R4: return &mono_defaults.single_class->byval_arg;
1274         case STACK_R8: return &mono_defaults.double_class->byval_arg;
1275         case STACK_MP:
1276                 return &ins->klass->this_arg;
1277         case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1278         case STACK_VTYPE: return &ins->klass->byval_arg;
1279         default:
1280                 g_error ("stack type %d to monotype not handled\n", ins->type);
1281         }
1282         return NULL;
1283 }
1284
1285 static G_GNUC_UNUSED int
1286 type_to_stack_type (MonoCompile *cfg, MonoType *t)
1287 {
1288         t = mono_type_get_underlying_type (t);
1289         switch (t->type) {
1290         case MONO_TYPE_I1:
1291         case MONO_TYPE_U1:
1292         case MONO_TYPE_I2:
1293         case MONO_TYPE_U2:
1294         case MONO_TYPE_I4:
1295         case MONO_TYPE_U4:
1296                 return STACK_I4;
1297         case MONO_TYPE_I:
1298         case MONO_TYPE_U:
1299         case MONO_TYPE_PTR:
1300         case MONO_TYPE_FNPTR:
1301                 return STACK_PTR;
1302         case MONO_TYPE_CLASS:
1303         case MONO_TYPE_STRING:
1304         case MONO_TYPE_OBJECT:
1305         case MONO_TYPE_SZARRAY:
1306         case MONO_TYPE_ARRAY:    
1307                 return STACK_OBJ;
1308         case MONO_TYPE_I8:
1309         case MONO_TYPE_U8:
1310                 return STACK_I8;
1311         case MONO_TYPE_R4:
1312                 return cfg->r4_stack_type;
1313         case MONO_TYPE_R8:
1314                 return STACK_R8;
1315         case MONO_TYPE_VALUETYPE:
1316         case MONO_TYPE_TYPEDBYREF:
1317                 return STACK_VTYPE;
1318         case MONO_TYPE_GENERICINST:
1319                 if (mono_type_generic_inst_is_valuetype (t))
1320                         return STACK_VTYPE;
1321                 else
1322                         return STACK_OBJ;
1323                 break;
1324         default:
1325                 g_assert_not_reached ();
1326         }
1327
1328         return -1;
1329 }
1330
1331 static MonoClass*
1332 array_access_to_klass (int opcode)
1333 {
1334         switch (opcode) {
1335         case CEE_LDELEM_U1:
1336                 return mono_defaults.byte_class;
1337         case CEE_LDELEM_U2:
1338                 return mono_defaults.uint16_class;
1339         case CEE_LDELEM_I:
1340         case CEE_STELEM_I:
1341                 return mono_defaults.int_class;
1342         case CEE_LDELEM_I1:
1343         case CEE_STELEM_I1:
1344                 return mono_defaults.sbyte_class;
1345         case CEE_LDELEM_I2:
1346         case CEE_STELEM_I2:
1347                 return mono_defaults.int16_class;
1348         case CEE_LDELEM_I4:
1349         case CEE_STELEM_I4:
1350                 return mono_defaults.int32_class;
1351         case CEE_LDELEM_U4:
1352                 return mono_defaults.uint32_class;
1353         case CEE_LDELEM_I8:
1354         case CEE_STELEM_I8:
1355                 return mono_defaults.int64_class;
1356         case CEE_LDELEM_R4:
1357         case CEE_STELEM_R4:
1358                 return mono_defaults.single_class;
1359         case CEE_LDELEM_R8:
1360         case CEE_STELEM_R8:
1361                 return mono_defaults.double_class;
1362         case CEE_LDELEM_REF:
1363         case CEE_STELEM_REF:
1364                 return mono_defaults.object_class;
1365         default:
1366                 g_assert_not_reached ();
1367         }
1368         return NULL;
1369 }
1370
1371 /*
1372  * We try to share variables when possible
1373  */
1374 static MonoInst *
1375 mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
1376 {
1377         MonoInst *res;
1378         int pos, vnum;
1379
1380         /* inlining can result in deeper stacks */ 
1381         if (slot >= cfg->header->max_stack)
1382                 return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1383
1384         pos = ins->type - 1 + slot * STACK_MAX;
1385
1386         switch (ins->type) {
1387         case STACK_I4:
1388         case STACK_I8:
1389         case STACK_R8:
1390         case STACK_PTR:
1391         case STACK_MP:
1392         case STACK_OBJ:
1393                 if ((vnum = cfg->intvars [pos]))
1394                         return cfg->varinfo [vnum];
1395                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1396                 cfg->intvars [pos] = res->inst_c0;
1397                 break;
1398         default:
1399                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1400         }
1401         return res;
1402 }
1403
1404 static void
1405 mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
1406 {
1407         /* 
1408          * Don't use this if a generic_context is set, since that means AOT can't
1409          * look up the method using just the image+token.
1410          * table == 0 means this is a reference made from a wrapper.
1411          */
1412         if (cfg->compile_aot && !cfg->generic_context && (mono_metadata_token_table (token) > 0)) {
1413                 MonoJumpInfoToken *jump_info_token = (MonoJumpInfoToken *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
1414                 jump_info_token->image = image;
1415                 jump_info_token->token = token;
1416                 g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
1417         }
1418 }
1419
1420 /*
1421  * This function is called to handle items that are left on the evaluation stack
1422  * at basic block boundaries. What happens is that we save the values to local variables
1423  * and we reload them later when first entering the target basic block (with the
1424  * handle_loaded_temps () function).
1425  * A single joint point will use the same variables (stored in the array bb->out_stack or
1426  * bb->in_stack, if the basic block is before or after the joint point).
1427  *
1428  * This function needs to be called _before_ emitting the last instruction of
1429  * the bb (i.e. before emitting a branch).
1430  * If the stack merge fails at a join point, cfg->unverifiable is set.
1431  */
1432 static void
1433 handle_stack_args (MonoCompile *cfg, MonoInst **sp, int count)
1434 {
1435         int i, bindex;
1436         MonoBasicBlock *bb = cfg->cbb;
1437         MonoBasicBlock *outb;
1438         MonoInst *inst, **locals;
1439         gboolean found;
1440
1441         if (!count)
1442                 return;
1443         if (cfg->verbose_level > 3)
1444                 printf ("%d item(s) on exit from B%d\n", count, bb->block_num);
1445         if (!bb->out_scount) {
1446                 bb->out_scount = count;
1447                 //printf ("bblock %d has out:", bb->block_num);
1448                 found = FALSE;
1449                 for (i = 0; i < bb->out_count; ++i) {
1450                         outb = bb->out_bb [i];
1451                         /* exception handlers are linked, but they should not be considered for stack args */
1452                         if (outb->flags & BB_EXCEPTION_HANDLER)
1453                                 continue;
1454                         //printf (" %d", outb->block_num);
1455                         if (outb->in_stack) {
1456                                 found = TRUE;
1457                                 bb->out_stack = outb->in_stack;
1458                                 break;
1459                         }
1460                 }
1461                 //printf ("\n");
1462                 if (!found) {
1463                         bb->out_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1464                         for (i = 0; i < count; ++i) {
1465                                 /* 
1466                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
1467                                  * stack slot and if they are of the same type.
1468                                  * This won't cause conflicts since if 'local' is used to 
1469                                  * store one of the values in the in_stack of a bblock, then
1470                                  * the same variable will be used for the same outgoing stack 
1471                                  * slot as well. 
1472                                  * This doesn't work when inlining methods, since the bblocks
1473                                  * in the inlined methods do not inherit their in_stack from
1474                                  * the bblock they are inlined to. See bug #58863 for an
1475                                  * example.
1476                                  */
1477                                 if (cfg->inlined_method)
1478                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1479                                 else
1480                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
1481                         }
1482                 }
1483         }
1484
1485         for (i = 0; i < bb->out_count; ++i) {
1486                 outb = bb->out_bb [i];
1487                 /* exception handlers are linked, but they should not be considered for stack args */
1488                 if (outb->flags & BB_EXCEPTION_HANDLER)
1489                         continue;
1490                 if (outb->in_scount) {
1491                         if (outb->in_scount != bb->out_scount) {
1492                                 cfg->unverifiable = TRUE;
1493                                 return;
1494                         }
1495                         continue; /* check they are the same locals */
1496                 }
1497                 outb->in_scount = count;
1498                 outb->in_stack = bb->out_stack;
1499         }
1500
1501         locals = bb->out_stack;
1502         cfg->cbb = bb;
1503         for (i = 0; i < count; ++i) {
1504                 EMIT_NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
1505                 inst->cil_code = sp [i]->cil_code;
1506                 sp [i] = locals [i];
1507                 if (cfg->verbose_level > 3)
1508                         printf ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
1509         }
1510
1511         /*
1512          * It is possible that the out bblocks already have in_stack assigned, and
1513          * the in_stacks differ. In this case, we will store to all the different 
1514          * in_stacks.
1515          */
1516
1517         found = TRUE;
1518         bindex = 0;
1519         while (found) {
1520                 /* Find a bblock which has a different in_stack */
1521                 found = FALSE;
1522                 while (bindex < bb->out_count) {
1523                         outb = bb->out_bb [bindex];
1524                         /* exception handlers are linked, but they should not be considered for stack args */
1525                         if (outb->flags & BB_EXCEPTION_HANDLER) {
1526                                 bindex++;
1527                                 continue;
1528                         }
1529                         if (outb->in_stack != locals) {
1530                                 for (i = 0; i < count; ++i) {
1531                                         EMIT_NEW_TEMPSTORE (cfg, inst, outb->in_stack [i]->inst_c0, sp [i]);
1532                                         inst->cil_code = sp [i]->cil_code;
1533                                         sp [i] = locals [i];
1534                                         if (cfg->verbose_level > 3)
1535                                                 printf ("storing %d to temp %d\n", i, (int)outb->in_stack [i]->inst_c0);
1536                                 }
1537                                 locals = outb->in_stack;
1538                                 found = TRUE;
1539                                 break;
1540                         }
1541                         bindex ++;
1542                 }
1543         }
1544 }
1545
1546 static MonoInst*
1547 emit_runtime_constant (MonoCompile *cfg, MonoJumpInfoType patch_type, gpointer data)
1548 {
1549         MonoInst *ins;
1550
1551         if (cfg->compile_aot) {
1552                 EMIT_NEW_AOTCONST (cfg, ins, patch_type, data);
1553         } else {
1554                 MonoJumpInfo ji;
1555                 gpointer target;
1556                 MonoError error;
1557
1558                 ji.type = patch_type;
1559                 ji.data.target = data;
1560                 target = mono_resolve_patch_target (NULL, cfg->domain, NULL, &ji, FALSE, &error);
1561                 mono_error_assert_ok (&error);
1562
1563                 EMIT_NEW_PCONST (cfg, ins, target);
1564         }
1565         return ins;
1566 }
1567
1568 static void
1569 mini_emit_interface_bitmap_check (MonoCompile *cfg, int intf_bit_reg, int base_reg, int offset, MonoClass *klass)
1570 {
1571         int ibitmap_reg = alloc_preg (cfg);
1572 #ifdef COMPRESSED_INTERFACE_BITMAP
1573         MonoInst *args [2];
1574         MonoInst *res, *ins;
1575         NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, ibitmap_reg, base_reg, offset);
1576         MONO_ADD_INS (cfg->cbb, ins);
1577         args [0] = ins;
1578         args [1] = emit_runtime_constant (cfg, MONO_PATCH_INFO_IID, klass);
1579         res = mono_emit_jit_icall (cfg, mono_class_interface_match, args);
1580         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, intf_bit_reg, res->dreg);
1581 #else
1582         int ibitmap_byte_reg = alloc_preg (cfg);
1583
1584         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, base_reg, offset);
1585
1586         if (cfg->compile_aot) {
1587                 int iid_reg = alloc_preg (cfg);
1588                 int shifted_iid_reg = alloc_preg (cfg);
1589                 int ibitmap_byte_address_reg = alloc_preg (cfg);
1590                 int masked_iid_reg = alloc_preg (cfg);
1591                 int iid_one_bit_reg = alloc_preg (cfg);
1592                 int iid_bit_reg = alloc_preg (cfg);
1593                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1594                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, shifted_iid_reg, iid_reg, 3);
1595                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ibitmap_byte_address_reg, ibitmap_reg, shifted_iid_reg);
1596                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, ibitmap_byte_reg, ibitmap_byte_address_reg, 0);
1597                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, masked_iid_reg, iid_reg, 7);
1598                 MONO_EMIT_NEW_ICONST (cfg, iid_one_bit_reg, 1);
1599                 MONO_EMIT_NEW_BIALU (cfg, OP_ISHL, iid_bit_reg, iid_one_bit_reg, masked_iid_reg);
1600                 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, intf_bit_reg, ibitmap_byte_reg, iid_bit_reg);
1601         } else {
1602                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, klass->interface_id >> 3);
1603                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (klass->interface_id & 7));
1604         }
1605 #endif
1606 }
1607
1608 /* 
1609  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoClass
1610  * stored in "klass_reg" implements the interface "klass".
1611  */
1612 static void
1613 mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass_reg, MonoClass *klass)
1614 {
1615         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, interface_bitmap), klass);
1616 }
1617
1618 /* 
1619  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoVTable
1620  * stored in "vtable_reg" implements the interface "klass".
1621  */
1622 static void
1623 mini_emit_load_intf_bit_reg_vtable (MonoCompile *cfg, int intf_bit_reg, int vtable_reg, MonoClass *klass)
1624 {
1625         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, interface_bitmap), klass);
1626 }
1627
1628 /* 
1629  * Emit code which checks whenever the interface id of @klass is smaller than
1630  * than the value given by max_iid_reg.
1631 */
1632 static void
1633 mini_emit_max_iid_check (MonoCompile *cfg, int max_iid_reg, MonoClass *klass,
1634                                                  MonoBasicBlock *false_target)
1635 {
1636         if (cfg->compile_aot) {
1637                 int iid_reg = alloc_preg (cfg);
1638                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1639                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, max_iid_reg, iid_reg);
1640         }
1641         else
1642                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, max_iid_reg, klass->interface_id);
1643         if (false_target)
1644                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1645         else
1646                 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1647 }
1648
1649 /* Same as above, but obtains max_iid from a vtable */
1650 static void
1651 mini_emit_max_iid_check_vtable (MonoCompile *cfg, int vtable_reg, MonoClass *klass,
1652                                                                  MonoBasicBlock *false_target)
1653 {
1654         int max_iid_reg = alloc_preg (cfg);
1655                 
1656         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, max_interface_id));
1657         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1658 }
1659
1660 /* Same as above, but obtains max_iid from a klass */
1661 static void
1662 mini_emit_max_iid_check_class (MonoCompile *cfg, int klass_reg, MonoClass *klass,
1663                                                                  MonoBasicBlock *false_target)
1664 {
1665         int max_iid_reg = alloc_preg (cfg);
1666
1667         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, max_interface_id));
1668         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1669 }
1670
1671 static void
1672 mini_emit_isninst_cast_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_ins, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1673 {
1674         int idepth_reg = alloc_preg (cfg);
1675         int stypes_reg = alloc_preg (cfg);
1676         int stype = alloc_preg (cfg);
1677
1678         mono_class_setup_supertypes (klass);
1679
1680         if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1681                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1682                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1683                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1684         }
1685         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1686         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1687         if (klass_ins) {
1688                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, klass_ins->dreg);
1689         } else if (cfg->compile_aot) {
1690                 int const_reg = alloc_preg (cfg);
1691                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1692                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, const_reg);
1693         } else {
1694                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, stype, klass);
1695         }
1696         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, true_target);
1697 }
1698
1699 static void
1700 mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1701 {
1702         mini_emit_isninst_cast_inst (cfg, klass_reg, klass, NULL, false_target, true_target);
1703 }
1704
1705 static void
1706 mini_emit_iface_cast (MonoCompile *cfg, int vtable_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1707 {
1708         int intf_reg = alloc_preg (cfg);
1709
1710         mini_emit_max_iid_check_vtable (cfg, vtable_reg, klass, false_target);
1711         mini_emit_load_intf_bit_reg_vtable (cfg, intf_reg, vtable_reg, klass);
1712         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_reg, 0);
1713         if (true_target)
1714                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1715         else
1716                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");               
1717 }
1718
1719 /*
1720  * Variant of the above that takes a register to the class, not the vtable.
1721  */
1722 static void
1723 mini_emit_iface_class_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1724 {
1725         int intf_bit_reg = alloc_preg (cfg);
1726
1727         mini_emit_max_iid_check_class (cfg, klass_reg, klass, false_target);
1728         mini_emit_load_intf_bit_reg_class (cfg, intf_bit_reg, klass_reg, klass);
1729         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_bit_reg, 0);
1730         if (true_target)
1731                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1732         else
1733                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
1734 }
1735
1736 static inline void
1737 mini_emit_class_check_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_inst)
1738 {
1739         if (klass_inst) {
1740                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_inst->dreg);
1741         } else {
1742                 MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
1743                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, ins->dreg);
1744         }
1745         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1746 }
1747
1748 static inline void
1749 mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass)
1750 {
1751         mini_emit_class_check_inst (cfg, klass_reg, klass, NULL);
1752 }
1753
1754 static inline void
1755 mini_emit_class_check_branch (MonoCompile *cfg, int klass_reg, MonoClass *klass, int branch_op, MonoBasicBlock *target)
1756 {
1757         if (cfg->compile_aot) {
1758                 int const_reg = alloc_preg (cfg);
1759                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1760                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1761         } else {
1762                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1763         }
1764         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, branch_op, target);
1765 }
1766
1767 static void
1768 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null);
1769         
1770 static void
1771 mini_emit_castclass_inst (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoInst *klass_inst, MonoBasicBlock *object_is_null)
1772 {
1773         if (klass->rank) {
1774                 int rank_reg = alloc_preg (cfg);
1775                 int eclass_reg = alloc_preg (cfg);
1776
1777                 g_assert (!klass_inst);
1778                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, rank));
1779                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
1780                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1781                 //              MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
1782                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
1783                 if (klass->cast_class == mono_defaults.object_class) {
1784                         int parent_reg = alloc_preg (cfg);
1785                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
1786                         mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, object_is_null);
1787                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1788                 } else if (klass->cast_class == mono_defaults.enum_class->parent) {
1789                         mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, object_is_null);
1790                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1791                 } else if (klass->cast_class == mono_defaults.enum_class) {
1792                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1793                 } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1794                         mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, NULL, NULL);
1795                 } else {
1796                         // Pass -1 as obj_reg to skip the check below for arrays of arrays
1797                         mini_emit_castclass (cfg, -1, eclass_reg, klass->cast_class, object_is_null);
1798                 }
1799
1800                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY) && (obj_reg != -1)) {
1801                         /* Check that the object is a vector too */
1802                         int bounds_reg = alloc_preg (cfg);
1803                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
1804                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
1805                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1806                 }
1807         } else {
1808                 int idepth_reg = alloc_preg (cfg);
1809                 int stypes_reg = alloc_preg (cfg);
1810                 int stype = alloc_preg (cfg);
1811
1812                 mono_class_setup_supertypes (klass);
1813
1814                 if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1815                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1816                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1817                         MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1818                 }
1819                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1820                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1821                 mini_emit_class_check_inst (cfg, stype, klass, klass_inst);
1822         }
1823 }
1824
1825 static void
1826 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null)
1827 {
1828         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, NULL, object_is_null);
1829 }
1830
1831 static void 
1832 mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align)
1833 {
1834         int val_reg;
1835
1836         g_assert (val == 0);
1837
1838         if (align == 0)
1839                 align = 4;
1840
1841         if ((size <= SIZEOF_REGISTER) && (size <= align)) {
1842                 switch (size) {
1843                 case 1:
1844                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, destreg, offset, val);
1845                         return;
1846                 case 2:
1847                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI2_MEMBASE_IMM, destreg, offset, val);
1848                         return;
1849                 case 4:
1850                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI4_MEMBASE_IMM, destreg, offset, val);
1851                         return;
1852 #if SIZEOF_REGISTER == 8
1853                 case 8:
1854                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI8_MEMBASE_IMM, destreg, offset, val);
1855                         return;
1856 #endif
1857                 }
1858         }
1859
1860         val_reg = alloc_preg (cfg);
1861
1862         if (SIZEOF_REGISTER == 8)
1863                 MONO_EMIT_NEW_I8CONST (cfg, val_reg, val);
1864         else
1865                 MONO_EMIT_NEW_ICONST (cfg, val_reg, val);
1866
1867         if (align < 4) {
1868                 /* This could be optimized further if neccesary */
1869                 while (size >= 1) {
1870                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1871                         offset += 1;
1872                         size -= 1;
1873                 }
1874                 return;
1875         }       
1876
1877         if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
1878                 if (offset % 8) {
1879                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1880                         offset += 4;
1881                         size -= 4;
1882                 }
1883                 while (size >= 8) {
1884                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, offset, val_reg);
1885                         offset += 8;
1886                         size -= 8;
1887                 }
1888         }       
1889
1890         while (size >= 4) {
1891                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1892                 offset += 4;
1893                 size -= 4;
1894         }
1895         while (size >= 2) {
1896                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, val_reg);
1897                 offset += 2;
1898                 size -= 2;
1899         }
1900         while (size >= 1) {
1901                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1902                 offset += 1;
1903                 size -= 1;
1904         }
1905 }
1906
1907 void 
1908 mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align)
1909 {
1910         int cur_reg;
1911
1912         if (align == 0)
1913                 align = 4;
1914
1915         /*FIXME arbitrary hack to avoid unbound code expansion.*/
1916         g_assert (size < 10000);
1917
1918         if (align < 4) {
1919                 /* This could be optimized further if neccesary */
1920                 while (size >= 1) {
1921                         cur_reg = alloc_preg (cfg);
1922                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1923                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1924                         doffset += 1;
1925                         soffset += 1;
1926                         size -= 1;
1927                 }
1928         }
1929
1930         if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
1931                 while (size >= 8) {
1932                         cur_reg = alloc_preg (cfg);
1933                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI8_MEMBASE, cur_reg, srcreg, soffset);
1934                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, doffset, cur_reg);
1935                         doffset += 8;
1936                         soffset += 8;
1937                         size -= 8;
1938                 }
1939         }       
1940
1941         while (size >= 4) {
1942                 cur_reg = alloc_preg (cfg);
1943                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, cur_reg, srcreg, soffset);
1944                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, doffset, cur_reg);
1945                 doffset += 4;
1946                 soffset += 4;
1947                 size -= 4;
1948         }
1949         while (size >= 2) {
1950                 cur_reg = alloc_preg (cfg);
1951                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, cur_reg, srcreg, soffset);
1952                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, doffset, cur_reg);
1953                 doffset += 2;
1954                 soffset += 2;
1955                 size -= 2;
1956         }
1957         while (size >= 1) {
1958                 cur_reg = alloc_preg (cfg);
1959                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1960                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1961                 doffset += 1;
1962                 soffset += 1;
1963                 size -= 1;
1964         }
1965 }
1966
1967 static void
1968 emit_tls_set (MonoCompile *cfg, int sreg1, MonoTlsKey tls_key)
1969 {
1970         MonoInst *ins, *c;
1971
1972         if (cfg->compile_aot) {
1973                 EMIT_NEW_TLS_OFFSETCONST (cfg, c, tls_key);
1974                 MONO_INST_NEW (cfg, ins, OP_TLS_SET_REG);
1975                 ins->sreg1 = sreg1;
1976                 ins->sreg2 = c->dreg;
1977                 MONO_ADD_INS (cfg->cbb, ins);
1978         } else {
1979                 MONO_INST_NEW (cfg, ins, OP_TLS_SET);
1980                 ins->sreg1 = sreg1;
1981                 ins->inst_offset = mini_get_tls_offset (tls_key);
1982                 MONO_ADD_INS (cfg->cbb, ins);
1983         }
1984 }
1985
1986 /*
1987  * emit_push_lmf:
1988  *
1989  *   Emit IR to push the current LMF onto the LMF stack.
1990  */
1991 static void
1992 emit_push_lmf (MonoCompile *cfg)
1993 {
1994         /*
1995          * Emit IR to push the LMF:
1996          * lmf_addr = <lmf_addr from tls>
1997          * lmf->lmf_addr = lmf_addr
1998          * lmf->prev_lmf = *lmf_addr
1999          * *lmf_addr = lmf
2000          */
2001         int lmf_reg, prev_lmf_reg;
2002         MonoInst *ins, *lmf_ins;
2003
2004         if (!cfg->lmf_ir)
2005                 return;
2006
2007         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
2008                 /* Load current lmf */
2009                 lmf_ins = mono_get_lmf_intrinsic (cfg);
2010                 g_assert (lmf_ins);
2011                 MONO_ADD_INS (cfg->cbb, lmf_ins);
2012                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2013                 lmf_reg = ins->dreg;
2014                 /* Save previous_lmf */
2015                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), lmf_ins->dreg);
2016                 /* Set new LMF */
2017                 emit_tls_set (cfg, lmf_reg, TLS_KEY_LMF);
2018         } else {
2019                 /*
2020                  * Store lmf_addr in a variable, so it can be allocated to a global register.
2021                  */
2022                 if (!cfg->lmf_addr_var)
2023                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2024
2025 #ifdef HOST_WIN32
2026                 ins = mono_get_jit_tls_intrinsic (cfg);
2027                 if (ins) {
2028                         int jit_tls_dreg = ins->dreg;
2029
2030                         MONO_ADD_INS (cfg->cbb, ins);
2031                         lmf_reg = alloc_preg (cfg);
2032                         EMIT_NEW_BIALU_IMM (cfg, lmf_ins, OP_PADD_IMM, lmf_reg, jit_tls_dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2033                 } else {
2034                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2035                 }
2036 #else
2037                 lmf_ins = mono_get_lmf_addr_intrinsic (cfg);
2038                 if (lmf_ins) {
2039                         MONO_ADD_INS (cfg->cbb, lmf_ins);
2040                 } else {
2041 #ifdef TARGET_IOS
2042                         MonoInst *args [16], *jit_tls_ins, *ins;
2043
2044                         /* Inline mono_get_lmf_addr () */
2045                         /* jit_tls = pthread_getspecific (mono_jit_tls_id); lmf_addr = &jit_tls->lmf; */
2046
2047                         /* Load mono_jit_tls_id */
2048                         if (cfg->compile_aot)
2049                                 EMIT_NEW_AOTCONST (cfg, args [0], MONO_PATCH_INFO_JIT_TLS_ID, NULL);
2050                         else
2051                                 EMIT_NEW_ICONST (cfg, args [0], mono_jit_tls_id);
2052                         /* call pthread_getspecific () */
2053                         jit_tls_ins = mono_emit_jit_icall (cfg, pthread_getspecific, args);
2054                         /* lmf_addr = &jit_tls->lmf */
2055                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, cfg->lmf_addr_var->dreg, jit_tls_ins->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2056                         lmf_ins = ins;
2057 #else
2058                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2059 #endif
2060                 }
2061 #endif
2062                 lmf_ins->dreg = cfg->lmf_addr_var->dreg;
2063
2064                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2065                 lmf_reg = ins->dreg;
2066
2067                 prev_lmf_reg = alloc_preg (cfg);
2068                 /* Save previous_lmf */
2069                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, cfg->lmf_addr_var->dreg, 0);
2070                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), prev_lmf_reg);
2071                 /* Set new lmf */
2072                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, cfg->lmf_addr_var->dreg, 0, lmf_reg);
2073         }
2074 }
2075
2076 /*
2077  * emit_pop_lmf:
2078  *
2079  *   Emit IR to pop the current LMF from the LMF stack.
2080  */
2081 static void
2082 emit_pop_lmf (MonoCompile *cfg)
2083 {
2084         int lmf_reg, lmf_addr_reg, prev_lmf_reg;
2085         MonoInst *ins;
2086
2087         if (!cfg->lmf_ir)
2088                 return;
2089
2090         EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2091         lmf_reg = ins->dreg;
2092
2093         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
2094                 /* Load previous_lmf */
2095                 prev_lmf_reg = alloc_preg (cfg);
2096                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2097                 /* Set new LMF */
2098                 emit_tls_set (cfg, prev_lmf_reg, TLS_KEY_LMF);
2099         } else {
2100                 /*
2101                  * Emit IR to pop the LMF:
2102                  * *(lmf->lmf_addr) = lmf->prev_lmf
2103                  */
2104                 /* This could be called before emit_push_lmf () */
2105                 if (!cfg->lmf_addr_var)
2106                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2107                 lmf_addr_reg = cfg->lmf_addr_var->dreg;
2108
2109                 prev_lmf_reg = alloc_preg (cfg);
2110                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2111                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_addr_reg, 0, prev_lmf_reg);
2112         }
2113 }
2114
2115 static void
2116 emit_instrumentation_call (MonoCompile *cfg, void *func)
2117 {
2118         MonoInst *iargs [1];
2119
2120         /*
2121          * Avoid instrumenting inlined methods since it can
2122          * distort profiling results.
2123          */
2124         if (cfg->method != cfg->current_method)
2125                 return;
2126
2127         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
2128                 EMIT_NEW_METHODCONST (cfg, iargs [0], cfg->method);
2129                 mono_emit_jit_icall (cfg, func, iargs);
2130         }
2131 }
2132
2133 static int
2134 ret_type_to_call_opcode (MonoCompile *cfg, MonoType *type, int calli, int virt)
2135 {
2136 handle_enum:
2137         type = mini_get_underlying_type (type);
2138         switch (type->type) {
2139         case MONO_TYPE_VOID:
2140                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALL_MEMBASE: OP_VOIDCALL;
2141         case MONO_TYPE_I1:
2142         case MONO_TYPE_U1:
2143         case MONO_TYPE_I2:
2144         case MONO_TYPE_U2:
2145         case MONO_TYPE_I4:
2146         case MONO_TYPE_U4:
2147                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2148         case MONO_TYPE_I:
2149         case MONO_TYPE_U:
2150         case MONO_TYPE_PTR:
2151         case MONO_TYPE_FNPTR:
2152                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2153         case MONO_TYPE_CLASS:
2154         case MONO_TYPE_STRING:
2155         case MONO_TYPE_OBJECT:
2156         case MONO_TYPE_SZARRAY:
2157         case MONO_TYPE_ARRAY:    
2158                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2159         case MONO_TYPE_I8:
2160         case MONO_TYPE_U8:
2161                 return calli? OP_LCALL_REG: virt? OP_LCALL_MEMBASE: OP_LCALL;
2162         case MONO_TYPE_R4:
2163                 if (cfg->r4fp)
2164                         return calli? OP_RCALL_REG: virt? OP_RCALL_MEMBASE: OP_RCALL;
2165                 else
2166                         return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2167         case MONO_TYPE_R8:
2168                 return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2169         case MONO_TYPE_VALUETYPE:
2170                 if (type->data.klass->enumtype) {
2171                         type = mono_class_enum_basetype (type->data.klass);
2172                         goto handle_enum;
2173                 } else
2174                         return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2175         case MONO_TYPE_TYPEDBYREF:
2176                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2177         case MONO_TYPE_GENERICINST:
2178                 type = &type->data.generic_class->container_class->byval_arg;
2179                 goto handle_enum;
2180         case MONO_TYPE_VAR:
2181         case MONO_TYPE_MVAR:
2182                 /* gsharedvt */
2183                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2184         default:
2185                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
2186         }
2187         return -1;
2188 }
2189
2190 //XXX this ignores if t is byref
2191 #define MONO_TYPE_IS_PRIMITIVE_SCALAR(t) ((((((t)->type >= MONO_TYPE_BOOLEAN && (t)->type <= MONO_TYPE_U8) || ((t)->type >= MONO_TYPE_I && (t)->type <= MONO_TYPE_U)))))
2192
2193 /*
2194  * target_type_is_incompatible:
2195  * @cfg: MonoCompile context
2196  *
2197  * Check that the item @arg on the evaluation stack can be stored
2198  * in the target type (can be a local, or field, etc).
2199  * The cfg arg can be used to check if we need verification or just
2200  * validity checks.
2201  *
2202  * Returns: non-0 value if arg can't be stored on a target.
2203  */
2204 static int
2205 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
2206 {
2207         MonoType *simple_type;
2208         MonoClass *klass;
2209
2210         if (target->byref) {
2211                 /* FIXME: check that the pointed to types match */
2212                 if (arg->type == STACK_MP) {
2213                         if (cfg->verbose_level) printf ("ok\n");
2214                         /* This is needed to handle gshared types + ldaddr. We lower the types so we can handle enums and other typedef-like types. */
2215                         MonoClass *target_class_lowered = mono_class_from_mono_type (mini_get_underlying_type (&mono_class_from_mono_type (target)->byval_arg));
2216                         MonoClass *source_class_lowered = mono_class_from_mono_type (mini_get_underlying_type (&arg->klass->byval_arg));
2217
2218                         /* if the target is native int& or same type */
2219                         if (target->type == MONO_TYPE_I || target_class_lowered == source_class_lowered)
2220                                 return 0;
2221
2222                         /* Both are primitive type byrefs and the source points to a larger type that the destination */
2223                         if (MONO_TYPE_IS_PRIMITIVE_SCALAR (&target_class_lowered->byval_arg) && MONO_TYPE_IS_PRIMITIVE_SCALAR (&source_class_lowered->byval_arg) &&
2224                                 mono_class_instance_size (target_class_lowered) <= mono_class_instance_size (source_class_lowered))
2225                                 return 0;
2226                         return 1;
2227                 }
2228                 if (arg->type == STACK_PTR)
2229                         return 0;
2230                 return 1;
2231         }
2232
2233         simple_type = mini_get_underlying_type (target);
2234         switch (simple_type->type) {
2235         case MONO_TYPE_VOID:
2236                 return 1;
2237         case MONO_TYPE_I1:
2238         case MONO_TYPE_U1:
2239         case MONO_TYPE_I2:
2240         case MONO_TYPE_U2:
2241         case MONO_TYPE_I4:
2242         case MONO_TYPE_U4:
2243                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2244                         return 1;
2245                 return 0;
2246         case MONO_TYPE_PTR:
2247                 /* STACK_MP is needed when setting pinned locals */
2248                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2249                         return 1;
2250                 return 0;
2251         case MONO_TYPE_I:
2252         case MONO_TYPE_U:
2253         case MONO_TYPE_FNPTR:
2254                 /* 
2255                  * Some opcodes like ldloca returns 'transient pointers' which can be stored in
2256                  * in native int. (#688008).
2257                  */
2258                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2259                         return 1;
2260                 return 0;
2261         case MONO_TYPE_CLASS:
2262         case MONO_TYPE_STRING:
2263         case MONO_TYPE_OBJECT:
2264         case MONO_TYPE_SZARRAY:
2265         case MONO_TYPE_ARRAY:    
2266                 if (arg->type != STACK_OBJ)
2267                         return 1;
2268                 /* FIXME: check type compatibility */
2269                 return 0;
2270         case MONO_TYPE_I8:
2271         case MONO_TYPE_U8:
2272                 if (arg->type != STACK_I8)
2273                         return 1;
2274                 return 0;
2275         case MONO_TYPE_R4:
2276                 if (arg->type != cfg->r4_stack_type)
2277                         return 1;
2278                 return 0;
2279         case MONO_TYPE_R8:
2280                 if (arg->type != STACK_R8)
2281                         return 1;
2282                 return 0;
2283         case MONO_TYPE_VALUETYPE:
2284                 if (arg->type != STACK_VTYPE)
2285                         return 1;
2286                 klass = mono_class_from_mono_type (simple_type);
2287                 if (klass != arg->klass)
2288                         return 1;
2289                 return 0;
2290         case MONO_TYPE_TYPEDBYREF:
2291                 if (arg->type != STACK_VTYPE)
2292                         return 1;
2293                 klass = mono_class_from_mono_type (simple_type);
2294                 if (klass != arg->klass)
2295                         return 1;
2296                 return 0;
2297         case MONO_TYPE_GENERICINST:
2298                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
2299                         MonoClass *target_class;
2300                         if (arg->type != STACK_VTYPE)
2301                                 return 1;
2302                         klass = mono_class_from_mono_type (simple_type);
2303                         target_class = mono_class_from_mono_type (target);
2304                         /* The second cases is needed when doing partial sharing */
2305                         if (klass != arg->klass && target_class != arg->klass && target_class != mono_class_from_mono_type (mini_get_underlying_type (&arg->klass->byval_arg)))
2306                                 return 1;
2307                         return 0;
2308                 } else {
2309                         if (arg->type != STACK_OBJ)
2310                                 return 1;
2311                         /* FIXME: check type compatibility */
2312                         return 0;
2313                 }
2314         case MONO_TYPE_VAR:
2315         case MONO_TYPE_MVAR:
2316                 g_assert (cfg->gshared);
2317                 if (mini_type_var_is_vt (simple_type)) {
2318                         if (arg->type != STACK_VTYPE)
2319                                 return 1;
2320                 } else {
2321                         if (arg->type != STACK_OBJ)
2322                                 return 1;
2323                 }
2324                 return 0;
2325         default:
2326                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
2327         }
2328         return 1;
2329 }
2330
2331 /*
2332  * Prepare arguments for passing to a function call.
2333  * Return a non-zero value if the arguments can't be passed to the given
2334  * signature.
2335  * The type checks are not yet complete and some conversions may need
2336  * casts on 32 or 64 bit architectures.
2337  *
2338  * FIXME: implement this using target_type_is_incompatible ()
2339  */
2340 static int
2341 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2342 {
2343         MonoType *simple_type;
2344         int i;
2345
2346         if (sig->hasthis) {
2347                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2348                         return 1;
2349                 args++;
2350         }
2351         for (i = 0; i < sig->param_count; ++i) {
2352                 if (sig->params [i]->byref) {
2353                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2354                                 return 1;
2355                         continue;
2356                 }
2357                 simple_type = mini_get_underlying_type (sig->params [i]);
2358 handle_enum:
2359                 switch (simple_type->type) {
2360                 case MONO_TYPE_VOID:
2361                         return 1;
2362                         continue;
2363                 case MONO_TYPE_I1:
2364                 case MONO_TYPE_U1:
2365                 case MONO_TYPE_I2:
2366                 case MONO_TYPE_U2:
2367                 case MONO_TYPE_I4:
2368                 case MONO_TYPE_U4:
2369                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2370                                 return 1;
2371                         continue;
2372                 case MONO_TYPE_I:
2373                 case MONO_TYPE_U:
2374                 case MONO_TYPE_PTR:
2375                 case MONO_TYPE_FNPTR:
2376                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2377                                 return 1;
2378                         continue;
2379                 case MONO_TYPE_CLASS:
2380                 case MONO_TYPE_STRING:
2381                 case MONO_TYPE_OBJECT:
2382                 case MONO_TYPE_SZARRAY:
2383                 case MONO_TYPE_ARRAY:    
2384                         if (args [i]->type != STACK_OBJ)
2385                                 return 1;
2386                         continue;
2387                 case MONO_TYPE_I8:
2388                 case MONO_TYPE_U8:
2389                         if (args [i]->type != STACK_I8)
2390                                 return 1;
2391                         continue;
2392                 case MONO_TYPE_R4:
2393                         if (args [i]->type != cfg->r4_stack_type)
2394                                 return 1;
2395                         continue;
2396                 case MONO_TYPE_R8:
2397                         if (args [i]->type != STACK_R8)
2398                                 return 1;
2399                         continue;
2400                 case MONO_TYPE_VALUETYPE:
2401                         if (simple_type->data.klass->enumtype) {
2402                                 simple_type = mono_class_enum_basetype (simple_type->data.klass);
2403                                 goto handle_enum;
2404                         }
2405                         if (args [i]->type != STACK_VTYPE)
2406                                 return 1;
2407                         continue;
2408                 case MONO_TYPE_TYPEDBYREF:
2409                         if (args [i]->type != STACK_VTYPE)
2410                                 return 1;
2411                         continue;
2412                 case MONO_TYPE_GENERICINST:
2413                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2414                         goto handle_enum;
2415                 case MONO_TYPE_VAR:
2416                 case MONO_TYPE_MVAR:
2417                         /* gsharedvt */
2418                         if (args [i]->type != STACK_VTYPE)
2419                                 return 1;
2420                         continue;
2421                 default:
2422                         g_error ("unknown type 0x%02x in check_call_signature",
2423                                  simple_type->type);
2424                 }
2425         }
2426         return 0;
2427 }
2428
2429 static int
2430 callvirt_to_call (int opcode)
2431 {
2432         switch (opcode) {
2433         case OP_CALL_MEMBASE:
2434                 return OP_CALL;
2435         case OP_VOIDCALL_MEMBASE:
2436                 return OP_VOIDCALL;
2437         case OP_FCALL_MEMBASE:
2438                 return OP_FCALL;
2439         case OP_RCALL_MEMBASE:
2440                 return OP_RCALL;
2441         case OP_VCALL_MEMBASE:
2442                 return OP_VCALL;
2443         case OP_LCALL_MEMBASE:
2444                 return OP_LCALL;
2445         default:
2446                 g_assert_not_reached ();
2447         }
2448
2449         return -1;
2450 }
2451
2452 static int
2453 callvirt_to_call_reg (int opcode)
2454 {
2455         switch (opcode) {
2456         case OP_CALL_MEMBASE:
2457                 return OP_CALL_REG;
2458         case OP_VOIDCALL_MEMBASE:
2459                 return OP_VOIDCALL_REG;
2460         case OP_FCALL_MEMBASE:
2461                 return OP_FCALL_REG;
2462         case OP_RCALL_MEMBASE:
2463                 return OP_RCALL_REG;
2464         case OP_VCALL_MEMBASE:
2465                 return OP_VCALL_REG;
2466         case OP_LCALL_MEMBASE:
2467                 return OP_LCALL_REG;
2468         default:
2469                 g_assert_not_reached ();
2470         }
2471
2472         return -1;
2473 }
2474
2475 /* Either METHOD or IMT_ARG needs to be set */
2476 static void
2477 emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoMethod *method, MonoInst *imt_arg)
2478 {
2479         int method_reg;
2480
2481         if (COMPILE_LLVM (cfg)) {
2482                 if (imt_arg) {
2483                         method_reg = alloc_preg (cfg);
2484                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2485                 } else {
2486                         MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHODCONST, method);
2487                         method_reg = ins->dreg;
2488                 }
2489
2490 #ifdef ENABLE_LLVM
2491                 call->imt_arg_reg = method_reg;
2492 #endif
2493                 mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2494                 return;
2495         }
2496
2497         if (imt_arg) {
2498                 method_reg = alloc_preg (cfg);
2499                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2500         } else {
2501                 MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHODCONST, method);
2502                 method_reg = ins->dreg;
2503         }
2504
2505         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2506 }
2507
2508 static MonoJumpInfo *
2509 mono_patch_info_new (MonoMemPool *mp, int ip, MonoJumpInfoType type, gconstpointer target)
2510 {
2511         MonoJumpInfo *ji = (MonoJumpInfo *)mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
2512
2513         ji->ip.i = ip;
2514         ji->type = type;
2515         ji->data.target = target;
2516
2517         return ji;
2518 }
2519
2520 static int
2521 mini_class_check_context_used (MonoCompile *cfg, MonoClass *klass)
2522 {
2523         if (cfg->gshared)
2524                 return mono_class_check_context_used (klass);
2525         else
2526                 return 0;
2527 }
2528
2529 static int
2530 mini_method_check_context_used (MonoCompile *cfg, MonoMethod *method)
2531 {
2532         if (cfg->gshared)
2533                 return mono_method_check_context_used (method);
2534         else
2535                 return 0;
2536 }
2537
2538 /*
2539  * check_method_sharing:
2540  *
2541  *   Check whenever the vtable or an mrgctx needs to be passed when calling CMETHOD.
2542  */
2543 static void
2544 check_method_sharing (MonoCompile *cfg, MonoMethod *cmethod, gboolean *out_pass_vtable, gboolean *out_pass_mrgctx)
2545 {
2546         gboolean pass_vtable = FALSE;
2547         gboolean pass_mrgctx = FALSE;
2548
2549         if (((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
2550                 (cmethod->klass->generic_class || cmethod->klass->generic_container)) {
2551                 gboolean sharable = FALSE;
2552
2553                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE))
2554                         sharable = TRUE;
2555
2556                 /*
2557                  * Pass vtable iff target method might
2558                  * be shared, which means that sharing
2559                  * is enabled for its class and its
2560                  * context is sharable (and it's not a
2561                  * generic method).
2562                  */
2563                 if (sharable && !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
2564                         pass_vtable = TRUE;
2565         }
2566
2567         if (mini_method_get_context (cmethod) &&
2568                 mini_method_get_context (cmethod)->method_inst) {
2569                 g_assert (!pass_vtable);
2570
2571                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE)) {
2572                         pass_mrgctx = TRUE;
2573                 } else {
2574                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (mono_method_signature (cmethod)))
2575                                 pass_mrgctx = TRUE;
2576                 }
2577         }
2578
2579         if (out_pass_vtable)
2580                 *out_pass_vtable = pass_vtable;
2581         if (out_pass_mrgctx)
2582                 *out_pass_mrgctx = pass_mrgctx;
2583 }
2584
2585 inline static MonoCallInst *
2586 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
2587                                          MonoInst **args, int calli, int virtual_, int tail, int rgctx, int unbox_trampoline)
2588 {
2589         MonoType *sig_ret;
2590         MonoCallInst *call;
2591 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2592         int i;
2593 #endif
2594
2595         if (cfg->llvm_only)
2596                 tail = FALSE;
2597
2598         if (tail) {
2599                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
2600
2601                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
2602         } else
2603                 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (cfg, sig->ret, calli, virtual_));
2604
2605         call->args = args;
2606         call->signature = sig;
2607         call->rgctx_reg = rgctx;
2608         sig_ret = mini_get_underlying_type (sig->ret);
2609
2610         type_to_eval_stack_type ((cfg), sig_ret, &call->inst);
2611
2612         if (tail) {
2613                 if (mini_type_is_vtype (sig_ret)) {
2614                         call->vret_var = cfg->vret_addr;
2615                         //g_assert_not_reached ();
2616                 }
2617         } else if (mini_type_is_vtype (sig_ret)) {
2618                 MonoInst *temp = mono_compile_create_var (cfg, sig_ret, OP_LOCAL);
2619                 MonoInst *loada;
2620
2621                 temp->backend.is_pinvoke = sig->pinvoke;
2622
2623                 /*
2624                  * We use a new opcode OP_OUTARG_VTRETADDR instead of LDADDR for emitting the
2625                  * address of return value to increase optimization opportunities.
2626                  * Before vtype decomposition, the dreg of the call ins itself represents the
2627                  * fact the call modifies the return value. After decomposition, the call will
2628                  * be transformed into one of the OP_VOIDCALL opcodes, and the VTRETADDR opcode
2629                  * will be transformed into an LDADDR.
2630                  */
2631                 MONO_INST_NEW (cfg, loada, OP_OUTARG_VTRETADDR);
2632                 loada->dreg = alloc_preg (cfg);
2633                 loada->inst_p0 = temp;
2634                 /* We reference the call too since call->dreg could change during optimization */
2635                 loada->inst_p1 = call;
2636                 MONO_ADD_INS (cfg->cbb, loada);
2637
2638                 call->inst.dreg = temp->dreg;
2639
2640                 call->vret_var = loada;
2641         } else if (!MONO_TYPE_IS_VOID (sig_ret))
2642                 call->inst.dreg = alloc_dreg (cfg, (MonoStackType)call->inst.type);
2643
2644 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2645         if (COMPILE_SOFT_FLOAT (cfg)) {
2646                 /* 
2647                  * If the call has a float argument, we would need to do an r8->r4 conversion using 
2648                  * an icall, but that cannot be done during the call sequence since it would clobber
2649                  * the call registers + the stack. So we do it before emitting the call.
2650                  */
2651                 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2652                         MonoType *t;
2653                         MonoInst *in = call->args [i];
2654
2655                         if (i >= sig->hasthis)
2656                                 t = sig->params [i - sig->hasthis];
2657                         else
2658                                 t = &mono_defaults.int_class->byval_arg;
2659                         t = mono_type_get_underlying_type (t);
2660
2661                         if (!t->byref && t->type == MONO_TYPE_R4) {
2662                                 MonoInst *iargs [1];
2663                                 MonoInst *conv;
2664
2665                                 iargs [0] = in;
2666                                 conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
2667
2668                                 /* The result will be in an int vreg */
2669                                 call->args [i] = conv;
2670                         }
2671                 }
2672         }
2673 #endif
2674
2675         call->need_unbox_trampoline = unbox_trampoline;
2676
2677 #ifdef ENABLE_LLVM
2678         if (COMPILE_LLVM (cfg))
2679                 mono_llvm_emit_call (cfg, call);
2680         else
2681                 mono_arch_emit_call (cfg, call);
2682 #else
2683         mono_arch_emit_call (cfg, call);
2684 #endif
2685
2686         cfg->param_area = MAX (cfg->param_area, call->stack_usage);
2687         cfg->flags |= MONO_CFG_HAS_CALLS;
2688         
2689         return call;
2690 }
2691
2692 static void
2693 set_rgctx_arg (MonoCompile *cfg, MonoCallInst *call, int rgctx_reg, MonoInst *rgctx_arg)
2694 {
2695         mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
2696         cfg->uses_rgctx_reg = TRUE;
2697         call->rgctx_reg = TRUE;
2698 #ifdef ENABLE_LLVM
2699         call->rgctx_arg_reg = rgctx_reg;
2700 #endif
2701 }       
2702
2703 inline static MonoInst*
2704 mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg)
2705 {
2706         MonoCallInst *call;
2707         MonoInst *ins;
2708         int rgctx_reg = -1;
2709         gboolean check_sp = FALSE;
2710
2711         if (cfg->check_pinvoke_callconv && cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
2712                 WrapperInfo *info = mono_marshal_get_wrapper_info (cfg->method);
2713
2714                 if (info && info->subtype == WRAPPER_SUBTYPE_PINVOKE)
2715                         check_sp = TRUE;
2716         }
2717
2718         if (rgctx_arg) {
2719                 rgctx_reg = mono_alloc_preg (cfg);
2720                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2721         }
2722
2723         if (check_sp) {
2724                 if (!cfg->stack_inbalance_var)
2725                         cfg->stack_inbalance_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2726
2727                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2728                 ins->dreg = cfg->stack_inbalance_var->dreg;
2729                 MONO_ADD_INS (cfg->cbb, ins);
2730         }
2731
2732         call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE, FALSE);
2733
2734         call->inst.sreg1 = addr->dreg;
2735
2736         if (imt_arg)
2737                 emit_imt_argument (cfg, call, NULL, imt_arg);
2738
2739         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2740
2741         if (check_sp) {
2742                 int sp_reg;
2743
2744                 sp_reg = mono_alloc_preg (cfg);
2745
2746                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2747                 ins->dreg = sp_reg;
2748                 MONO_ADD_INS (cfg->cbb, ins);
2749
2750                 /* Restore the stack so we don't crash when throwing the exception */
2751                 MONO_INST_NEW (cfg, ins, OP_SET_SP);
2752                 ins->sreg1 = cfg->stack_inbalance_var->dreg;
2753                 MONO_ADD_INS (cfg->cbb, ins);
2754
2755                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, cfg->stack_inbalance_var->dreg, sp_reg);
2756                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ExecutionEngineException");
2757         }
2758
2759         if (rgctx_arg)
2760                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2761
2762         return (MonoInst*)call;
2763 }
2764
2765 static MonoInst*
2766 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2767
2768 static MonoInst*
2769 emit_get_rgctx_method (MonoCompile *cfg, int context_used, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type);
2770 static MonoInst*
2771 emit_get_rgctx_klass (MonoCompile *cfg, int context_used, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2772
2773 static MonoInst*
2774 mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig, gboolean tail,
2775                                                         MonoInst **args, MonoInst *this_ins, MonoInst *imt_arg, MonoInst *rgctx_arg)
2776 {
2777 #ifndef DISABLE_REMOTING
2778         gboolean might_be_remote = FALSE;
2779 #endif
2780         gboolean virtual_ = this_ins != NULL;
2781         gboolean enable_for_aot = TRUE;
2782         int context_used;
2783         MonoCallInst *call;
2784         MonoInst *call_target = NULL;
2785         int rgctx_reg = 0;
2786         gboolean need_unbox_trampoline;
2787
2788         if (!sig)
2789                 sig = mono_method_signature (method);
2790
2791         if (cfg->llvm_only && (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE))
2792                 g_assert_not_reached ();
2793
2794         if (rgctx_arg) {
2795                 rgctx_reg = mono_alloc_preg (cfg);
2796                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2797         }
2798
2799         if (method->string_ctor) {
2800                 /* Create the real signature */
2801                 /* FIXME: Cache these */
2802                 MonoMethodSignature *ctor_sig = mono_metadata_signature_dup_mempool (cfg->mempool, sig);
2803                 ctor_sig->ret = &mono_defaults.string_class->byval_arg;
2804
2805                 sig = ctor_sig;
2806         }
2807
2808         context_used = mini_method_check_context_used (cfg, method);
2809
2810 #ifndef DISABLE_REMOTING
2811         might_be_remote = this_ins && sig->hasthis &&
2812                 (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) &&
2813                 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && (!MONO_CHECK_THIS (this_ins) || context_used);
2814
2815         if (might_be_remote && context_used) {
2816                 MonoInst *addr;
2817
2818                 g_assert (cfg->gshared);
2819
2820                 addr = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK);
2821
2822                 return mono_emit_calli (cfg, sig, args, addr, NULL, NULL);
2823         }
2824 #endif
2825
2826         if (cfg->llvm_only && !call_target && virtual_ && (method->flags & METHOD_ATTRIBUTE_VIRTUAL))
2827                 return emit_llvmonly_virtual_call (cfg, method, sig, 0, args);
2828
2829         need_unbox_trampoline = method->klass == mono_defaults.object_class || (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
2830
2831         call = mono_emit_call_args (cfg, sig, args, FALSE, virtual_, tail, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline);
2832
2833 #ifndef DISABLE_REMOTING
2834         if (might_be_remote)
2835                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2836         else
2837 #endif
2838                 call->method = method;
2839         call->inst.flags |= MONO_INST_HAS_METHOD;
2840         call->inst.inst_left = this_ins;
2841         call->tail_call = tail;
2842
2843         if (virtual_) {
2844                 int vtable_reg, slot_reg, this_reg;
2845                 int offset;
2846
2847                 this_reg = this_ins->dreg;
2848
2849                 if (!cfg->llvm_only && (method->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (method->name, "Invoke")) {
2850                         MonoInst *dummy_use;
2851
2852                         MONO_EMIT_NULL_CHECK (cfg, this_reg);
2853
2854                         /* Make a call to delegate->invoke_impl */
2855                         call->inst.inst_basereg = this_reg;
2856                         call->inst.inst_offset = MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl);
2857                         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2858
2859                         /* We must emit a dummy use here because the delegate trampoline will
2860                         replace the 'this' argument with the delegate target making this activation
2861                         no longer a root for the delegate.
2862                         This is an issue for delegates that target collectible code such as dynamic
2863                         methods of GC'able assemblies.
2864
2865                         For a test case look into #667921.
2866
2867                         FIXME: a dummy use is not the best way to do it as the local register allocator
2868                         will put it on a caller save register and spil it around the call. 
2869                         Ideally, we would either put it on a callee save register or only do the store part.  
2870                          */
2871                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, args [0]);
2872
2873                         return (MonoInst*)call;
2874                 }
2875
2876                 if ((!cfg->compile_aot || enable_for_aot) && 
2877                         (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || 
2878                          (MONO_METHOD_IS_FINAL (method) &&
2879                           method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)) &&
2880                         !(mono_class_is_marshalbyref (method->klass) && context_used)) {
2881                         /* 
2882                          * the method is not virtual, we just need to ensure this is not null
2883                          * and then we can call the method directly.
2884                          */
2885 #ifndef DISABLE_REMOTING
2886                         if (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) {
2887                                 /* 
2888                                  * The check above ensures method is not gshared, this is needed since
2889                                  * gshared methods can't have wrappers.
2890                                  */
2891                                 method = call->method = mono_marshal_get_remoting_invoke_with_check (method);
2892                         }
2893 #endif
2894
2895                         if (!method->string_ctor)
2896                                 MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2897
2898                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2899                 } else if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && MONO_METHOD_IS_FINAL (method)) {
2900                         /*
2901                          * the method is virtual, but we can statically dispatch since either
2902                          * it's class or the method itself are sealed.
2903                          * But first we need to ensure it's not a null reference.
2904                          */
2905                         MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2906
2907                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2908                 } else if (call_target) {
2909                         vtable_reg = alloc_preg (cfg);
2910                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2911
2912                         call->inst.opcode = callvirt_to_call_reg (call->inst.opcode);
2913                         call->inst.sreg1 = call_target->dreg;
2914                         call->inst.flags &= !MONO_INST_HAS_METHOD;
2915                 } else {
2916                         vtable_reg = alloc_preg (cfg);
2917                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2918                         if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2919                                 guint32 imt_slot = mono_method_get_imt_slot (method);
2920                                 emit_imt_argument (cfg, call, call->method, imt_arg);
2921                                 slot_reg = vtable_reg;
2922                                 offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
2923                         } else {
2924                                 slot_reg = vtable_reg;
2925                                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) +
2926                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
2927                                 if (imt_arg) {
2928                                         g_assert (mono_method_signature (method)->generic_param_count);
2929                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2930                                 }
2931                         }
2932
2933                         call->inst.sreg1 = slot_reg;
2934                         call->inst.inst_offset = offset;
2935                         call->is_virtual = TRUE;
2936                 }
2937         }
2938
2939         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2940
2941         if (rgctx_arg)
2942                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2943
2944         return (MonoInst*)call;
2945 }
2946
2947 MonoInst*
2948 mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoInst **args, MonoInst *this_ins)
2949 {
2950         return mono_emit_method_call_full (cfg, method, mono_method_signature (method), FALSE, args, this_ins, NULL, NULL);
2951 }
2952
2953 MonoInst*
2954 mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig,
2955                                            MonoInst **args)
2956 {
2957         MonoCallInst *call;
2958
2959         g_assert (sig);
2960
2961         call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE, FALSE, FALSE);
2962         call->fptr = func;
2963
2964         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2965
2966         return (MonoInst*)call;
2967 }
2968
2969 MonoInst*
2970 mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args)
2971 {
2972         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2973
2974         g_assert (info);
2975
2976         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2977 }
2978
2979 /*
2980  * mono_emit_abs_call:
2981  *
2982  *   Emit a call to the runtime function described by PATCH_TYPE and DATA.
2983  */
2984 inline static MonoInst*
2985 mono_emit_abs_call (MonoCompile *cfg, MonoJumpInfoType patch_type, gconstpointer data, 
2986                                         MonoMethodSignature *sig, MonoInst **args)
2987 {
2988         MonoJumpInfo *ji = mono_patch_info_new (cfg->mempool, 0, patch_type, data);
2989         MonoInst *ins;
2990
2991         /* 
2992          * We pass ji as the call address, the PATCH_INFO_ABS resolving code will
2993          * handle it.
2994          */
2995         if (cfg->abs_patches == NULL)
2996                 cfg->abs_patches = g_hash_table_new (NULL, NULL);
2997         g_hash_table_insert (cfg->abs_patches, ji, ji);
2998         ins = mono_emit_native_call (cfg, ji, sig, args);
2999         ((MonoCallInst*)ins)->fptr_is_patch = TRUE;
3000         return ins;
3001 }
3002
3003 static MonoMethodSignature*
3004 sig_to_rgctx_sig (MonoMethodSignature *sig)
3005 {
3006         // FIXME: memory allocation
3007         MonoMethodSignature *res;
3008         int i;
3009
3010         res = (MonoMethodSignature *)g_malloc (MONO_SIZEOF_METHOD_SIGNATURE + (sig->param_count + 1) * sizeof (MonoType*));
3011         memcpy (res, sig, MONO_SIZEOF_METHOD_SIGNATURE);
3012         res->param_count = sig->param_count + 1;
3013         for (i = 0; i < sig->param_count; ++i)
3014                 res->params [i] = sig->params [i];
3015         res->params [sig->param_count] = &mono_defaults.int_class->this_arg;
3016         return res;
3017 }
3018
3019 /* Make an indirect call to FSIG passing an additional argument */
3020 static MonoInst*
3021 emit_extra_arg_calli (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **orig_args, int arg_reg, MonoInst *call_target)
3022 {
3023         MonoMethodSignature *csig;
3024         MonoInst *args_buf [16];
3025         MonoInst **args;
3026         int i, pindex, tmp_reg;
3027
3028         /* Make a call with an rgctx/extra arg */
3029         if (fsig->param_count + 2 < 16)
3030                 args = args_buf;
3031         else
3032                 args = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (fsig->param_count + 2));
3033         pindex = 0;
3034         if (fsig->hasthis)
3035                 args [pindex ++] = orig_args [0];
3036         for (i = 0; i < fsig->param_count; ++i)
3037                 args [pindex ++] = orig_args [fsig->hasthis + i];
3038         tmp_reg = alloc_preg (cfg);
3039         EMIT_NEW_UNALU (cfg, args [pindex], OP_MOVE, tmp_reg, arg_reg);
3040         csig = sig_to_rgctx_sig (fsig);
3041         return mono_emit_calli (cfg, csig, args, call_target, NULL, NULL);
3042 }
3043
3044 /* Emit an indirect call to the function descriptor ADDR */
3045 static MonoInst*
3046 emit_llvmonly_calli (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, MonoInst *addr)
3047 {
3048         int addr_reg, arg_reg;
3049         MonoInst *call_target;
3050
3051         g_assert (cfg->llvm_only);
3052
3053         /*
3054          * addr points to a <addr, arg> pair, load both of them, and
3055          * make a call to addr, passing arg as an extra arg.
3056          */
3057         addr_reg = alloc_preg (cfg);
3058         EMIT_NEW_LOAD_MEMBASE (cfg, call_target, OP_LOAD_MEMBASE, addr_reg, addr->dreg, 0);
3059         arg_reg = alloc_preg (cfg);
3060         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, arg_reg, addr->dreg, sizeof (gpointer));
3061
3062         return emit_extra_arg_calli (cfg, fsig, args, arg_reg, call_target);
3063 }
3064
3065 static gboolean
3066 direct_icalls_enabled (MonoCompile *cfg)
3067 {
3068         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
3069 #ifdef TARGET_AMD64
3070         if (cfg->compile_llvm)
3071                 return FALSE;
3072 #endif
3073         if (cfg->gen_sdb_seq_points || cfg->disable_direct_icalls)
3074                 return FALSE;
3075         return TRUE;
3076 }
3077
3078 MonoInst*
3079 mono_emit_jit_icall_by_info (MonoCompile *cfg, MonoJitICallInfo *info, MonoInst **args)
3080 {
3081         /*
3082          * Call the jit icall without a wrapper if possible.
3083          * The wrapper is needed for the following reasons:
3084          * - to handle exceptions thrown using mono_raise_exceptions () from the
3085          *   icall function. The EH code needs the lmf frame pushed by the
3086          *   wrapper to be able to unwind back to managed code.
3087          * - to be able to do stack walks for asynchronously suspended
3088          *   threads when debugging.
3089          */
3090         if (info->no_raise && direct_icalls_enabled (cfg)) {
3091                 char *name;
3092                 int costs;
3093
3094                 if (!info->wrapper_method) {
3095                         name = g_strdup_printf ("__icall_wrapper_%s", info->name);
3096                         info->wrapper_method = mono_marshal_get_icall_wrapper (info->sig, name, info->func, TRUE);
3097                         g_free (name);
3098                         mono_memory_barrier ();
3099                 }
3100
3101                 /*
3102                  * Inline the wrapper method, which is basically a call to the C icall, and
3103                  * an exception check.
3104                  */
3105                 costs = inline_method (cfg, info->wrapper_method, NULL,
3106                                                            args, NULL, cfg->real_offset, TRUE);
3107                 g_assert (costs > 0);
3108                 g_assert (!MONO_TYPE_IS_VOID (info->sig->ret));
3109
3110                 return args [0];
3111         } else {
3112                 return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
3113         }
3114 }
3115  
3116 static MonoInst*
3117 mono_emit_widen_call_res (MonoCompile *cfg, MonoInst *ins, MonoMethodSignature *fsig)
3118 {
3119         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
3120                 if ((fsig->pinvoke || LLVM_ENABLED) && !fsig->ret->byref) {
3121                         int widen_op = -1;
3122
3123                         /* 
3124                          * Native code might return non register sized integers 
3125                          * without initializing the upper bits.
3126                          */
3127                         switch (mono_type_to_load_membase (cfg, fsig->ret)) {
3128                         case OP_LOADI1_MEMBASE:
3129                                 widen_op = OP_ICONV_TO_I1;
3130                                 break;
3131                         case OP_LOADU1_MEMBASE:
3132                                 widen_op = OP_ICONV_TO_U1;
3133                                 break;
3134                         case OP_LOADI2_MEMBASE:
3135                                 widen_op = OP_ICONV_TO_I2;
3136                                 break;
3137                         case OP_LOADU2_MEMBASE:
3138                                 widen_op = OP_ICONV_TO_U2;
3139                                 break;
3140                         default:
3141                                 break;
3142                         }
3143
3144                         if (widen_op != -1) {
3145                                 int dreg = alloc_preg (cfg);
3146                                 MonoInst *widen;
3147
3148                                 EMIT_NEW_UNALU (cfg, widen, widen_op, dreg, ins->dreg);
3149                                 widen->type = ins->type;
3150                                 ins = widen;
3151                         }
3152                 }
3153         }
3154
3155         return ins;
3156 }
3157
3158 static MonoMethod*
3159 get_memcpy_method (void)
3160 {
3161         static MonoMethod *memcpy_method = NULL;
3162         if (!memcpy_method) {
3163                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
3164                 if (!memcpy_method)
3165                         g_error ("Old corlib found. Install a new one");
3166         }
3167         return memcpy_method;
3168 }
3169
3170 static void
3171 create_write_barrier_bitmap (MonoCompile *cfg, MonoClass *klass, unsigned *wb_bitmap, int offset)
3172 {
3173         MonoClassField *field;
3174         gpointer iter = NULL;
3175
3176         while ((field = mono_class_get_fields (klass, &iter))) {
3177                 int foffset;
3178
3179                 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3180                         continue;
3181                 foffset = klass->valuetype ? field->offset - sizeof (MonoObject): field->offset;
3182                 if (mini_type_is_reference (mono_field_get_type (field))) {
3183                         g_assert ((foffset % SIZEOF_VOID_P) == 0);
3184                         *wb_bitmap |= 1 << ((offset + foffset) / SIZEOF_VOID_P);
3185                 } else {
3186                         MonoClass *field_class = mono_class_from_mono_type (field->type);
3187                         if (field_class->has_references)
3188                                 create_write_barrier_bitmap (cfg, field_class, wb_bitmap, offset + foffset);
3189                 }
3190         }
3191 }
3192
3193 static void
3194 emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value)
3195 {
3196         int card_table_shift_bits;
3197         gpointer card_table_mask;
3198         guint8 *card_table;
3199         MonoInst *dummy_use;
3200         int nursery_shift_bits;
3201         size_t nursery_size;
3202
3203         if (!cfg->gen_write_barriers)
3204                 return;
3205
3206         card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
3207
3208         mono_gc_get_nursery (&nursery_shift_bits, &nursery_size);
3209
3210         if (cfg->backend->have_card_table_wb && !cfg->compile_aot && card_table && nursery_shift_bits > 0 && !COMPILE_LLVM (cfg)) {
3211                 MonoInst *wbarrier;
3212
3213                 MONO_INST_NEW (cfg, wbarrier, OP_CARD_TABLE_WBARRIER);
3214                 wbarrier->sreg1 = ptr->dreg;
3215                 wbarrier->sreg2 = value->dreg;
3216                 MONO_ADD_INS (cfg->cbb, wbarrier);
3217         } else if (card_table && !cfg->compile_aot && !mono_gc_card_table_nursery_check ()) {
3218                 int offset_reg = alloc_preg (cfg);
3219                 int card_reg;
3220                 MonoInst *ins;
3221
3222                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, offset_reg, ptr->dreg, card_table_shift_bits);
3223                 if (card_table_mask)
3224                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, offset_reg, offset_reg, card_table_mask);
3225
3226                 /*We can't use PADD_IMM since the cardtable might end up in high addresses and amd64 doesn't support
3227                  * IMM's larger than 32bits.
3228                  */
3229                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
3230                 card_reg = ins->dreg;
3231
3232                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, offset_reg, offset_reg, card_reg);
3233                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, offset_reg, 0, 1);
3234         } else {
3235                 MonoMethod *write_barrier = mono_gc_get_write_barrier ();
3236                 mono_emit_method_call (cfg, write_barrier, &ptr, NULL);
3237         }
3238
3239         EMIT_NEW_DUMMY_USE (cfg, dummy_use, value);
3240 }
3241
3242 static gboolean
3243 mono_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align)
3244 {
3245         int dest_ptr_reg, tmp_reg, destreg, srcreg, offset;
3246         unsigned need_wb = 0;
3247
3248         if (align == 0)
3249                 align = 4;
3250
3251         /*types with references can't have alignment smaller than sizeof(void*) */
3252         if (align < SIZEOF_VOID_P)
3253                 return FALSE;
3254
3255         /*This value cannot be bigger than 32 due to the way we calculate the required wb bitmap.*/
3256         if (size > 32 * SIZEOF_VOID_P)
3257                 return FALSE;
3258
3259         create_write_barrier_bitmap (cfg, klass, &need_wb, 0);
3260
3261         /* We don't unroll more than 5 stores to avoid code bloat. */
3262         if (size > 5 * SIZEOF_VOID_P) {
3263                 /*This is harmless and simplify mono_gc_wbarrier_value_copy_bitmap */
3264                 size += (SIZEOF_VOID_P - 1);
3265                 size &= ~(SIZEOF_VOID_P - 1);
3266
3267                 EMIT_NEW_ICONST (cfg, iargs [2], size);
3268                 EMIT_NEW_ICONST (cfg, iargs [3], need_wb);
3269                 mono_emit_jit_icall (cfg, mono_gc_wbarrier_value_copy_bitmap, iargs);
3270                 return TRUE;
3271         }
3272
3273         destreg = iargs [0]->dreg;
3274         srcreg = iargs [1]->dreg;
3275         offset = 0;
3276
3277         dest_ptr_reg = alloc_preg (cfg);
3278         tmp_reg = alloc_preg (cfg);
3279
3280         /*tmp = dreg*/
3281         EMIT_NEW_UNALU (cfg, iargs [0], OP_MOVE, dest_ptr_reg, destreg);
3282
3283         while (size >= SIZEOF_VOID_P) {
3284                 MonoInst *load_inst;
3285                 MONO_INST_NEW (cfg, load_inst, OP_LOAD_MEMBASE);
3286                 load_inst->dreg = tmp_reg;
3287                 load_inst->inst_basereg = srcreg;
3288                 load_inst->inst_offset = offset;
3289                 MONO_ADD_INS (cfg->cbb, load_inst);
3290
3291                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, dest_ptr_reg, 0, tmp_reg);
3292
3293                 if (need_wb & 0x1)
3294                         emit_write_barrier (cfg, iargs [0], load_inst);
3295
3296                 offset += SIZEOF_VOID_P;
3297                 size -= SIZEOF_VOID_P;
3298                 need_wb >>= 1;
3299
3300                 /*tmp += sizeof (void*)*/
3301                 if (size >= SIZEOF_VOID_P) {
3302                         NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dest_ptr_reg, dest_ptr_reg, SIZEOF_VOID_P);
3303                         MONO_ADD_INS (cfg->cbb, iargs [0]);
3304                 }
3305         }
3306
3307         /* Those cannot be references since size < sizeof (void*) */
3308         while (size >= 4) {
3309                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tmp_reg, srcreg, offset);
3310                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, tmp_reg);
3311                 offset += 4;
3312                 size -= 4;
3313         }
3314
3315         while (size >= 2) {
3316                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmp_reg, srcreg, offset);
3317                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, tmp_reg);
3318                 offset += 2;
3319                 size -= 2;
3320         }
3321
3322         while (size >= 1) {
3323                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmp_reg, srcreg, offset);
3324                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, tmp_reg);
3325                 offset += 1;
3326                 size -= 1;
3327         }
3328
3329         return TRUE;
3330 }
3331
3332 /*
3333  * Emit code to copy a valuetype of type @klass whose address is stored in
3334  * @src->dreg to memory whose address is stored at @dest->dreg.
3335  */
3336 void
3337 mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native)
3338 {
3339         MonoInst *iargs [4];
3340         int n;
3341         guint32 align = 0;
3342         MonoMethod *memcpy_method;
3343         MonoInst *size_ins = NULL;
3344         MonoInst *memcpy_ins = NULL;
3345
3346         g_assert (klass);
3347         if (cfg->gshared)
3348                 klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg));
3349
3350         /*
3351          * This check breaks with spilled vars... need to handle it during verification anyway.
3352          * g_assert (klass && klass == src->klass && klass == dest->klass);
3353          */
3354
3355         if (mini_is_gsharedvt_klass (klass)) {
3356                 g_assert (!native);
3357                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3358                 memcpy_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_MEMCPY);
3359         }
3360
3361         if (native)
3362                 n = mono_class_native_size (klass, &align);
3363         else
3364                 n = mono_class_value_size (klass, &align);
3365
3366         /* if native is true there should be no references in the struct */
3367         if (cfg->gen_write_barriers && (klass->has_references || size_ins) && !native) {
3368                 /* Avoid barriers when storing to the stack */
3369                 if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) ||
3370                           (dest->opcode == OP_LDADDR))) {
3371                         int context_used;
3372
3373                         iargs [0] = dest;
3374                         iargs [1] = src;
3375
3376                         context_used = mini_class_check_context_used (cfg, klass);
3377
3378                         /* It's ok to intrinsify under gsharing since shared code types are layout stable. */
3379                         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && mono_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
3380                                 return;
3381                         } else if (context_used) {
3382                                 iargs [2] = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3383                         }  else {
3384                                 iargs [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
3385                                 if (!cfg->compile_aot)
3386                                         mono_class_compute_gc_descriptor (klass);
3387                         }
3388
3389                         if (size_ins)
3390                                 mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs);
3391                         else
3392                                 mono_emit_jit_icall (cfg, mono_value_copy, iargs);
3393                         return;
3394                 }
3395         }
3396
3397         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 8) {
3398                 /* FIXME: Optimize the case when src/dest is OP_LDADDR */
3399                 mini_emit_memcpy (cfg, dest->dreg, 0, src->dreg, 0, n, align);
3400         } else {
3401                 iargs [0] = dest;
3402                 iargs [1] = src;
3403                 if (size_ins)
3404                         iargs [2] = size_ins;
3405                 else
3406                         EMIT_NEW_ICONST (cfg, iargs [2], n);
3407                 
3408                 memcpy_method = get_memcpy_method ();
3409                 if (memcpy_ins)
3410                         mono_emit_calli (cfg, mono_method_signature (memcpy_method), iargs, memcpy_ins, NULL, NULL);
3411                 else
3412                         mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
3413         }
3414 }
3415
3416 static MonoMethod*
3417 get_memset_method (void)
3418 {
3419         static MonoMethod *memset_method = NULL;
3420         if (!memset_method) {
3421                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
3422                 if (!memset_method)
3423                         g_error ("Old corlib found. Install a new one");
3424         }
3425         return memset_method;
3426 }
3427
3428 void
3429 mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass)
3430 {
3431         MonoInst *iargs [3];
3432         int n;
3433         guint32 align;
3434         MonoMethod *memset_method;
3435         MonoInst *size_ins = NULL;
3436         MonoInst *bzero_ins = NULL;
3437         static MonoMethod *bzero_method;
3438
3439         /* FIXME: Optimize this for the case when dest is an LDADDR */
3440         mono_class_init (klass);
3441         if (mini_is_gsharedvt_klass (klass)) {
3442                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3443                 bzero_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_BZERO);
3444                 if (!bzero_method)
3445                         bzero_method = mono_class_get_method_from_name (mono_defaults.string_class, "bzero_aligned_1", 2);
3446                 g_assert (bzero_method);
3447                 iargs [0] = dest;
3448                 iargs [1] = size_ins;
3449                 mono_emit_calli (cfg, mono_method_signature (bzero_method), iargs, bzero_ins, NULL, NULL);
3450                 return;
3451         }
3452
3453         klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg));
3454
3455         n = mono_class_value_size (klass, &align);
3456
3457         if (n <= sizeof (gpointer) * 8) {
3458                 mini_emit_memset (cfg, dest->dreg, 0, n, 0, align);
3459         }
3460         else {
3461                 memset_method = get_memset_method ();
3462                 iargs [0] = dest;
3463                 EMIT_NEW_ICONST (cfg, iargs [1], 0);
3464                 EMIT_NEW_ICONST (cfg, iargs [2], n);
3465                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
3466         }
3467 }
3468
3469 /*
3470  * emit_get_rgctx:
3471  *
3472  *   Emit IR to return either the this pointer for instance method,
3473  * or the mrgctx for static methods.
3474  */
3475 static MonoInst*
3476 emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used)
3477 {
3478         MonoInst *this_ins = NULL;
3479
3480         g_assert (cfg->gshared);
3481
3482         if (!(method->flags & METHOD_ATTRIBUTE_STATIC) &&
3483                         !(context_used & MONO_GENERIC_CONTEXT_USED_METHOD) &&
3484                         !method->klass->valuetype)
3485                 EMIT_NEW_ARGLOAD (cfg, this_ins, 0);
3486
3487         if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
3488                 MonoInst *mrgctx_loc, *mrgctx_var;
3489
3490                 g_assert (!this_ins);
3491                 g_assert (method->is_inflated && mono_method_get_context (method)->method_inst);
3492
3493                 mrgctx_loc = mono_get_vtable_var (cfg);
3494                 EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
3495
3496                 return mrgctx_var;
3497         } else if (method->flags & METHOD_ATTRIBUTE_STATIC || method->klass->valuetype) {
3498                 MonoInst *vtable_loc, *vtable_var;
3499
3500                 g_assert (!this_ins);
3501
3502                 vtable_loc = mono_get_vtable_var (cfg);
3503                 EMIT_NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
3504
3505                 if (method->is_inflated && mono_method_get_context (method)->method_inst) {
3506                         MonoInst *mrgctx_var = vtable_var;
3507                         int vtable_reg;
3508
3509                         vtable_reg = alloc_preg (cfg);
3510                         EMIT_NEW_LOAD_MEMBASE (cfg, vtable_var, OP_LOAD_MEMBASE, vtable_reg, mrgctx_var->dreg, MONO_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, class_vtable));
3511                         vtable_var->type = STACK_PTR;
3512                 }
3513
3514                 return vtable_var;
3515         } else {
3516                 MonoInst *ins;
3517                 int vtable_reg;
3518         
3519                 vtable_reg = alloc_preg (cfg);
3520                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, vtable_reg, this_ins->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3521                 return ins;
3522         }
3523 }
3524
3525 static MonoJumpInfoRgctxEntry *
3526 mono_patch_info_rgctx_entry_new (MonoMemPool *mp, MonoMethod *method, gboolean in_mrgctx, MonoJumpInfoType patch_type, gconstpointer patch_data, MonoRgctxInfoType info_type)
3527 {
3528         MonoJumpInfoRgctxEntry *res = (MonoJumpInfoRgctxEntry *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoRgctxEntry));
3529         res->method = method;
3530         res->in_mrgctx = in_mrgctx;
3531         res->data = (MonoJumpInfo *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
3532         res->data->type = patch_type;
3533         res->data->data.target = patch_data;
3534         res->info_type = info_type;
3535
3536         return res;
3537 }
3538
3539 static inline MonoInst*
3540 emit_rgctx_fetch_inline (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3541 {
3542         MonoInst *args [16];
3543         MonoInst *call;
3544
3545         // FIXME: No fastpath since the slot is not a compile time constant
3546         args [0] = rgctx;
3547         EMIT_NEW_AOTCONST (cfg, args [1], MONO_PATCH_INFO_RGCTX_SLOT_INDEX, entry);
3548         if (entry->in_mrgctx)
3549                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3550         else
3551                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3552         return call;
3553 #if 0
3554         /*
3555          * FIXME: This can be called during decompose, which is a problem since it creates
3556          * new bblocks.
3557          * Also, the fastpath doesn't work since the slot number is dynamically allocated.
3558          */
3559         int i, slot, depth, index, rgctx_reg, val_reg, res_reg;
3560         gboolean mrgctx;
3561         MonoBasicBlock *is_null_bb, *end_bb;
3562         MonoInst *res, *ins, *call;
3563         MonoInst *args[16];
3564
3565         slot = mini_get_rgctx_entry_slot (entry);
3566
3567         mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot);
3568         index = MONO_RGCTX_SLOT_INDEX (slot);
3569         if (mrgctx)
3570                 index += MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
3571         for (depth = 0; ; ++depth) {
3572                 int size = mono_class_rgctx_get_array_size (depth, mrgctx);
3573
3574                 if (index < size - 1)
3575                         break;
3576                 index -= size - 1;
3577         }
3578
3579         NEW_BBLOCK (cfg, end_bb);
3580         NEW_BBLOCK (cfg, is_null_bb);
3581
3582         if (mrgctx) {
3583                 rgctx_reg = rgctx->dreg;
3584         } else {
3585                 rgctx_reg = alloc_preg (cfg);
3586
3587                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, rgctx_reg, rgctx->dreg, MONO_STRUCT_OFFSET (MonoVTable, runtime_generic_context));
3588                 // FIXME: Avoid this check by allocating the table when the vtable is created etc.
3589                 NEW_BBLOCK (cfg, is_null_bb);
3590
3591                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3592                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3593         }
3594
3595         for (i = 0; i < depth; ++i) {
3596                 int array_reg = alloc_preg (cfg);
3597
3598                 /* load ptr to next array */
3599                 if (mrgctx && i == 0)
3600                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT);
3601                 else
3602                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, 0);
3603                 rgctx_reg = array_reg;
3604                 /* is the ptr null? */
3605                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3606                 /* if yes, jump to actual trampoline */
3607                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3608         }
3609
3610         /* fetch slot */
3611         val_reg = alloc_preg (cfg);
3612         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, val_reg, rgctx_reg, (index + 1) * sizeof (gpointer));
3613         /* is the slot null? */
3614         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, val_reg, 0);
3615         /* if yes, jump to actual trampoline */
3616         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3617
3618         /* Fastpath */
3619         res_reg = alloc_preg (cfg);
3620         MONO_INST_NEW (cfg, ins, OP_MOVE);
3621         ins->dreg = res_reg;
3622         ins->sreg1 = val_reg;
3623         MONO_ADD_INS (cfg->cbb, ins);
3624         res = ins;
3625         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3626
3627         /* Slowpath */
3628         MONO_START_BB (cfg, is_null_bb);
3629         args [0] = rgctx;
3630         EMIT_NEW_ICONST (cfg, args [1], index);
3631         if (mrgctx)
3632                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3633         else
3634                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3635         MONO_INST_NEW (cfg, ins, OP_MOVE);
3636         ins->dreg = res_reg;
3637         ins->sreg1 = call->dreg;
3638         MONO_ADD_INS (cfg->cbb, ins);
3639         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3640
3641         MONO_START_BB (cfg, end_bb);
3642
3643         return res;
3644 #endif
3645 }
3646
3647 /*
3648  * emit_rgctx_fetch:
3649  *
3650  *   Emit IR to load the value of the rgctx entry ENTRY from the rgctx
3651  * given by RGCTX.
3652  */
3653 static inline MonoInst*
3654 emit_rgctx_fetch (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3655 {
3656         if (cfg->llvm_only)
3657                 return emit_rgctx_fetch_inline (cfg, rgctx, entry);
3658         else
3659                 return mono_emit_abs_call (cfg, MONO_PATCH_INFO_RGCTX_FETCH, entry, helper_sig_rgctx_lazy_fetch_trampoline, &rgctx);
3660 }
3661
3662 static MonoInst*
3663 emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
3664                                           MonoClass *klass, MonoRgctxInfoType rgctx_type)
3665 {
3666         MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_CLASS, klass, rgctx_type);
3667         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3668
3669         return emit_rgctx_fetch (cfg, rgctx, entry);
3670 }
3671
3672 static MonoInst*
3673 emit_get_rgctx_sig (MonoCompile *cfg, int context_used,
3674                                         MonoMethodSignature *sig, MonoRgctxInfoType rgctx_type)
3675 {
3676         MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_SIGNATURE, sig, rgctx_type);
3677         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3678
3679         return emit_rgctx_fetch (cfg, rgctx, entry);
3680 }
3681
3682 static MonoInst*
3683 emit_get_rgctx_gsharedvt_call (MonoCompile *cfg, int context_used,
3684                                                            MonoMethodSignature *sig, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3685 {
3686         MonoJumpInfoGSharedVtCall *call_info;
3687         MonoJumpInfoRgctxEntry *entry;
3688         MonoInst *rgctx;
3689
3690         call_info = (MonoJumpInfoGSharedVtCall *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoGSharedVtCall));
3691         call_info->sig = sig;
3692         call_info->method = cmethod;
3693
3694         entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_GSHAREDVT_CALL, call_info, rgctx_type);
3695         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3696
3697         return emit_rgctx_fetch (cfg, rgctx, entry);
3698 }
3699
3700 /*
3701  * emit_get_rgctx_virt_method:
3702  *
3703  *   Return data for method VIRT_METHOD for a receiver of type KLASS.
3704  */
3705 static MonoInst*
3706 emit_get_rgctx_virt_method (MonoCompile *cfg, int context_used,
3707                                                         MonoClass *klass, MonoMethod *virt_method, MonoRgctxInfoType rgctx_type)
3708 {
3709         MonoJumpInfoVirtMethod *info;
3710         MonoJumpInfoRgctxEntry *entry;
3711         MonoInst *rgctx;
3712
3713         info = (MonoJumpInfoVirtMethod *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoVirtMethod));
3714         info->klass = klass;
3715         info->method = virt_method;
3716
3717         entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_VIRT_METHOD, info, rgctx_type);
3718         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3719
3720         return emit_rgctx_fetch (cfg, rgctx, entry);
3721 }
3722
3723 static MonoInst*
3724 emit_get_rgctx_gsharedvt_method (MonoCompile *cfg, int context_used,
3725                                                                  MonoMethod *cmethod, MonoGSharedVtMethodInfo *info)
3726 {
3727         MonoJumpInfoRgctxEntry *entry;
3728         MonoInst *rgctx;
3729
3730         entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_GSHAREDVT_METHOD, info, MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO);
3731         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3732
3733         return emit_rgctx_fetch (cfg, rgctx, entry);
3734 }
3735
3736 /*
3737  * emit_get_rgctx_method:
3738  *
3739  *   Emit IR to load the property RGCTX_TYPE of CMETHOD. If context_used is 0, emit
3740  * normal constants, else emit a load from the rgctx.
3741  */
3742 static MonoInst*
3743 emit_get_rgctx_method (MonoCompile *cfg, int context_used,
3744                                            MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3745 {
3746         if (!context_used) {
3747                 MonoInst *ins;
3748
3749                 switch (rgctx_type) {
3750                 case MONO_RGCTX_INFO_METHOD:
3751                         EMIT_NEW_METHODCONST (cfg, ins, cmethod);
3752                         return ins;
3753                 case MONO_RGCTX_INFO_METHOD_RGCTX:
3754                         EMIT_NEW_METHOD_RGCTX_CONST (cfg, ins, cmethod);
3755                         return ins;
3756                 default:
3757                         g_assert_not_reached ();
3758                 }
3759         } else {
3760                 MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_METHODCONST, cmethod, rgctx_type);
3761                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3762
3763                 return emit_rgctx_fetch (cfg, rgctx, entry);
3764         }
3765 }
3766
3767 static MonoInst*
3768 emit_get_rgctx_field (MonoCompile *cfg, int context_used,
3769                                           MonoClassField *field, MonoRgctxInfoType rgctx_type)
3770 {
3771         MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_FIELD, field, rgctx_type);
3772         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3773
3774         return emit_rgctx_fetch (cfg, rgctx, entry);
3775 }
3776
3777 static int
3778 get_gsharedvt_info_slot (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3779 {
3780         MonoGSharedVtMethodInfo *info = cfg->gsharedvt_info;
3781         MonoRuntimeGenericContextInfoTemplate *template_;
3782         int i, idx;
3783
3784         g_assert (info);
3785
3786         for (i = 0; i < info->num_entries; ++i) {
3787                 MonoRuntimeGenericContextInfoTemplate *otemplate = &info->entries [i];
3788
3789                 if (otemplate->info_type == rgctx_type && otemplate->data == data && rgctx_type != MONO_RGCTX_INFO_LOCAL_OFFSET)
3790                         return i;
3791         }
3792
3793         if (info->num_entries == info->count_entries) {
3794                 MonoRuntimeGenericContextInfoTemplate *new_entries;
3795                 int new_count_entries = info->count_entries ? info->count_entries * 2 : 16;
3796
3797                 new_entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * new_count_entries);
3798
3799                 memcpy (new_entries, info->entries, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
3800                 info->entries = new_entries;
3801                 info->count_entries = new_count_entries;
3802         }
3803
3804         idx = info->num_entries;
3805         template_ = &info->entries [idx];
3806         template_->info_type = rgctx_type;
3807         template_->data = data;
3808
3809         info->num_entries ++;
3810
3811         return idx;
3812 }
3813
3814 /*
3815  * emit_get_gsharedvt_info:
3816  *
3817  *   This is similar to emit_get_rgctx_.., but loads the data from the gsharedvt info var instead of calling an rgctx fetch trampoline.
3818  */
3819 static MonoInst*
3820 emit_get_gsharedvt_info (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3821 {
3822         MonoInst *ins;
3823         int idx, dreg;
3824
3825         idx = get_gsharedvt_info_slot (cfg, data, rgctx_type);
3826         /* Load info->entries [idx] */
3827         dreg = alloc_preg (cfg);
3828         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, cfg->gsharedvt_info_var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
3829
3830         return ins;
3831 }
3832
3833 static MonoInst*
3834 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type)
3835 {
3836         return emit_get_gsharedvt_info (cfg, &klass->byval_arg, rgctx_type);
3837 }
3838
3839 /*
3840  * On return the caller must check @klass for load errors.
3841  */
3842 static void
3843 emit_class_init (MonoCompile *cfg, MonoClass *klass)
3844 {
3845         MonoInst *vtable_arg;
3846         int context_used;
3847
3848         context_used = mini_class_check_context_used (cfg, klass);
3849
3850         if (context_used) {
3851                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
3852                                                                                    klass, MONO_RGCTX_INFO_VTABLE);
3853         } else {
3854                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3855
3856                 if (!vtable)
3857                         return;
3858                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
3859         }
3860
3861         if (!COMPILE_LLVM (cfg) && cfg->backend->have_op_generic_class_init) {
3862                 MonoInst *ins;
3863
3864                 /*
3865                  * Using an opcode instead of emitting IR here allows the hiding of the call inside the opcode,
3866                  * so this doesn't have to clobber any regs and it doesn't break basic blocks.
3867                  */
3868                 MONO_INST_NEW (cfg, ins, OP_GENERIC_CLASS_INIT);
3869                 ins->sreg1 = vtable_arg->dreg;
3870                 MONO_ADD_INS (cfg->cbb, ins);
3871         } else {
3872                 static int byte_offset = -1;
3873                 static guint8 bitmask;
3874                 int bits_reg, inited_reg;
3875                 MonoBasicBlock *inited_bb;
3876                 MonoInst *args [16];
3877
3878                 if (byte_offset < 0)
3879                         mono_marshal_find_bitfield_offset (MonoVTable, initialized, &byte_offset, &bitmask);
3880
3881                 bits_reg = alloc_ireg (cfg);
3882                 inited_reg = alloc_ireg (cfg);
3883
3884                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, bits_reg, vtable_arg->dreg, byte_offset);
3885                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, inited_reg, bits_reg, bitmask);
3886
3887                 NEW_BBLOCK (cfg, inited_bb);
3888
3889                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, inited_reg, 0);
3890                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, inited_bb);
3891
3892                 args [0] = vtable_arg;
3893                 mono_emit_jit_icall (cfg, mono_generic_class_init, args);
3894
3895                 MONO_START_BB (cfg, inited_bb);
3896         }
3897 }
3898
3899 static void
3900 emit_seq_point (MonoCompile *cfg, MonoMethod *method, guint8* ip, gboolean intr_loc, gboolean nonempty_stack)
3901 {
3902         MonoInst *ins;
3903
3904         if (cfg->gen_seq_points && cfg->method == method) {
3905                 NEW_SEQ_POINT (cfg, ins, ip - cfg->header->code, intr_loc);
3906                 if (nonempty_stack)
3907                         ins->flags |= MONO_INST_NONEMPTY_STACK;
3908                 MONO_ADD_INS (cfg->cbb, ins);
3909         }
3910 }
3911
3912 static void
3913 save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean null_check)
3914 {
3915         if (mini_get_debug_options ()->better_cast_details) {
3916                 int vtable_reg = alloc_preg (cfg);
3917                 int klass_reg = alloc_preg (cfg);
3918                 MonoBasicBlock *is_null_bb = NULL;
3919                 MonoInst *tls_get;
3920                 int to_klass_reg, context_used;
3921
3922                 if (null_check) {
3923                         NEW_BBLOCK (cfg, is_null_bb);
3924
3925                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3926                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3927                 }
3928
3929                 tls_get = mono_get_jit_tls_intrinsic (cfg);
3930                 if (!tls_get) {
3931                         fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
3932                         exit (1);
3933                 }
3934
3935                 MONO_ADD_INS (cfg->cbb, tls_get);
3936                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3937                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3938
3939                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg);
3940
3941                 context_used = mini_class_check_context_used (cfg, klass);
3942                 if (context_used) {
3943                         MonoInst *class_ins;
3944
3945                         class_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3946                         to_klass_reg = class_ins->dreg;
3947                 } else {
3948                         to_klass_reg = alloc_preg (cfg);
3949                         MONO_EMIT_NEW_CLASSCONST (cfg, to_klass_reg, klass);
3950                 }
3951                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg);
3952
3953                 if (null_check)
3954                         MONO_START_BB (cfg, is_null_bb);
3955         }
3956 }
3957
3958 static void
3959 reset_cast_details (MonoCompile *cfg)
3960 {
3961         /* Reset the variables holding the cast details */
3962         if (mini_get_debug_options ()->better_cast_details) {
3963                 MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
3964
3965                 MONO_ADD_INS (cfg->cbb, tls_get);
3966                 /* It is enough to reset the from field */
3967                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0);
3968         }
3969 }
3970
3971 /*
3972  * On return the caller must check @array_class for load errors
3973  */
3974 static void
3975 mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_class)
3976 {
3977         int vtable_reg = alloc_preg (cfg);
3978         int context_used;
3979
3980         context_used = mini_class_check_context_used (cfg, array_class);
3981
3982         save_cast_details (cfg, array_class, obj->dreg, FALSE);
3983
3984         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3985
3986         if (cfg->opt & MONO_OPT_SHARED) {
3987                 int class_reg = alloc_preg (cfg);
3988                 MonoInst *ins;
3989
3990                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, class_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3991                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, array_class);
3992                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, class_reg, ins->dreg);
3993         } else if (context_used) {
3994                 MonoInst *vtable_ins;
3995
3996                 vtable_ins = emit_get_rgctx_klass (cfg, context_used, array_class, MONO_RGCTX_INFO_VTABLE);
3997                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vtable_ins->dreg);
3998         } else {
3999                 if (cfg->compile_aot) {
4000                         int vt_reg;
4001                         MonoVTable *vtable;
4002
4003                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
4004                                 return;
4005                         vt_reg = alloc_preg (cfg);
4006                         MONO_EMIT_NEW_VTABLECONST (cfg, vt_reg, vtable);
4007                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vt_reg);
4008                 } else {
4009                         MonoVTable *vtable;
4010                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
4011                                 return;
4012                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vtable);
4013                 }
4014         }
4015         
4016         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException");
4017
4018         reset_cast_details (cfg);
4019 }
4020
4021 /**
4022  * Handles unbox of a Nullable<T>. If context_used is non zero, then shared 
4023  * generic code is generated.
4024  */
4025 static MonoInst*
4026 handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int context_used)
4027 {
4028         MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
4029
4030         if (context_used) {
4031                 MonoInst *rgctx, *addr;
4032
4033                 /* FIXME: What if the class is shared?  We might not
4034                    have to get the address of the method from the
4035                    RGCTX. */
4036                 addr = emit_get_rgctx_method (cfg, context_used, method,
4037                                                                           MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4038                 if (cfg->llvm_only && cfg->gsharedvt) {
4039                         return emit_llvmonly_calli (cfg, mono_method_signature (method), &val, addr);
4040                 } else {
4041                         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
4042
4043                         return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
4044                 }
4045         } else {
4046                 gboolean pass_vtable, pass_mrgctx;
4047                 MonoInst *rgctx_arg = NULL;
4048
4049                 check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
4050                 g_assert (!pass_mrgctx);
4051
4052                 if (pass_vtable) {
4053                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4054
4055                         g_assert (vtable);
4056                         EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
4057                 }
4058
4059                 return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4060         }
4061 }
4062
4063 static MonoInst*
4064 handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_used)
4065 {
4066         MonoInst *add;
4067         int obj_reg;
4068         int vtable_reg = alloc_dreg (cfg ,STACK_PTR);
4069         int klass_reg = alloc_dreg (cfg ,STACK_PTR);
4070         int eclass_reg = alloc_dreg (cfg ,STACK_PTR);
4071         int rank_reg = alloc_dreg (cfg ,STACK_I4);
4072
4073         obj_reg = sp [0]->dreg;
4074         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4075         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
4076
4077         /* FIXME: generics */
4078         g_assert (klass->rank == 0);
4079                         
4080         // Check rank == 0
4081         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, 0);
4082         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4083
4084         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4085         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, element_class));
4086
4087         if (context_used) {
4088                 MonoInst *element_class;
4089
4090                 /* This assertion is from the unboxcast insn */
4091                 g_assert (klass->rank == 0);
4092
4093                 element_class = emit_get_rgctx_klass (cfg, context_used,
4094                                 klass, MONO_RGCTX_INFO_ELEMENT_KLASS);
4095
4096                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, eclass_reg, element_class->dreg);
4097                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4098         } else {
4099                 save_cast_details (cfg, klass->element_class, obj_reg, FALSE);
4100                 mini_emit_class_check (cfg, eclass_reg, klass->element_class);
4101                 reset_cast_details (cfg);
4102         }
4103
4104         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), obj_reg, sizeof (MonoObject));
4105         MONO_ADD_INS (cfg->cbb, add);
4106         add->type = STACK_MP;
4107         add->klass = klass;
4108
4109         return add;
4110 }
4111
4112 static MonoInst*
4113 handle_unbox_gsharedvt (MonoCompile *cfg, MonoClass *klass, MonoInst *obj)
4114 {
4115         MonoInst *addr, *klass_inst, *is_ref, *args[16];
4116         MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4117         MonoInst *ins;
4118         int dreg, addr_reg;
4119
4120         klass_inst = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_KLASS);
4121
4122         /* obj */
4123         args [0] = obj;
4124
4125         /* klass */
4126         args [1] = klass_inst;
4127
4128         /* CASTCLASS */
4129         obj = mono_emit_jit_icall (cfg, mono_object_castclass_unbox, args);
4130
4131         NEW_BBLOCK (cfg, is_ref_bb);
4132         NEW_BBLOCK (cfg, is_nullable_bb);
4133         NEW_BBLOCK (cfg, end_bb);
4134         is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4135         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
4136         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4137
4138         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
4139         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4140
4141         /* This will contain either the address of the unboxed vtype, or an address of the temporary where the ref is stored */
4142         addr_reg = alloc_dreg (cfg, STACK_MP);
4143
4144         /* Non-ref case */
4145         /* UNBOX */
4146         NEW_BIALU_IMM (cfg, addr, OP_ADD_IMM, addr_reg, obj->dreg, sizeof (MonoObject));
4147         MONO_ADD_INS (cfg->cbb, addr);
4148
4149         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4150
4151         /* Ref case */
4152         MONO_START_BB (cfg, is_ref_bb);
4153
4154         /* Save the ref to a temporary */
4155         dreg = alloc_ireg (cfg);
4156         EMIT_NEW_VARLOADA_VREG (cfg, addr, dreg, &klass->byval_arg);
4157         addr->dreg = addr_reg;
4158         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, obj->dreg);
4159         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4160
4161         /* Nullable case */
4162         MONO_START_BB (cfg, is_nullable_bb);
4163
4164         {
4165                 MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX);
4166                 MonoInst *unbox_call;
4167                 MonoMethodSignature *unbox_sig;
4168
4169                 unbox_sig = (MonoMethodSignature *)mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4170                 unbox_sig->ret = &klass->byval_arg;
4171                 unbox_sig->param_count = 1;
4172                 unbox_sig->params [0] = &mono_defaults.object_class->byval_arg;
4173
4174                 if (cfg->llvm_only)
4175                         unbox_call = emit_llvmonly_calli (cfg, unbox_sig, &obj, addr);
4176                 else
4177                         unbox_call = mono_emit_calli (cfg, unbox_sig, &obj, addr, NULL, NULL);
4178
4179                 EMIT_NEW_VARLOADA_VREG (cfg, addr, unbox_call->dreg, &klass->byval_arg);
4180                 addr->dreg = addr_reg;
4181         }
4182
4183         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4184
4185         /* End */
4186         MONO_START_BB (cfg, end_bb);
4187
4188         /* LDOBJ */
4189         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr_reg, 0);
4190
4191         return ins;
4192 }
4193
4194 /*
4195  * Returns NULL and set the cfg exception on error.
4196  */
4197 static MonoInst*
4198 handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_used)
4199 {
4200         MonoInst *iargs [2];
4201         void *alloc_ftn;
4202
4203         if (context_used) {
4204                 MonoInst *data;
4205                 MonoRgctxInfoType rgctx_info;
4206                 MonoInst *iargs [2];
4207                 gboolean known_instance_size = !mini_is_gsharedvt_klass (klass);
4208
4209                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (klass, for_box, known_instance_size);
4210
4211                 if (cfg->opt & MONO_OPT_SHARED)
4212                         rgctx_info = MONO_RGCTX_INFO_KLASS;
4213                 else
4214                         rgctx_info = MONO_RGCTX_INFO_VTABLE;
4215                 data = emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
4216
4217                 if (cfg->opt & MONO_OPT_SHARED) {
4218                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4219                         iargs [1] = data;
4220                         alloc_ftn = ves_icall_object_new;
4221                 } else {
4222                         iargs [0] = data;
4223                         alloc_ftn = ves_icall_object_new_specific;
4224                 }
4225
4226                 if (managed_alloc && !(cfg->opt & MONO_OPT_SHARED)) {
4227                         if (known_instance_size) {
4228                                 int size = mono_class_instance_size (klass);
4229                                 if (size < sizeof (MonoObject))
4230                                         g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4231
4232                                 EMIT_NEW_ICONST (cfg, iargs [1], mono_gc_get_aligned_size_for_allocator (size));
4233                         }
4234                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4235                 }
4236
4237                 return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4238         }
4239
4240         if (cfg->opt & MONO_OPT_SHARED) {
4241                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4242                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
4243
4244                 alloc_ftn = ves_icall_object_new;
4245         } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !klass->generic_class) {
4246                 /* This happens often in argument checking code, eg. throw new FooException... */
4247                 /* Avoid relocations and save some space by calling a helper function specialized to mscorlib */
4248                 EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
4249                 return mono_emit_jit_icall (cfg, mono_helper_newobj_mscorlib, iargs);
4250         } else {
4251                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
4252                 MonoMethod *managed_alloc = NULL;
4253                 gboolean pass_lw;
4254
4255                 if (!vtable) {
4256                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4257                         cfg->exception_ptr = klass;
4258                         return NULL;
4259                 }
4260
4261                 managed_alloc = mono_gc_get_managed_allocator (klass, for_box, TRUE);
4262
4263                 if (managed_alloc) {
4264                         int size = mono_class_instance_size (klass);
4265                         if (size < sizeof (MonoObject))
4266                                 g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4267
4268                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4269                         EMIT_NEW_ICONST (cfg, iargs [1], mono_gc_get_aligned_size_for_allocator (size));
4270                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4271                 }
4272                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
4273                 if (pass_lw) {
4274                         guint32 lw = vtable->klass->instance_size;
4275                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
4276                         EMIT_NEW_ICONST (cfg, iargs [0], lw);
4277                         EMIT_NEW_VTABLECONST (cfg, iargs [1], vtable);
4278                 }
4279                 else {
4280                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4281                 }
4282         }
4283
4284         return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4285 }
4286         
4287 /*
4288  * Returns NULL and set the cfg exception on error.
4289  */     
4290 static MonoInst*
4291 handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used)
4292 {
4293         MonoInst *alloc, *ins;
4294
4295         if (mono_class_is_nullable (klass)) {
4296                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
4297
4298                 if (context_used) {
4299                         if (cfg->llvm_only && cfg->gsharedvt) {
4300                                 MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4301                                                                                                                 MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4302                                 return emit_llvmonly_calli (cfg, mono_method_signature (method), &val, addr);
4303                         } else {
4304                                 /* FIXME: What if the class is shared?  We might not
4305                                    have to get the method address from the RGCTX. */
4306                                 MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4307                                                                                                                 MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4308                                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
4309
4310                                 return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
4311                         }
4312                 } else {
4313                         gboolean pass_vtable, pass_mrgctx;
4314                         MonoInst *rgctx_arg = NULL;
4315
4316                         check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
4317                         g_assert (!pass_mrgctx);
4318
4319                         if (pass_vtable) {
4320                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4321
4322                                 g_assert (vtable);
4323                                 EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
4324                         }
4325
4326                         return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4327                 }
4328         }
4329
4330         if (mini_is_gsharedvt_klass (klass)) {
4331                 MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4332                 MonoInst *res, *is_ref, *src_var, *addr;
4333                 int dreg;
4334
4335                 dreg = alloc_ireg (cfg);
4336
4337                 NEW_BBLOCK (cfg, is_ref_bb);
4338                 NEW_BBLOCK (cfg, is_nullable_bb);
4339                 NEW_BBLOCK (cfg, end_bb);
4340                 is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4341                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
4342                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4343
4344                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
4345                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4346
4347                 /* Non-ref case */
4348                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4349                 if (!alloc)
4350                         return NULL;
4351                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4352                 ins->opcode = OP_STOREV_MEMBASE;
4353
4354                 EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, alloc->dreg);
4355                 res->type = STACK_OBJ;
4356                 res->klass = klass;
4357                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4358                 
4359                 /* Ref case */
4360                 MONO_START_BB (cfg, is_ref_bb);
4361
4362                 /* val is a vtype, so has to load the value manually */
4363                 src_var = get_vreg_to_inst (cfg, val->dreg);
4364                 if (!src_var)
4365                         src_var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, val->dreg);
4366                 EMIT_NEW_VARLOADA (cfg, addr, src_var, src_var->inst_vtype);
4367                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, addr->dreg, 0);
4368                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4369
4370                 /* Nullable case */
4371                 MONO_START_BB (cfg, is_nullable_bb);
4372
4373                 {
4374                         MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass,
4375                                                                                                         MONO_RGCTX_INFO_NULLABLE_CLASS_BOX);
4376                         MonoInst *box_call;
4377                         MonoMethodSignature *box_sig;
4378
4379                         /*
4380                          * klass is Nullable<T>, need to call Nullable<T>.Box () using a gsharedvt signature, but we cannot
4381                          * construct that method at JIT time, so have to do things by hand.
4382                          */
4383                         box_sig = (MonoMethodSignature *)mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4384                         box_sig->ret = &mono_defaults.object_class->byval_arg;
4385                         box_sig->param_count = 1;
4386                         box_sig->params [0] = &klass->byval_arg;
4387
4388                         if (cfg->llvm_only)
4389                                 box_call = emit_llvmonly_calli (cfg, box_sig, &val, addr);
4390                         else
4391                                 box_call = mono_emit_calli (cfg, box_sig, &val, addr, NULL, NULL);
4392                         EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, box_call->dreg);
4393                         res->type = STACK_OBJ;
4394                         res->klass = klass;
4395                 }
4396
4397                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4398
4399                 MONO_START_BB (cfg, end_bb);
4400
4401                 return res;
4402         } else {
4403                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4404                 if (!alloc)
4405                         return NULL;
4406
4407                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4408                 return alloc;
4409         }
4410 }
4411
4412 static gboolean
4413 mini_class_has_reference_variant_generic_argument (MonoCompile *cfg, MonoClass *klass, int context_used)
4414 {
4415         int i;
4416         MonoGenericContainer *container;
4417         MonoGenericInst *ginst;
4418
4419         if (klass->generic_class) {
4420                 container = klass->generic_class->container_class->generic_container;
4421                 ginst = klass->generic_class->context.class_inst;
4422         } else if (klass->generic_container && context_used) {
4423                 container = klass->generic_container;
4424                 ginst = container->context.class_inst;
4425         } else {
4426                 return FALSE;
4427         }
4428
4429         for (i = 0; i < container->type_argc; ++i) {
4430                 MonoType *type;
4431                 if (!(mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT)))
4432                         continue;
4433                 type = ginst->type_argv [i];
4434                 if (mini_type_is_reference (type))
4435                         return TRUE;
4436         }
4437         return FALSE;
4438 }
4439
4440 static GHashTable* direct_icall_type_hash;
4441
4442 static gboolean
4443 icall_is_direct_callable (MonoCompile *cfg, MonoMethod *cmethod)
4444 {
4445         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
4446         if (!direct_icalls_enabled (cfg))
4447                 return FALSE;
4448
4449         /*
4450          * An icall is directly callable if it doesn't directly or indirectly call mono_raise_exception ().
4451          * Whitelist a few icalls for now.
4452          */
4453         if (!direct_icall_type_hash) {
4454                 GHashTable *h = g_hash_table_new (g_str_hash, g_str_equal);
4455
4456                 g_hash_table_insert (h, (char*)"Decimal", GUINT_TO_POINTER (1));
4457                 g_hash_table_insert (h, (char*)"Number", GUINT_TO_POINTER (1));
4458                 g_hash_table_insert (h, (char*)"Buffer", GUINT_TO_POINTER (1));
4459                 g_hash_table_insert (h, (char*)"Monitor", GUINT_TO_POINTER (1));
4460                 mono_memory_barrier ();
4461                 direct_icall_type_hash = h;
4462         }
4463
4464         if (cmethod->klass == mono_defaults.math_class)
4465                 return TRUE;
4466         /* No locking needed */
4467         if (cmethod->klass->image == mono_defaults.corlib && g_hash_table_lookup (direct_icall_type_hash, cmethod->klass->name))
4468                 return TRUE;
4469         return FALSE;
4470 }
4471
4472 #define is_complex_isinst(klass) ((klass->flags & TYPE_ATTRIBUTE_INTERFACE) || klass->rank || mono_class_is_nullable (klass) || mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_SEALED) || klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR)
4473
4474 static MonoInst*
4475 emit_castclass_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args)
4476 {
4477         MonoMethod *mono_castclass;
4478         MonoInst *res;
4479
4480         mono_castclass = mono_marshal_get_castclass_with_cache ();
4481
4482         save_cast_details (cfg, klass, args [0]->dreg, TRUE);
4483         res = mono_emit_method_call (cfg, mono_castclass, args, NULL);
4484         reset_cast_details (cfg);
4485
4486         return res;
4487 }
4488
4489 static int
4490 get_castclass_cache_idx (MonoCompile *cfg)
4491 {
4492         /* Each CASTCLASS_CACHE patch needs a unique index which identifies the call site */
4493         cfg->castclass_cache_index ++;
4494         return (cfg->method_index << 16) | cfg->castclass_cache_index;
4495 }
4496
4497 static MonoInst*
4498 emit_castclass_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass *klass)
4499 {
4500         MonoInst *args [3];
4501         int idx;
4502
4503         /* obj */
4504         args [0] = obj;
4505
4506         /* klass */
4507         EMIT_NEW_CLASSCONST (cfg, args [1], klass);
4508
4509         /* inline cache*/
4510         idx = get_castclass_cache_idx (cfg);
4511         args [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
4512
4513         /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
4514         return emit_castclass_with_cache (cfg, klass, args);
4515 }
4516
4517 /*
4518  * Returns NULL and set the cfg exception on error.
4519  */
4520 static MonoInst*
4521 handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, guint8 *ip, int *inline_costs)
4522 {
4523         MonoBasicBlock *is_null_bb;
4524         int obj_reg = src->dreg;
4525         int vtable_reg = alloc_preg (cfg);
4526         int context_used;
4527         MonoInst *klass_inst = NULL, *res;
4528
4529         context_used = mini_class_check_context_used (cfg, klass);
4530
4531         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
4532                 res = emit_castclass_with_cache_nonshared (cfg, src, klass);
4533                 (*inline_costs) += 2;
4534                 return res;
4535         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
4536                 MonoMethod *mono_castclass;
4537                 MonoInst *iargs [1];
4538                 int costs;
4539
4540                 mono_castclass = mono_marshal_get_castclass (klass); 
4541                 iargs [0] = src;
4542                                 
4543                 save_cast_details (cfg, klass, src->dreg, TRUE);
4544                 costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
4545                                                            iargs, ip, cfg->real_offset, TRUE);
4546                 reset_cast_details (cfg);
4547                 CHECK_CFG_EXCEPTION;
4548                 g_assert (costs > 0);
4549                                 
4550                 cfg->real_offset += 5;
4551
4552                 (*inline_costs) += costs;
4553
4554                 return src;
4555         }
4556
4557         if (context_used) {
4558                 MonoInst *args [3];
4559
4560                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4561                         MonoInst *cache_ins;
4562
4563                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4564
4565                         /* obj */
4566                         args [0] = src;
4567
4568                         /* klass - it's the second element of the cache entry*/
4569                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4570
4571                         /* cache */
4572                         args [2] = cache_ins;
4573
4574                         return emit_castclass_with_cache (cfg, klass, args);
4575                 }
4576
4577                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4578         }
4579
4580         NEW_BBLOCK (cfg, is_null_bb);
4581
4582         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4583         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
4584
4585         save_cast_details (cfg, klass, obj_reg, FALSE);
4586
4587         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4588                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4589                 mini_emit_iface_cast (cfg, vtable_reg, klass, NULL, NULL);
4590         } else {
4591                 int klass_reg = alloc_preg (cfg);
4592
4593                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4594
4595                 if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4596                         /* the remoting code is broken, access the class for now */
4597                         if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4598                                 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4599                                 if (!vt) {
4600                                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4601                                         cfg->exception_ptr = klass;
4602                                         return NULL;
4603                                 }
4604                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4605                         } else {
4606                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4607                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4608                         }
4609                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4610                 } else {
4611                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4612                         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, klass_inst, is_null_bb);
4613                 }
4614         }
4615
4616         MONO_START_BB (cfg, is_null_bb);
4617
4618         reset_cast_details (cfg);
4619
4620         return src;
4621
4622 exception_exit:
4623         return NULL;
4624 }
4625
4626 /*
4627  * Returns NULL and set the cfg exception on error.
4628  */
4629 static MonoInst*
4630 handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
4631 {
4632         MonoInst *ins;
4633         MonoBasicBlock *is_null_bb, *false_bb, *end_bb;
4634         int obj_reg = src->dreg;
4635         int vtable_reg = alloc_preg (cfg);
4636         int res_reg = alloc_ireg_ref (cfg);
4637         MonoInst *klass_inst = NULL;
4638
4639         if (context_used) {
4640                 MonoInst *args [3];
4641
4642                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4643                         MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
4644                         MonoInst *cache_ins;
4645
4646                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4647
4648                         /* obj */
4649                         args [0] = src;
4650
4651                         /* klass - it's the second element of the cache entry*/
4652                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4653
4654                         /* cache */
4655                         args [2] = cache_ins;
4656
4657                         return mono_emit_method_call (cfg, mono_isinst, args, NULL);
4658                 }
4659
4660                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4661         }
4662
4663         NEW_BBLOCK (cfg, is_null_bb);
4664         NEW_BBLOCK (cfg, false_bb);
4665         NEW_BBLOCK (cfg, end_bb);
4666
4667         /* Do the assignment at the beginning, so the other assignment can be if converted */
4668         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, res_reg, obj_reg);
4669         ins->type = STACK_OBJ;
4670         ins->klass = klass;
4671
4672         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4673         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_null_bb);
4674
4675         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4676
4677         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4678                 g_assert (!context_used);
4679                 /* the is_null_bb target simply copies the input register to the output */
4680                 mini_emit_iface_cast (cfg, vtable_reg, klass, false_bb, is_null_bb);
4681         } else {
4682                 int klass_reg = alloc_preg (cfg);
4683
4684                 if (klass->rank) {
4685                         int rank_reg = alloc_preg (cfg);
4686                         int eclass_reg = alloc_preg (cfg);
4687
4688                         g_assert (!context_used);
4689                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
4690                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
4691                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4692                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4693                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
4694                         if (klass->cast_class == mono_defaults.object_class) {
4695                                 int parent_reg = alloc_preg (cfg);
4696                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
4697                                 mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, is_null_bb);
4698                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4699                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4700                         } else if (klass->cast_class == mono_defaults.enum_class->parent) {
4701                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, is_null_bb);
4702                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);                          
4703                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4704                         } else if (klass->cast_class == mono_defaults.enum_class) {
4705                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4706                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4707                         } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
4708                                 mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4709                         } else {
4710                                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY)) {
4711                                         /* Check that the object is a vector too */
4712                                         int bounds_reg = alloc_preg (cfg);
4713                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
4714                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
4715                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4716                                 }
4717
4718                                 /* the is_null_bb target simply copies the input register to the output */
4719                                 mini_emit_isninst_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4720                         }
4721                 } else if (mono_class_is_nullable (klass)) {
4722                         g_assert (!context_used);
4723                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4724                         /* the is_null_bb target simply copies the input register to the output */
4725                         mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb);
4726                 } else {
4727                         if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4728                                 g_assert (!context_used);
4729                                 /* the remoting code is broken, access the class for now */
4730                                 if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4731                                         MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4732                                         if (!vt) {
4733                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4734                                                 cfg->exception_ptr = klass;
4735                                                 return NULL;
4736                                         }
4737                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4738                                 } else {
4739                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4740                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4741                                 }
4742                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4743                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
4744                         } else {
4745                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4746                                 /* the is_null_bb target simply copies the input register to the output */
4747                                 mini_emit_isninst_cast_inst (cfg, klass_reg, klass, klass_inst, false_bb, is_null_bb);
4748                         }
4749                 }
4750         }
4751
4752         MONO_START_BB (cfg, false_bb);
4753
4754         MONO_EMIT_NEW_PCONST (cfg, res_reg, 0);
4755         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4756
4757         MONO_START_BB (cfg, is_null_bb);
4758
4759         MONO_START_BB (cfg, end_bb);
4760
4761         return ins;
4762 }
4763
4764 static MonoInst*
4765 handle_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4766 {
4767         /* This opcode takes as input an object reference and a class, and returns:
4768         0) if the object is an instance of the class,
4769         1) if the object is not instance of the class,
4770         2) if the object is a proxy whose type cannot be determined */
4771
4772         MonoInst *ins;
4773 #ifndef DISABLE_REMOTING
4774         MonoBasicBlock *true_bb, *false_bb, *false2_bb, *end_bb, *no_proxy_bb, *interface_fail_bb;
4775 #else
4776         MonoBasicBlock *true_bb, *false_bb, *end_bb;
4777 #endif
4778         int obj_reg = src->dreg;
4779         int dreg = alloc_ireg (cfg);
4780         int tmp_reg;
4781 #ifndef DISABLE_REMOTING
4782         int klass_reg = alloc_preg (cfg);
4783 #endif
4784
4785         NEW_BBLOCK (cfg, true_bb);
4786         NEW_BBLOCK (cfg, false_bb);
4787         NEW_BBLOCK (cfg, end_bb);
4788 #ifndef DISABLE_REMOTING
4789         NEW_BBLOCK (cfg, false2_bb);
4790         NEW_BBLOCK (cfg, no_proxy_bb);
4791 #endif
4792
4793         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4794         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
4795
4796         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4797 #ifndef DISABLE_REMOTING
4798                 NEW_BBLOCK (cfg, interface_fail_bb);
4799 #endif
4800
4801                 tmp_reg = alloc_preg (cfg);
4802                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4803 #ifndef DISABLE_REMOTING
4804                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, true_bb);
4805                 MONO_START_BB (cfg, interface_fail_bb);
4806                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4807                 
4808                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, false_bb);
4809
4810                 tmp_reg = alloc_preg (cfg);
4811                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4812                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4813                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false2_bb);                
4814 #else
4815                 mini_emit_iface_cast (cfg, tmp_reg, klass, false_bb, true_bb);
4816 #endif
4817         } else {
4818 #ifndef DISABLE_REMOTING
4819                 tmp_reg = alloc_preg (cfg);
4820                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4821                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4822
4823                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4824                 tmp_reg = alloc_preg (cfg);
4825                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4826                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4827
4828                 tmp_reg = alloc_preg (cfg);             
4829                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4830                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4831                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4832                 
4833                 mini_emit_isninst_cast (cfg, klass_reg, klass, false2_bb, true_bb);
4834                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false2_bb);
4835
4836                 MONO_START_BB (cfg, no_proxy_bb);
4837
4838                 mini_emit_isninst_cast (cfg, klass_reg, klass, false_bb, true_bb);
4839 #else
4840                 g_error ("transparent proxy support is disabled while trying to JIT code that uses it");
4841 #endif
4842         }
4843
4844         MONO_START_BB (cfg, false_bb);
4845
4846         MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4847         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4848
4849 #ifndef DISABLE_REMOTING
4850         MONO_START_BB (cfg, false2_bb);
4851
4852         MONO_EMIT_NEW_ICONST (cfg, dreg, 2);
4853         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4854 #endif
4855
4856         MONO_START_BB (cfg, true_bb);
4857
4858         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4859
4860         MONO_START_BB (cfg, end_bb);
4861
4862         /* FIXME: */
4863         MONO_INST_NEW (cfg, ins, OP_ICONST);
4864         ins->dreg = dreg;
4865         ins->type = STACK_I4;
4866
4867         return ins;
4868 }
4869
4870 static MonoInst*
4871 handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4872 {
4873         /* This opcode takes as input an object reference and a class, and returns:
4874         0) if the object is an instance of the class,
4875         1) if the object is a proxy whose type cannot be determined
4876         an InvalidCastException exception is thrown otherwhise*/
4877         
4878         MonoInst *ins;
4879 #ifndef DISABLE_REMOTING
4880         MonoBasicBlock *end_bb, *ok_result_bb, *no_proxy_bb, *interface_fail_bb, *fail_1_bb;
4881 #else
4882         MonoBasicBlock *ok_result_bb;
4883 #endif
4884         int obj_reg = src->dreg;
4885         int dreg = alloc_ireg (cfg);
4886         int tmp_reg = alloc_preg (cfg);
4887
4888 #ifndef DISABLE_REMOTING
4889         int klass_reg = alloc_preg (cfg);
4890         NEW_BBLOCK (cfg, end_bb);
4891 #endif
4892
4893         NEW_BBLOCK (cfg, ok_result_bb);
4894
4895         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4896         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, ok_result_bb);
4897
4898         save_cast_details (cfg, klass, obj_reg, FALSE);
4899
4900         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4901 #ifndef DISABLE_REMOTING
4902                 NEW_BBLOCK (cfg, interface_fail_bb);
4903         
4904                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4905                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, ok_result_bb);
4906                 MONO_START_BB (cfg, interface_fail_bb);
4907                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4908
4909                 mini_emit_class_check (cfg, klass_reg, mono_defaults.transparent_proxy_class);
4910
4911                 tmp_reg = alloc_preg (cfg);             
4912                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4913                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4914                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
4915                 
4916                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4917                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4918 #else
4919                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4920                 mini_emit_iface_cast (cfg, tmp_reg, klass, NULL, NULL);
4921                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, ok_result_bb);
4922 #endif
4923         } else {
4924 #ifndef DISABLE_REMOTING
4925                 NEW_BBLOCK (cfg, no_proxy_bb);
4926
4927                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4928                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4929                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4930
4931                 tmp_reg = alloc_preg (cfg);
4932                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4933                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4934
4935                 tmp_reg = alloc_preg (cfg);
4936                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4937                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4938                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4939
4940                 NEW_BBLOCK (cfg, fail_1_bb);
4941                 
4942                 mini_emit_isninst_cast (cfg, klass_reg, klass, fail_1_bb, ok_result_bb);
4943
4944                 MONO_START_BB (cfg, fail_1_bb);
4945
4946                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4947                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4948
4949                 MONO_START_BB (cfg, no_proxy_bb);
4950
4951                 mini_emit_castclass (cfg, obj_reg, klass_reg, klass, ok_result_bb);
4952 #else
4953                 g_error ("Transparent proxy support is disabled while trying to JIT code that uses it");
4954 #endif
4955         }
4956
4957         MONO_START_BB (cfg, ok_result_bb);
4958
4959         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4960
4961 #ifndef DISABLE_REMOTING
4962         MONO_START_BB (cfg, end_bb);
4963 #endif
4964
4965         /* FIXME: */
4966         MONO_INST_NEW (cfg, ins, OP_ICONST);
4967         ins->dreg = dreg;
4968         ins->type = STACK_I4;
4969
4970         return ins;
4971 }
4972
4973 static G_GNUC_UNUSED MonoInst*
4974 handle_enum_has_flag (MonoCompile *cfg, MonoClass *klass, MonoInst *enum_this, MonoInst *enum_flag)
4975 {
4976         MonoType *enum_type = mono_type_get_underlying_type (&klass->byval_arg);
4977         guint32 load_opc = mono_type_to_load_membase (cfg, enum_type);
4978         gboolean is_i4;
4979
4980         switch (enum_type->type) {
4981         case MONO_TYPE_I8:
4982         case MONO_TYPE_U8:
4983 #if SIZEOF_REGISTER == 8
4984         case MONO_TYPE_I:
4985         case MONO_TYPE_U:
4986 #endif
4987                 is_i4 = FALSE;
4988                 break;
4989         default:
4990                 is_i4 = TRUE;
4991                 break;
4992         }
4993
4994         {
4995                 MonoInst *load, *and_, *cmp, *ceq;
4996                 int enum_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4997                 int and_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4998                 int dest_reg = alloc_ireg (cfg);
4999
5000                 EMIT_NEW_LOAD_MEMBASE (cfg, load, load_opc, enum_reg, enum_this->dreg, 0);
5001                 EMIT_NEW_BIALU (cfg, and_, is_i4 ? OP_IAND : OP_LAND, and_reg, enum_reg, enum_flag->dreg);
5002                 EMIT_NEW_BIALU (cfg, cmp, is_i4 ? OP_ICOMPARE : OP_LCOMPARE, -1, and_reg, enum_flag->dreg);
5003                 EMIT_NEW_UNALU (cfg, ceq, is_i4 ? OP_ICEQ : OP_LCEQ, dest_reg, -1);
5004
5005                 ceq->type = STACK_I4;
5006
5007                 if (!is_i4) {
5008                         load = mono_decompose_opcode (cfg, load);
5009                         and_ = mono_decompose_opcode (cfg, and_);
5010                         cmp = mono_decompose_opcode (cfg, cmp);
5011                         ceq = mono_decompose_opcode (cfg, ceq);
5012                 }
5013
5014                 return ceq;
5015         }
5016 }
5017
5018 /*
5019  * Returns NULL and set the cfg exception on error.
5020  */
5021 static G_GNUC_UNUSED MonoInst*
5022 handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method, int context_used, gboolean virtual_)
5023 {
5024         MonoInst *ptr;
5025         int dreg;
5026         gpointer trampoline;
5027         MonoInst *obj, *method_ins, *tramp_ins;
5028         MonoDomain *domain;
5029         guint8 **code_slot;
5030
5031         if (virtual_ && !cfg->llvm_only) {
5032                 MonoMethod *invoke = mono_get_delegate_invoke (klass);
5033                 g_assert (invoke);
5034
5035                 if (!mono_get_delegate_virtual_invoke_impl (mono_method_signature (invoke), context_used ? NULL : method))
5036                         return NULL;
5037         }
5038
5039         obj = handle_alloc (cfg, klass, FALSE, mono_class_check_context_used (klass));
5040         if (!obj)
5041                 return NULL;
5042
5043         /* Inline the contents of mono_delegate_ctor */
5044
5045         /* Set target field */
5046         /* Optimize away setting of NULL target */
5047         if (!(target->opcode == OP_PCONST && target->inst_p0 == 0)) {
5048                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
5049                 if (cfg->gen_write_barriers) {
5050                         dreg = alloc_preg (cfg);
5051                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target));
5052                         emit_write_barrier (cfg, ptr, target);
5053                 }
5054         }
5055
5056         /* Set method field */
5057         method_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
5058         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg);
5059
5060         /* 
5061          * To avoid looking up the compiled code belonging to the target method
5062          * in mono_delegate_trampoline (), we allocate a per-domain memory slot to
5063          * store it, and we fill it after the method has been compiled.
5064          */
5065         if (!method->dynamic && !(cfg->opt & MONO_OPT_SHARED)) {
5066                 MonoInst *code_slot_ins;
5067
5068                 if (context_used) {
5069                         code_slot_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD_DELEGATE_CODE);
5070                 } else {
5071                         domain = mono_domain_get ();
5072                         mono_domain_lock (domain);
5073                         if (!domain_jit_info (domain)->method_code_hash)
5074                                 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
5075                         code_slot = (guint8 **)g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, method);
5076                         if (!code_slot) {
5077                                 code_slot = (guint8 **)mono_domain_alloc0 (domain, sizeof (gpointer));
5078                                 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, method, code_slot);
5079                         }
5080                         mono_domain_unlock (domain);
5081
5082                         code_slot_ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHOD_CODE_SLOT, method);
5083                 }
5084                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);                
5085         }
5086
5087         if (cfg->llvm_only) {
5088                 MonoInst *args [16];
5089
5090                 if (virtual_) {
5091                         args [0] = obj;
5092                         args [1] = target;
5093                         args [2] = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
5094                         mono_emit_jit_icall (cfg, mono_llvmonly_init_delegate_virtual, args);
5095                 } else {
5096                         args [0] = obj;
5097                         mono_emit_jit_icall (cfg, mono_llvmonly_init_delegate, args);
5098                 }
5099
5100                 return obj;
5101         }
5102
5103         if (cfg->compile_aot) {
5104                 MonoDelegateClassMethodPair *del_tramp;
5105
5106                 del_tramp = (MonoDelegateClassMethodPair *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoDelegateClassMethodPair));
5107                 del_tramp->klass = klass;
5108                 del_tramp->method = context_used ? NULL : method;
5109                 del_tramp->is_virtual = virtual_;
5110                 EMIT_NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_DELEGATE_TRAMPOLINE, del_tramp);
5111         } else {
5112                 if (virtual_)
5113                         trampoline = mono_create_delegate_virtual_trampoline (cfg->domain, klass, context_used ? NULL : method);
5114                 else
5115                         trampoline = mono_create_delegate_trampoline_info (cfg->domain, klass, context_used ? NULL : method);
5116                 EMIT_NEW_PCONST (cfg, tramp_ins, trampoline);
5117         }
5118
5119         /* Set invoke_impl field */
5120         if (virtual_) {
5121                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), tramp_ins->dreg);
5122         } else {
5123                 dreg = alloc_preg (cfg);
5124                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, invoke_impl));
5125                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), dreg);
5126
5127                 dreg = alloc_preg (cfg);
5128                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, method_ptr));
5129                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr), dreg);
5130         }
5131
5132         dreg = alloc_preg (cfg);
5133         MONO_EMIT_NEW_ICONST (cfg, dreg, virtual_ ? 1 : 0);
5134         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_is_virtual), dreg);
5135
5136         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
5137
5138         return obj;
5139 }
5140
5141 static MonoInst*
5142 handle_array_new (MonoCompile *cfg, int rank, MonoInst **sp, unsigned char *ip)
5143 {
5144         MonoJitICallInfo *info;
5145
5146         /* Need to register the icall so it gets an icall wrapper */
5147         info = mono_get_array_new_va_icall (rank);
5148
5149         cfg->flags |= MONO_CFG_HAS_VARARGS;
5150
5151         /* mono_array_new_va () needs a vararg calling convention */
5152         cfg->exception_message = g_strdup ("array-new");
5153         cfg->disable_llvm = TRUE;
5154
5155         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
5156         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, sp);
5157 }
5158
5159 /*
5160  * handle_constrained_gsharedvt_call:
5161  *
5162  *   Handle constrained calls where the receiver is a gsharedvt type.
5163  * Return the instruction representing the call. Set the cfg exception on failure.
5164  */
5165 static MonoInst*
5166 handle_constrained_gsharedvt_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp, MonoClass *constrained_class,
5167                                                                    gboolean *ref_emit_widen)
5168 {
5169         MonoInst *ins = NULL;
5170         gboolean emit_widen = *ref_emit_widen;
5171
5172         /*
5173          * Constrained calls need to behave differently at runtime dependending on whenever the receiver is instantiated as ref type or as a vtype.
5174          * This is hard to do with the current call code, since we would have to emit a branch and two different calls. So instead, we
5175          * pack the arguments into an array, and do the rest of the work in in an icall.
5176          */
5177         if (((cmethod->klass == mono_defaults.object_class) || (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) &&
5178                 (MONO_TYPE_IS_VOID (fsig->ret) || MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_IS_REFERENCE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret) || mini_is_gsharedvt_type (fsig->ret)) &&
5179                 (fsig->param_count == 0 || (!fsig->hasthis && fsig->param_count == 1) || (fsig->param_count == 1 && (MONO_TYPE_IS_REFERENCE (fsig->params [0]) || fsig->params [0]->byref || mini_is_gsharedvt_type (fsig->params [0]))))) {
5180                 MonoInst *args [16];
5181
5182                 /*
5183                  * This case handles calls to
5184                  * - object:ToString()/Equals()/GetHashCode(),
5185                  * - System.IComparable<T>:CompareTo()
5186                  * - System.IEquatable<T>:Equals ()
5187                  * plus some simple interface calls enough to support AsyncTaskMethodBuilder.
5188                  */
5189
5190                 args [0] = sp [0];
5191                 if (mono_method_check_context_used (cmethod))
5192                         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cmethod), cmethod, MONO_RGCTX_INFO_METHOD);
5193                 else
5194                         EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
5195                 args [2] = emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_class), constrained_class, MONO_RGCTX_INFO_KLASS);
5196
5197                 /* !fsig->hasthis is for the wrapper for the Object.GetType () icall */
5198                 if (fsig->hasthis && fsig->param_count) {
5199                         /* Pass the arguments using a localloc-ed array using the format expected by runtime_invoke () */
5200                         MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
5201                         ins->dreg = alloc_preg (cfg);
5202                         ins->inst_imm = fsig->param_count * sizeof (mgreg_t);
5203                         MONO_ADD_INS (cfg->cbb, ins);
5204                         args [4] = ins;
5205
5206                         if (mini_is_gsharedvt_type (fsig->params [0])) {
5207                                 int addr_reg, deref_arg_reg;
5208
5209                                 ins = emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type (fsig->params [0]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
5210                                 deref_arg_reg = alloc_preg (cfg);
5211                                 /* deref_arg = BOX_TYPE != MONO_GSHAREDVT_BOX_TYPE_VTYPE */
5212                                 EMIT_NEW_BIALU_IMM (cfg, args [3], OP_ISUB_IMM, deref_arg_reg, ins->dreg, 1);
5213
5214                                 EMIT_NEW_VARLOADA_VREG (cfg, ins, sp [1]->dreg, fsig->params [0]);
5215                                 addr_reg = ins->dreg;
5216                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, addr_reg);
5217                         } else {
5218                                 EMIT_NEW_ICONST (cfg, args [3], 0);
5219                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, sp [1]->dreg);
5220                         }
5221                 } else {
5222                         EMIT_NEW_ICONST (cfg, args [3], 0);
5223                         EMIT_NEW_ICONST (cfg, args [4], 0);
5224                 }
5225                 ins = mono_emit_jit_icall (cfg, mono_gsharedvt_constrained_call, args);
5226                 emit_widen = FALSE;
5227
5228                 if (mini_is_gsharedvt_type (fsig->ret)) {
5229                         ins = handle_unbox_gsharedvt (cfg, mono_class_from_mono_type (fsig->ret), ins);
5230                 } else if (MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret)) {
5231                         MonoInst *add;
5232
5233                         /* Unbox */
5234                         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), ins->dreg, sizeof (MonoObject));
5235                         MONO_ADD_INS (cfg->cbb, add);
5236                         /* Load value */
5237                         NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, add->dreg, 0);
5238                         MONO_ADD_INS (cfg->cbb, ins);
5239                         /* ins represents the call result */
5240                 }
5241         } else {
5242                 GSHAREDVT_FAILURE (CEE_CALLVIRT);
5243         }
5244
5245         *ref_emit_widen = emit_widen;
5246
5247         return ins;
5248
5249  exception_exit:
5250         return NULL;
5251 }
5252
5253 static void
5254 mono_emit_load_got_addr (MonoCompile *cfg)
5255 {
5256         MonoInst *getaddr, *dummy_use;
5257
5258         if (!cfg->got_var || cfg->got_var_allocated)
5259                 return;
5260
5261         MONO_INST_NEW (cfg, getaddr, OP_LOAD_GOTADDR);
5262         getaddr->cil_code = cfg->header->code;
5263         getaddr->dreg = cfg->got_var->dreg;
5264
5265         /* Add it to the start of the first bblock */
5266         if (cfg->bb_entry->code) {
5267                 getaddr->next = cfg->bb_entry->code;
5268                 cfg->bb_entry->code = getaddr;
5269         }
5270         else
5271                 MONO_ADD_INS (cfg->bb_entry, getaddr);
5272
5273         cfg->got_var_allocated = TRUE;
5274
5275         /* 
5276          * Add a dummy use to keep the got_var alive, since real uses might
5277          * only be generated by the back ends.
5278          * Add it to end_bblock, so the variable's lifetime covers the whole
5279          * method.
5280          * It would be better to make the usage of the got var explicit in all
5281          * cases when the backend needs it (i.e. calls, throw etc.), so this
5282          * wouldn't be needed.
5283          */
5284         NEW_DUMMY_USE (cfg, dummy_use, cfg->got_var);
5285         MONO_ADD_INS (cfg->bb_exit, dummy_use);
5286 }
5287
5288 static int inline_limit;
5289 static gboolean inline_limit_inited;
5290
5291 static gboolean
5292 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
5293 {
5294         MonoMethodHeaderSummary header;
5295         MonoVTable *vtable;
5296 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5297         MonoMethodSignature *sig = mono_method_signature (method);
5298         int i;
5299 #endif
5300
5301         if (cfg->disable_inline)
5302                 return FALSE;
5303         if (cfg->gshared)
5304                 return FALSE;
5305
5306         if (cfg->inline_depth > 10)
5307                 return FALSE;
5308
5309         if (!mono_method_get_header_summary (method, &header))
5310                 return FALSE;
5311
5312         /*runtime, icall and pinvoke are checked by summary call*/
5313         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
5314             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
5315             (mono_class_is_marshalbyref (method->klass)) ||
5316             header.has_clauses)
5317                 return FALSE;
5318
5319         /* also consider num_locals? */
5320         /* Do the size check early to avoid creating vtables */
5321         if (!inline_limit_inited) {
5322                 if (g_getenv ("MONO_INLINELIMIT"))
5323                         inline_limit = atoi (g_getenv ("MONO_INLINELIMIT"));
5324                 else
5325                         inline_limit = INLINE_LENGTH_LIMIT;
5326                 inline_limit_inited = TRUE;
5327         }
5328         if (header.code_size >= inline_limit && !(method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
5329                 return FALSE;
5330
5331         /*
5332          * if we can initialize the class of the method right away, we do,
5333          * otherwise we don't allow inlining if the class needs initialization,
5334          * since it would mean inserting a call to mono_runtime_class_init()
5335          * inside the inlined code
5336          */
5337         if (!(cfg->opt & MONO_OPT_SHARED)) {
5338                 /* The AggressiveInlining hint is a good excuse to force that cctor to run. */
5339                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING) {
5340                         vtable = mono_class_vtable (cfg->domain, method->klass);
5341                         if (!vtable)
5342                                 return FALSE;
5343                         if (!cfg->compile_aot) {
5344                                 MonoError error;
5345                                 if (!mono_runtime_class_init_full (vtable, &error))
5346                                         mono_error_raise_exception (&error); /* FIXME don't raise here */
5347                         }
5348                 } else if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5349                         if (cfg->run_cctors && method->klass->has_cctor) {
5350                                 /*FIXME it would easier and lazier to just use mono_class_try_get_vtable */
5351                                 if (!method->klass->runtime_info)
5352                                         /* No vtable created yet */
5353                                         return FALSE;
5354                                 vtable = mono_class_vtable (cfg->domain, method->klass);
5355                                 if (!vtable)
5356                                         return FALSE;
5357                                 /* This makes so that inline cannot trigger */
5358                                 /* .cctors: too many apps depend on them */
5359                                 /* running with a specific order... */
5360                                 if (! vtable->initialized)
5361                                         return FALSE;
5362                                 MonoError error;
5363                                 if (!mono_runtime_class_init_full (vtable, &error))
5364                                         mono_error_raise_exception (&error); /* FIXME don't raise here */
5365                         }
5366                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
5367                         if (!method->klass->runtime_info)
5368                                 /* No vtable created yet */
5369                                 return FALSE;
5370                         vtable = mono_class_vtable (cfg->domain, method->klass);
5371                         if (!vtable)
5372                                 return FALSE;
5373                         if (!vtable->initialized)
5374                                 return FALSE;
5375                 }
5376         } else {
5377                 /* 
5378                  * If we're compiling for shared code
5379                  * the cctor will need to be run at aot method load time, for example,
5380                  * or at the end of the compilation of the inlining method.
5381                  */
5382                 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
5383                         return FALSE;
5384         }
5385
5386 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5387         if (mono_arch_is_soft_float ()) {
5388                 /* FIXME: */
5389                 if (sig->ret && sig->ret->type == MONO_TYPE_R4)
5390                         return FALSE;
5391                 for (i = 0; i < sig->param_count; ++i)
5392                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4)
5393                                 return FALSE;
5394         }
5395 #endif
5396
5397         if (g_list_find (cfg->dont_inline, method))
5398                 return FALSE;
5399
5400         return TRUE;
5401 }
5402
5403 static gboolean
5404 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoClass *klass, MonoVTable *vtable)
5405 {
5406         if (!cfg->compile_aot) {
5407                 g_assert (vtable);
5408                 if (vtable->initialized)
5409                         return FALSE;
5410         }
5411
5412         if (klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5413                 if (cfg->method == method)
5414                         return FALSE;
5415         }
5416
5417         if (!mono_class_needs_cctor_run (klass, method))
5418                 return FALSE;
5419
5420         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (klass == method->klass))
5421                 /* The initialization is already done before the method is called */
5422                 return FALSE;
5423
5424         return TRUE;
5425 }
5426
5427 static MonoInst*
5428 mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck)
5429 {
5430         MonoInst *ins;
5431         guint32 size;
5432         int mult_reg, add_reg, array_reg, index_reg, index2_reg;
5433         int context_used;
5434
5435         if (mini_is_gsharedvt_variable_klass (klass)) {
5436                 size = -1;
5437         } else {
5438                 mono_class_init (klass);
5439                 size = mono_class_array_element_size (klass);
5440         }
5441
5442         mult_reg = alloc_preg (cfg);
5443         array_reg = arr->dreg;
5444         index_reg = index->dreg;
5445
5446 #if SIZEOF_REGISTER == 8
5447         /* The array reg is 64 bits but the index reg is only 32 */
5448         if (COMPILE_LLVM (cfg)) {
5449                 /* Not needed */
5450                 index2_reg = index_reg;
5451         } else {
5452                 index2_reg = alloc_preg (cfg);
5453                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
5454         }
5455 #else
5456         if (index->type == STACK_I8) {
5457                 index2_reg = alloc_preg (cfg);
5458                 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I4, index2_reg, index_reg);
5459         } else {
5460                 index2_reg = index_reg;
5461         }
5462 #endif
5463
5464         if (bcheck)
5465                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
5466
5467 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5468         if (size == 1 || size == 2 || size == 4 || size == 8) {
5469                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
5470
5471                 EMIT_NEW_X86_LEA (cfg, ins, array_reg, index2_reg, fast_log2 [size], MONO_STRUCT_OFFSET (MonoArray, vector));
5472                 ins->klass = mono_class_get_element_class (klass);
5473                 ins->type = STACK_MP;
5474
5475                 return ins;
5476         }
5477 #endif          
5478
5479         add_reg = alloc_ireg_mp (cfg);
5480
5481         if (size == -1) {
5482                 MonoInst *rgctx_ins;
5483
5484                 /* gsharedvt */
5485                 g_assert (cfg->gshared);
5486                 context_used = mini_class_check_context_used (cfg, klass);
5487                 g_assert (context_used);
5488                 rgctx_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE);
5489                 MONO_EMIT_NEW_BIALU (cfg, OP_IMUL, mult_reg, index2_reg, rgctx_ins->dreg);
5490         } else {
5491                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
5492         }
5493         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg);
5494         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5495         ins->klass = mono_class_get_element_class (klass);
5496         ins->type = STACK_MP;
5497         MONO_ADD_INS (cfg->cbb, ins);
5498
5499         return ins;
5500 }
5501
5502 static MonoInst*
5503 mini_emit_ldelema_2_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index_ins1, MonoInst *index_ins2)
5504 {
5505         int bounds_reg = alloc_preg (cfg);
5506         int add_reg = alloc_ireg_mp (cfg);
5507         int mult_reg = alloc_preg (cfg);
5508         int mult2_reg = alloc_preg (cfg);
5509         int low1_reg = alloc_preg (cfg);
5510         int low2_reg = alloc_preg (cfg);
5511         int high1_reg = alloc_preg (cfg);
5512         int high2_reg = alloc_preg (cfg);
5513         int realidx1_reg = alloc_preg (cfg);
5514         int realidx2_reg = alloc_preg (cfg);
5515         int sum_reg = alloc_preg (cfg);
5516         int index1, index2, tmpreg;
5517         MonoInst *ins;
5518         guint32 size;
5519
5520         mono_class_init (klass);
5521         size = mono_class_array_element_size (klass);
5522
5523         index1 = index_ins1->dreg;
5524         index2 = index_ins2->dreg;
5525
5526 #if SIZEOF_REGISTER == 8
5527         /* The array reg is 64 bits but the index reg is only 32 */
5528         if (COMPILE_LLVM (cfg)) {
5529                 /* Not needed */
5530         } else {
5531                 tmpreg = alloc_preg (cfg);
5532                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index1);
5533                 index1 = tmpreg;
5534                 tmpreg = alloc_preg (cfg);
5535                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index2);
5536                 index2 = tmpreg;
5537         }
5538 #else
5539         // FIXME: Do we need to do something here for i8 indexes, like in ldelema_1_ins ?
5540         tmpreg = -1;
5541 #endif
5542
5543         /* range checking */
5544         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, 
5545                                        arr->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5546
5547         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low1_reg, 
5548                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5549         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx1_reg, index1, low1_reg);
5550         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high1_reg, 
5551                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5552         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high1_reg, realidx1_reg);
5553         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5554
5555         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low2_reg, 
5556                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5557         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx2_reg, index2, low2_reg);
5558         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high2_reg, 
5559                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5560         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high2_reg, realidx2_reg);
5561         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5562
5563         MONO_EMIT_NEW_BIALU (cfg, OP_PMUL, mult_reg, high2_reg, realidx1_reg);
5564         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, mult_reg, realidx2_reg);
5565         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PMUL_IMM, mult2_reg, sum_reg, size);
5566         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult2_reg, arr->dreg);
5567         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5568
5569         ins->type = STACK_MP;
5570         ins->klass = klass;
5571         MONO_ADD_INS (cfg->cbb, ins);
5572
5573         return ins;
5574 }
5575
5576 static MonoInst*
5577 mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
5578 {
5579         int rank;
5580         MonoInst *addr;
5581         MonoMethod *addr_method;
5582         int element_size;
5583         MonoClass *eclass = cmethod->klass->element_class;
5584
5585         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
5586
5587         if (rank == 1)
5588                 return mini_emit_ldelema_1_ins (cfg, eclass, sp [0], sp [1], TRUE);
5589
5590         /* emit_ldelema_2 depends on OP_LMUL */
5591         if (!cfg->backend->emulate_mul_div && rank == 2 && (cfg->opt & MONO_OPT_INTRINS) && !mini_is_gsharedvt_variable_klass (eclass)) {
5592                 return mini_emit_ldelema_2_ins (cfg, eclass, sp [0], sp [1], sp [2]);
5593         }
5594
5595         if (mini_is_gsharedvt_variable_klass (eclass))
5596                 element_size = 0;
5597         else
5598                 element_size = mono_class_array_element_size (eclass);
5599         addr_method = mono_marshal_get_array_address (rank, element_size);
5600         addr = mono_emit_method_call (cfg, addr_method, sp, NULL);
5601
5602         return addr;
5603 }
5604
5605 static MonoBreakPolicy
5606 always_insert_breakpoint (MonoMethod *method)
5607 {
5608         return MONO_BREAK_POLICY_ALWAYS;
5609 }
5610
5611 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
5612
5613 /**
5614  * mono_set_break_policy:
5615  * policy_callback: the new callback function
5616  *
5617  * Allow embedders to decide wherther to actually obey breakpoint instructions
5618  * (both break IL instructions and Debugger.Break () method calls), for example
5619  * to not allow an app to be aborted by a perfectly valid IL opcode when executing
5620  * untrusted or semi-trusted code.
5621  *
5622  * @policy_callback will be called every time a break point instruction needs to
5623  * be inserted with the method argument being the method that calls Debugger.Break()
5624  * or has the IL break instruction. The callback should return #MONO_BREAK_POLICY_NEVER
5625  * if it wants the breakpoint to not be effective in the given method.
5626  * #MONO_BREAK_POLICY_ALWAYS is the default.
5627  */
5628 void
5629 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
5630 {
5631         if (policy_callback)
5632                 break_policy_func = policy_callback;
5633         else
5634                 break_policy_func = always_insert_breakpoint;
5635 }
5636
5637 static gboolean
5638 should_insert_brekpoint (MonoMethod *method) {
5639         switch (break_policy_func (method)) {
5640         case MONO_BREAK_POLICY_ALWAYS:
5641                 return TRUE;
5642         case MONO_BREAK_POLICY_NEVER:
5643                 return FALSE;
5644         case MONO_BREAK_POLICY_ON_DBG:
5645                 g_warning ("mdb no longer supported");
5646                 return FALSE;
5647         default:
5648                 g_warning ("Incorrect value returned from break policy callback");
5649                 return FALSE;
5650         }
5651 }
5652
5653 /* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */
5654 static MonoInst*
5655 emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5656 {
5657         MonoInst *addr, *store, *load;
5658         MonoClass *eklass = mono_class_from_mono_type (fsig->params [2]);
5659
5660         /* the bounds check is already done by the callers */
5661         addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5662         if (is_set) {
5663                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
5664                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
5665                 if (mini_type_is_reference (fsig->params [2]))
5666                         emit_write_barrier (cfg, addr, load);
5667         } else {
5668                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
5669                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
5670         }
5671         return store;
5672 }
5673
5674
5675 static gboolean
5676 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
5677 {
5678         return mini_type_is_reference (&klass->byval_arg);
5679 }
5680
5681 static MonoInst*
5682 emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboolean safety_checks)
5683 {
5684         if (safety_checks && generic_class_is_reference_type (cfg, klass) &&
5685                 !(sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL)) {
5686                 MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
5687                 MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
5688                 MonoInst *iargs [3];
5689
5690                 if (!helper->slot)
5691                         mono_class_setup_vtable (obj_array);
5692                 g_assert (helper->slot);
5693
5694                 if (sp [0]->type != STACK_OBJ)
5695                         return NULL;
5696                 if (sp [2]->type != STACK_OBJ)
5697                         return NULL;
5698
5699                 iargs [2] = sp [2];
5700                 iargs [1] = sp [1];
5701                 iargs [0] = sp [0];
5702
5703                 return mono_emit_method_call (cfg, helper, iargs, sp [0]);
5704         } else {
5705                 MonoInst *ins;
5706
5707                 if (mini_is_gsharedvt_variable_klass (klass)) {
5708                         MonoInst *addr;
5709
5710                         // FIXME-VT: OP_ICONST optimization
5711                         addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
5712                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5713                         ins->opcode = OP_STOREV_MEMBASE;
5714                 } else if (sp [1]->opcode == OP_ICONST) {
5715                         int array_reg = sp [0]->dreg;
5716                         int index_reg = sp [1]->dreg;
5717                         int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
5718
5719                         if (SIZEOF_REGISTER == 8 && COMPILE_LLVM (cfg))
5720                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, index_reg);
5721
5722                         if (safety_checks)
5723                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
5724                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
5725                 } else {
5726                         MonoInst *addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], safety_checks);
5727                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5728                         if (generic_class_is_reference_type (cfg, klass))
5729                                 emit_write_barrier (cfg, addr, sp [2]);
5730                 }
5731                 return ins;
5732         }
5733 }
5734
5735 static MonoInst*
5736 emit_array_unsafe_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5737 {
5738         MonoClass *eklass;
5739         
5740         if (is_set)
5741                 eklass = mono_class_from_mono_type (fsig->params [2]);
5742         else
5743                 eklass = mono_class_from_mono_type (fsig->ret);
5744
5745         if (is_set) {
5746                 return emit_array_store (cfg, eklass, args, FALSE);
5747         } else {
5748                 MonoInst *ins, *addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5749                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &eklass->byval_arg, addr->dreg, 0);
5750                 return ins;
5751         }
5752 }
5753
5754 static gboolean
5755 is_unsafe_mov_compatible (MonoCompile *cfg, MonoClass *param_klass, MonoClass *return_klass)
5756 {
5757         uint32_t align;
5758         int param_size, return_size;
5759
5760         param_klass = mono_class_from_mono_type (mini_get_underlying_type (&param_klass->byval_arg));
5761         return_klass = mono_class_from_mono_type (mini_get_underlying_type (&return_klass->byval_arg));
5762
5763         if (cfg->verbose_level > 3)
5764                 printf ("[UNSAFE-MOV-INTRISIC] %s <- %s\n", return_klass->name, param_klass->name);
5765
5766         //Don't allow mixing reference types with value types
5767         if (param_klass->valuetype != return_klass->valuetype) {
5768                 if (cfg->verbose_level > 3)
5769                         printf ("[UNSAFE-MOV-INTRISIC]\tone of the args is a valuetype and the other is not\n");
5770                 return FALSE;
5771         }
5772
5773         if (!param_klass->valuetype) {
5774                 if (cfg->verbose_level > 3)
5775                         printf ("[UNSAFE-MOV-INTRISIC]\targs are reference types\n");
5776                 return TRUE;
5777         }
5778
5779         //That are blitable
5780         if (param_klass->has_references || return_klass->has_references)
5781                 return FALSE;
5782
5783         /* Avoid mixing structs and primitive types/enums, they need to be handled differently in the JIT */
5784         if ((MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && !MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)) ||
5785                 (!MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && MONO_TYPE_ISSTRUCT (&return_klass->byval_arg))) {
5786                         if (cfg->verbose_level > 3)
5787                                 printf ("[UNSAFE-MOV-INTRISIC]\tmixing structs and scalars\n");
5788                 return FALSE;
5789         }
5790
5791         if (param_klass->byval_arg.type == MONO_TYPE_R4 || param_klass->byval_arg.type == MONO_TYPE_R8 ||
5792                 return_klass->byval_arg.type == MONO_TYPE_R4 || return_klass->byval_arg.type == MONO_TYPE_R8) {
5793                 if (cfg->verbose_level > 3)
5794                         printf ("[UNSAFE-MOV-INTRISIC]\tfloat or double are not supported\n");
5795                 return FALSE;
5796         }
5797
5798         param_size = mono_class_value_size (param_klass, &align);
5799         return_size = mono_class_value_size (return_klass, &align);
5800
5801         //We can do it if sizes match
5802         if (param_size == return_size) {
5803                 if (cfg->verbose_level > 3)
5804                         printf ("[UNSAFE-MOV-INTRISIC]\tsame size\n");
5805                 return TRUE;
5806         }
5807
5808         //No simple way to handle struct if sizes don't match
5809         if (MONO_TYPE_ISSTRUCT (&param_klass->byval_arg)) {
5810                 if (cfg->verbose_level > 3)
5811                         printf ("[UNSAFE-MOV-INTRISIC]\tsize mismatch and type is a struct\n");
5812                 return FALSE;
5813         }
5814
5815         /*
5816          * Same reg size category.
5817          * A quick note on why we don't require widening here.
5818          * The intrinsic is "R Array.UnsafeMov<S,R> (S s)".
5819          *
5820          * Since the source value comes from a function argument, the JIT will already have
5821          * the value in a VREG and performed any widening needed before (say, when loading from a field).
5822          */
5823         if (param_size <= 4 && return_size <= 4) {
5824                 if (cfg->verbose_level > 3)
5825                         printf ("[UNSAFE-MOV-INTRISIC]\tsize mismatch but both are of the same reg class\n");
5826                 return TRUE;
5827         }
5828
5829         return FALSE;
5830 }
5831
5832 static MonoInst*
5833 emit_array_unsafe_mov (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args)
5834 {
5835         MonoClass *param_klass = mono_class_from_mono_type (fsig->params [0]);
5836         MonoClass *return_klass = mono_class_from_mono_type (fsig->ret);
5837
5838         if (mini_is_gsharedvt_variable_type (fsig->ret))
5839                 return NULL;
5840
5841         //Valuetypes that are semantically equivalent or numbers than can be widened to
5842         if (is_unsafe_mov_compatible (cfg, param_klass, return_klass))
5843                 return args [0];
5844
5845         //Arrays of valuetypes that are semantically equivalent
5846         if (param_klass->rank == 1 && return_klass->rank == 1 && is_unsafe_mov_compatible (cfg, param_klass->element_class, return_klass->element_class))
5847                 return args [0];
5848
5849         return NULL;
5850 }
5851
5852 static MonoInst*
5853 mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5854 {
5855 #ifdef MONO_ARCH_SIMD_INTRINSICS
5856         MonoInst *ins = NULL;
5857
5858         if (cfg->opt & MONO_OPT_SIMD) {
5859                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5860                 if (ins)
5861                         return ins;
5862         }
5863 #endif
5864
5865         return mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
5866 }
5867
5868 static MonoInst*
5869 emit_memory_barrier (MonoCompile *cfg, int kind)
5870 {
5871         MonoInst *ins = NULL;
5872         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
5873         MONO_ADD_INS (cfg->cbb, ins);
5874         ins->backend.memory_barrier_kind = kind;
5875
5876         return ins;
5877 }
5878
5879 static MonoInst*
5880 llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5881 {
5882         MonoInst *ins = NULL;
5883         int opcode = 0;
5884
5885         /* The LLVM backend supports these intrinsics */
5886         if (cmethod->klass == mono_defaults.math_class) {
5887                 if (strcmp (cmethod->name, "Sin") == 0) {
5888                         opcode = OP_SIN;
5889                 } else if (strcmp (cmethod->name, "Cos") == 0) {
5890                         opcode = OP_COS;
5891                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
5892                         opcode = OP_SQRT;
5893                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
5894                         opcode = OP_ABS;
5895                 }
5896
5897                 if (opcode && fsig->param_count == 1) {
5898                         MONO_INST_NEW (cfg, ins, opcode);
5899                         ins->type = STACK_R8;
5900                         ins->dreg = mono_alloc_freg (cfg);
5901                         ins->sreg1 = args [0]->dreg;
5902                         MONO_ADD_INS (cfg->cbb, ins);
5903                 }
5904
5905                 opcode = 0;
5906                 if (cfg->opt & MONO_OPT_CMOV) {
5907                         if (strcmp (cmethod->name, "Min") == 0) {
5908                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5909                                         opcode = OP_IMIN;
5910                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5911                                         opcode = OP_IMIN_UN;
5912                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5913                                         opcode = OP_LMIN;
5914                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5915                                         opcode = OP_LMIN_UN;
5916                         } else if (strcmp (cmethod->name, "Max") == 0) {
5917                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5918                                         opcode = OP_IMAX;
5919                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5920                                         opcode = OP_IMAX_UN;
5921                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5922                                         opcode = OP_LMAX;
5923                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5924                                         opcode = OP_LMAX_UN;
5925                         }
5926                 }
5927
5928                 if (opcode && fsig->param_count == 2) {
5929                         MONO_INST_NEW (cfg, ins, opcode);
5930                         ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
5931                         ins->dreg = mono_alloc_ireg (cfg);
5932                         ins->sreg1 = args [0]->dreg;
5933                         ins->sreg2 = args [1]->dreg;
5934                         MONO_ADD_INS (cfg->cbb, ins);
5935                 }
5936         }
5937
5938         return ins;
5939 }
5940
5941 static MonoInst*
5942 mini_emit_inst_for_sharable_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5943 {
5944         if (cmethod->klass == mono_defaults.array_class) {
5945                 if (strcmp (cmethod->name, "UnsafeStore") == 0)
5946                         return emit_array_unsafe_access (cfg, fsig, args, TRUE);
5947                 else if (strcmp (cmethod->name, "UnsafeLoad") == 0)
5948                         return emit_array_unsafe_access (cfg, fsig, args, FALSE);
5949                 else if (strcmp (cmethod->name, "UnsafeMov") == 0)
5950                         return emit_array_unsafe_mov (cfg, fsig, args);
5951         }
5952
5953         return NULL;
5954 }
5955
5956 static MonoInst*
5957 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5958 {
5959         MonoInst *ins = NULL;
5960
5961          MonoClass *runtime_helpers_class = mono_class_get_runtime_helpers_class ();
5962
5963         if (cmethod->klass == mono_defaults.string_class) {
5964                 if (strcmp (cmethod->name, "get_Chars") == 0 && fsig->param_count + fsig->hasthis == 2) {
5965                         int dreg = alloc_ireg (cfg);
5966                         int index_reg = alloc_preg (cfg);
5967                         int add_reg = alloc_preg (cfg);
5968
5969 #if SIZEOF_REGISTER == 8
5970                         if (COMPILE_LLVM (cfg)) {
5971                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, args [1]->dreg);
5972                         } else {
5973                                 /* The array reg is 64 bits but the index reg is only 32 */
5974                                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index_reg, args [1]->dreg);
5975                         }
5976 #else
5977                         index_reg = args [1]->dreg;
5978 #endif  
5979                         MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
5980
5981 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5982                         EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, MONO_STRUCT_OFFSET (MonoString, chars));
5983                         add_reg = ins->dreg;
5984                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5985                                                                    add_reg, 0);
5986 #else
5987                         int mult_reg = alloc_preg (cfg);
5988                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1);
5989                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5990                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5991                                                                    add_reg, MONO_STRUCT_OFFSET (MonoString, chars));
5992 #endif
5993                         type_from_op (cfg, ins, NULL, NULL);
5994                         return ins;
5995                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
5996                         int dreg = alloc_ireg (cfg);
5997                         /* Decompose later to allow more optimizations */
5998                         EMIT_NEW_UNALU (cfg, ins, OP_STRLEN, dreg, args [0]->dreg);
5999                         ins->type = STACK_I4;
6000                         ins->flags |= MONO_INST_FAULT;
6001                         cfg->cbb->has_array_access = TRUE;
6002                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
6003
6004                         return ins;
6005                 } else 
6006                         return NULL;
6007         } else if (cmethod->klass == mono_defaults.object_class) {
6008                 if (strcmp (cmethod->name, "GetType") == 0 && fsig->param_count + fsig->hasthis == 1) {
6009                         int dreg = alloc_ireg_ref (cfg);
6010                         int vt_reg = alloc_preg (cfg);
6011                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
6012                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, MONO_STRUCT_OFFSET (MonoVTable, type));
6013                         type_from_op (cfg, ins, NULL, NULL);
6014
6015                         return ins;
6016                 } else if (!cfg->backend->emulate_mul_div && strcmp (cmethod->name, "InternalGetHashCode") == 0 && fsig->param_count == 1 && !mono_gc_is_moving ()) {
6017                         int dreg = alloc_ireg (cfg);
6018                         int t1 = alloc_ireg (cfg);
6019         
6020                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, t1, args [0]->dreg, 3);
6021                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_MUL_IMM, dreg, t1, 2654435761u);
6022                         ins->type = STACK_I4;
6023
6024                         return ins;
6025                 } else if (strcmp (cmethod->name, ".ctor") == 0 && fsig->param_count == 0) {
6026                         MONO_INST_NEW (cfg, ins, OP_NOP);
6027                         MONO_ADD_INS (cfg->cbb, ins);
6028                         return ins;
6029                 } else
6030                         return NULL;
6031         } else if (cmethod->klass == mono_defaults.array_class) {
6032                 if (strcmp (cmethod->name, "GetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
6033                         return emit_array_generic_access (cfg, fsig, args, FALSE);
6034                 else if (strcmp (cmethod->name, "SetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
6035                         return emit_array_generic_access (cfg, fsig, args, TRUE);
6036
6037 #ifndef MONO_BIG_ARRAYS
6038                 /*
6039                  * This is an inline version of GetLength/GetLowerBound(0) used frequently in
6040                  * Array methods.
6041                  */
6042                 else if (((strcmp (cmethod->name, "GetLength") == 0 && fsig->param_count + fsig->hasthis == 2) ||
6043                          (strcmp (cmethod->name, "GetLowerBound") == 0 && fsig->param_count + fsig->hasthis == 2)) &&
6044                          args [1]->opcode == OP_ICONST && args [1]->inst_c0 == 0) {
6045                         int dreg = alloc_ireg (cfg);
6046                         int bounds_reg = alloc_ireg_mp (cfg);
6047                         MonoBasicBlock *end_bb, *szarray_bb;
6048                         gboolean get_length = strcmp (cmethod->name, "GetLength") == 0;
6049
6050                         NEW_BBLOCK (cfg, end_bb);
6051                         NEW_BBLOCK (cfg, szarray_bb);
6052
6053                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOAD_MEMBASE, bounds_reg,
6054                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
6055                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
6056                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, szarray_bb);
6057                         /* Non-szarray case */
6058                         if (get_length)
6059                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
6060                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
6061                         else
6062                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
6063                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
6064                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
6065                         MONO_START_BB (cfg, szarray_bb);
6066                         /* Szarray case */
6067                         if (get_length)
6068                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
6069                                                                            args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
6070                         else
6071                                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
6072                         MONO_START_BB (cfg, end_bb);
6073
6074                         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, dreg, dreg);
6075                         ins->type = STACK_I4;
6076                         
6077                         return ins;
6078                 }
6079 #endif
6080
6081                 if (cmethod->name [0] != 'g')
6082                         return NULL;
6083
6084                 if (strcmp (cmethod->name, "get_Rank") == 0 && fsig->param_count + fsig->hasthis == 1) {
6085                         int dreg = alloc_ireg (cfg);
6086                         int vtable_reg = alloc_preg (cfg);
6087                         MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, 
6088                                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
6089                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
6090                                                                    vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
6091                         type_from_op (cfg, ins, NULL, NULL);
6092
6093                         return ins;
6094                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
6095                         int dreg = alloc_ireg (cfg);
6096
6097                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
6098                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
6099                         type_from_op (cfg, ins, NULL, NULL);
6100
6101                         return ins;
6102                 } else
6103                         return NULL;
6104         } else if (cmethod->klass == runtime_helpers_class) {
6105                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0 && fsig->param_count == 0) {
6106                         EMIT_NEW_ICONST (cfg, ins, MONO_STRUCT_OFFSET (MonoString, chars));
6107                         return ins;
6108                 } else
6109                         return NULL;
6110         } else if (cmethod->klass == mono_defaults.monitor_class) {
6111                 gboolean is_enter = FALSE;
6112                 gboolean is_v4 = FALSE;
6113
6114                 if (!strcmp (cmethod->name, "enter_with_atomic_var") && mono_method_signature (cmethod)->param_count == 2) {
6115                         is_enter = TRUE;
6116                         is_v4 = TRUE;
6117                 }
6118                 if (!strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1)
6119                         is_enter = TRUE;
6120
6121                 if (is_enter) {
6122                         /*
6123                          * To make async stack traces work, icalls which can block should have a wrapper.
6124                          * For Monitor.Enter, emit two calls: a fastpath which doesn't have a wrapper, and a slowpath, which does.
6125                          */
6126                         MonoBasicBlock *end_bb;
6127
6128                         NEW_BBLOCK (cfg, end_bb);
6129
6130                         ins = mono_emit_jit_icall (cfg, is_v4 ? (gpointer)mono_monitor_enter_v4_fast : (gpointer)mono_monitor_enter_fast, args);
6131                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, ins->dreg, 0);
6132                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, end_bb);
6133                         ins = mono_emit_jit_icall (cfg, is_v4 ? (gpointer)mono_monitor_enter_v4 : (gpointer)mono_monitor_enter, args);
6134                         MONO_START_BB (cfg, end_bb);
6135                         return ins;
6136                 }
6137         } else if (cmethod->klass == mono_defaults.thread_class) {
6138                 if (strcmp (cmethod->name, "SpinWait_nop") == 0 && fsig->param_count == 0) {
6139                         MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
6140                         MONO_ADD_INS (cfg->cbb, ins);
6141                         return ins;
6142                 } else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0) {
6143                         return emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6144                 } else if (!strcmp (cmethod->name, "VolatileRead") && fsig->param_count == 1) {
6145                         guint32 opcode = 0;
6146                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6147
6148                         if (fsig->params [0]->type == MONO_TYPE_I1)
6149                                 opcode = OP_LOADI1_MEMBASE;
6150                         else if (fsig->params [0]->type == MONO_TYPE_U1)
6151                                 opcode = OP_LOADU1_MEMBASE;
6152                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6153                                 opcode = OP_LOADI2_MEMBASE;
6154                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6155                                 opcode = OP_LOADU2_MEMBASE;
6156                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6157                                 opcode = OP_LOADI4_MEMBASE;
6158                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6159                                 opcode = OP_LOADU4_MEMBASE;
6160                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
6161                                 opcode = OP_LOADI8_MEMBASE;
6162                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6163                                 opcode = OP_LOADR4_MEMBASE;
6164                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6165                                 opcode = OP_LOADR8_MEMBASE;
6166                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
6167                                 opcode = OP_LOAD_MEMBASE;
6168
6169                         if (opcode) {
6170                                 MONO_INST_NEW (cfg, ins, opcode);
6171                                 ins->inst_basereg = args [0]->dreg;
6172                                 ins->inst_offset = 0;
6173                                 MONO_ADD_INS (cfg->cbb, ins);
6174
6175                                 switch (fsig->params [0]->type) {
6176                                 case MONO_TYPE_I1:
6177                                 case MONO_TYPE_U1:
6178                                 case MONO_TYPE_I2:
6179                                 case MONO_TYPE_U2:
6180                                 case MONO_TYPE_I4:
6181                                 case MONO_TYPE_U4:
6182                                         ins->dreg = mono_alloc_ireg (cfg);
6183                                         ins->type = STACK_I4;
6184                                         break;
6185                                 case MONO_TYPE_I8:
6186                                 case MONO_TYPE_U8:
6187                                         ins->dreg = mono_alloc_lreg (cfg);
6188                                         ins->type = STACK_I8;
6189                                         break;
6190                                 case MONO_TYPE_I:
6191                                 case MONO_TYPE_U:
6192                                         ins->dreg = mono_alloc_ireg (cfg);
6193 #if SIZEOF_REGISTER == 8
6194                                         ins->type = STACK_I8;
6195 #else
6196                                         ins->type = STACK_I4;
6197 #endif
6198                                         break;
6199                                 case MONO_TYPE_R4:
6200                                 case MONO_TYPE_R8:
6201                                         ins->dreg = mono_alloc_freg (cfg);
6202                                         ins->type = STACK_R8;
6203                                         break;
6204                                 default:
6205                                         g_assert (mini_type_is_reference (fsig->params [0]));
6206                                         ins->dreg = mono_alloc_ireg_ref (cfg);
6207                                         ins->type = STACK_OBJ;
6208                                         break;
6209                                 }
6210
6211                                 if (opcode == OP_LOADI8_MEMBASE)
6212                                         ins = mono_decompose_opcode (cfg, ins);
6213
6214                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6215
6216                                 return ins;
6217                         }
6218                 } else if (!strcmp (cmethod->name, "VolatileWrite") && fsig->param_count == 2) {
6219                         guint32 opcode = 0;
6220                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6221
6222                         if (fsig->params [0]->type == MONO_TYPE_I1 || fsig->params [0]->type == MONO_TYPE_U1)
6223                                 opcode = OP_STOREI1_MEMBASE_REG;
6224                         else if (fsig->params [0]->type == MONO_TYPE_I2 || fsig->params [0]->type == MONO_TYPE_U2)
6225                                 opcode = OP_STOREI2_MEMBASE_REG;
6226                         else if (fsig->params [0]->type == MONO_TYPE_I4 || fsig->params [0]->type == MONO_TYPE_U4)
6227                                 opcode = OP_STOREI4_MEMBASE_REG;
6228                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
6229                                 opcode = OP_STOREI8_MEMBASE_REG;
6230                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6231                                 opcode = OP_STORER4_MEMBASE_REG;
6232                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6233                                 opcode = OP_STORER8_MEMBASE_REG;
6234                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
6235                                 opcode = OP_STORE_MEMBASE_REG;
6236
6237                         if (opcode) {
6238                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6239
6240                                 MONO_INST_NEW (cfg, ins, opcode);
6241                                 ins->sreg1 = args [1]->dreg;
6242                                 ins->inst_destbasereg = args [0]->dreg;
6243                                 ins->inst_offset = 0;
6244                                 MONO_ADD_INS (cfg->cbb, ins);
6245
6246                                 if (opcode == OP_STOREI8_MEMBASE_REG)
6247                                         ins = mono_decompose_opcode (cfg, ins);
6248
6249                                 return ins;
6250                         }
6251                 }
6252         } else if (cmethod->klass->image == mono_defaults.corlib &&
6253                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6254                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
6255                 ins = NULL;
6256
6257 #if SIZEOF_REGISTER == 8
6258                 if (!cfg->llvm_only && strcmp (cmethod->name, "Read") == 0 && fsig->param_count == 1 && (fsig->params [0]->type == MONO_TYPE_I8)) {
6259                         if (!cfg->llvm_only && mono_arch_opcode_supported (OP_ATOMIC_LOAD_I8)) {
6260                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_LOAD_I8);
6261                                 ins->dreg = mono_alloc_preg (cfg);
6262                                 ins->sreg1 = args [0]->dreg;
6263                                 ins->type = STACK_I8;
6264                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_SEQ;
6265                                 MONO_ADD_INS (cfg->cbb, ins);
6266                         } else {
6267                                 MonoInst *load_ins;
6268
6269                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6270
6271                                 /* 64 bit reads are already atomic */
6272                                 MONO_INST_NEW (cfg, load_ins, OP_LOADI8_MEMBASE);
6273                                 load_ins->dreg = mono_alloc_preg (cfg);
6274                                 load_ins->inst_basereg = args [0]->dreg;
6275                                 load_ins->inst_offset = 0;
6276                                 load_ins->type = STACK_I8;
6277                                 MONO_ADD_INS (cfg->cbb, load_ins);
6278
6279                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6280
6281                                 ins = load_ins;
6282                         }
6283                 }
6284 #endif
6285
6286                 if (strcmp (cmethod->name, "Increment") == 0 && fsig->param_count == 1) {
6287                         MonoInst *ins_iconst;
6288                         guint32 opcode = 0;
6289
6290                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6291                                 opcode = OP_ATOMIC_ADD_I4;
6292                                 cfg->has_atomic_add_i4 = TRUE;
6293                         }
6294 #if SIZEOF_REGISTER == 8
6295                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6296                                 opcode = OP_ATOMIC_ADD_I8;
6297 #endif
6298                         if (opcode) {
6299                                 if (!mono_arch_opcode_supported (opcode))
6300                                         return NULL;
6301                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6302                                 ins_iconst->inst_c0 = 1;
6303                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6304                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6305
6306                                 MONO_INST_NEW (cfg, ins, opcode);
6307                                 ins->dreg = mono_alloc_ireg (cfg);
6308                                 ins->inst_basereg = args [0]->dreg;
6309                                 ins->inst_offset = 0;
6310                                 ins->sreg2 = ins_iconst->dreg;
6311                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6312                                 MONO_ADD_INS (cfg->cbb, ins);
6313                         }
6314                 } else if (strcmp (cmethod->name, "Decrement") == 0 && fsig->param_count == 1) {
6315                         MonoInst *ins_iconst;
6316                         guint32 opcode = 0;
6317
6318                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6319                                 opcode = OP_ATOMIC_ADD_I4;
6320                                 cfg->has_atomic_add_i4 = TRUE;
6321                         }
6322 #if SIZEOF_REGISTER == 8
6323                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6324                                 opcode = OP_ATOMIC_ADD_I8;
6325 #endif
6326                         if (opcode) {
6327                                 if (!mono_arch_opcode_supported (opcode))
6328                                         return NULL;
6329                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6330                                 ins_iconst->inst_c0 = -1;
6331                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6332                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6333
6334                                 MONO_INST_NEW (cfg, ins, opcode);
6335                                 ins->dreg = mono_alloc_ireg (cfg);
6336                                 ins->inst_basereg = args [0]->dreg;
6337                                 ins->inst_offset = 0;
6338                                 ins->sreg2 = ins_iconst->dreg;
6339                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6340                                 MONO_ADD_INS (cfg->cbb, ins);
6341                         }
6342                 } else if (strcmp (cmethod->name, "Add") == 0 && fsig->param_count == 2) {
6343                         guint32 opcode = 0;
6344
6345                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6346                                 opcode = OP_ATOMIC_ADD_I4;
6347                                 cfg->has_atomic_add_i4 = TRUE;
6348                         }
6349 #if SIZEOF_REGISTER == 8
6350                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6351                                 opcode = OP_ATOMIC_ADD_I8;
6352 #endif
6353                         if (opcode) {
6354                                 if (!mono_arch_opcode_supported (opcode))
6355                                         return NULL;
6356                                 MONO_INST_NEW (cfg, ins, opcode);
6357                                 ins->dreg = mono_alloc_ireg (cfg);
6358                                 ins->inst_basereg = args [0]->dreg;
6359                                 ins->inst_offset = 0;
6360                                 ins->sreg2 = args [1]->dreg;
6361                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6362                                 MONO_ADD_INS (cfg->cbb, ins);
6363                         }
6364                 }
6365                 else if (strcmp (cmethod->name, "Exchange") == 0 && fsig->param_count == 2) {
6366                         MonoInst *f2i = NULL, *i2f;
6367                         guint32 opcode, f2i_opcode, i2f_opcode;
6368                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6369                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
6370
6371                         if (fsig->params [0]->type == MONO_TYPE_I4 ||
6372                             fsig->params [0]->type == MONO_TYPE_R4) {
6373                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6374                                 f2i_opcode = OP_MOVE_F_TO_I4;
6375                                 i2f_opcode = OP_MOVE_I4_TO_F;
6376                                 cfg->has_atomic_exchange_i4 = TRUE;
6377                         }
6378 #if SIZEOF_REGISTER == 8
6379                         else if (is_ref ||
6380                                  fsig->params [0]->type == MONO_TYPE_I8 ||
6381                                  fsig->params [0]->type == MONO_TYPE_R8 ||
6382                                  fsig->params [0]->type == MONO_TYPE_I) {
6383                                 opcode = OP_ATOMIC_EXCHANGE_I8;
6384                                 f2i_opcode = OP_MOVE_F_TO_I8;
6385                                 i2f_opcode = OP_MOVE_I8_TO_F;
6386                         }
6387 #else
6388                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I) {
6389                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6390                                 cfg->has_atomic_exchange_i4 = TRUE;
6391                         }
6392 #endif
6393                         else
6394                                 return NULL;
6395
6396                         if (!mono_arch_opcode_supported (opcode))
6397                                 return NULL;
6398
6399                         if (is_float) {
6400                                 /* TODO: Decompose these opcodes instead of bailing here. */
6401                                 if (COMPILE_SOFT_FLOAT (cfg))
6402                                         return NULL;
6403
6404                                 MONO_INST_NEW (cfg, f2i, f2i_opcode);
6405                                 f2i->dreg = mono_alloc_ireg (cfg);
6406                                 f2i->sreg1 = args [1]->dreg;
6407                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6408                                         f2i->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6409                                 MONO_ADD_INS (cfg->cbb, f2i);
6410                         }
6411
6412                         MONO_INST_NEW (cfg, ins, opcode);
6413                         ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : mono_alloc_ireg (cfg);
6414                         ins->inst_basereg = args [0]->dreg;
6415                         ins->inst_offset = 0;
6416                         ins->sreg2 = is_float ? f2i->dreg : args [1]->dreg;
6417                         MONO_ADD_INS (cfg->cbb, ins);
6418
6419                         switch (fsig->params [0]->type) {
6420                         case MONO_TYPE_I4:
6421                                 ins->type = STACK_I4;
6422                                 break;
6423                         case MONO_TYPE_I8:
6424                                 ins->type = STACK_I8;
6425                                 break;
6426                         case MONO_TYPE_I:
6427 #if SIZEOF_REGISTER == 8
6428                                 ins->type = STACK_I8;
6429 #else
6430                                 ins->type = STACK_I4;
6431 #endif
6432                                 break;
6433                         case MONO_TYPE_R4:
6434                         case MONO_TYPE_R8:
6435                                 ins->type = STACK_R8;
6436                                 break;
6437                         default:
6438                                 g_assert (mini_type_is_reference (fsig->params [0]));
6439                                 ins->type = STACK_OBJ;
6440                                 break;
6441                         }
6442
6443                         if (is_float) {
6444                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6445                                 i2f->dreg = mono_alloc_freg (cfg);
6446                                 i2f->sreg1 = ins->dreg;
6447                                 i2f->type = STACK_R8;
6448                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6449                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6450                                 MONO_ADD_INS (cfg->cbb, i2f);
6451
6452                                 ins = i2f;
6453                         }
6454
6455                         if (cfg->gen_write_barriers && is_ref)
6456                                 emit_write_barrier (cfg, args [0], args [1]);
6457                 }
6458                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 3) {
6459                         MonoInst *f2i_new = NULL, *f2i_cmp = NULL, *i2f;
6460                         guint32 opcode, f2i_opcode, i2f_opcode;
6461                         gboolean is_ref = mini_type_is_reference (fsig->params [1]);
6462                         gboolean is_float = fsig->params [1]->type == MONO_TYPE_R4 || fsig->params [1]->type == MONO_TYPE_R8;
6463
6464                         if (fsig->params [1]->type == MONO_TYPE_I4 ||
6465                             fsig->params [1]->type == MONO_TYPE_R4) {
6466                                 opcode = OP_ATOMIC_CAS_I4;
6467                                 f2i_opcode = OP_MOVE_F_TO_I4;
6468                                 i2f_opcode = OP_MOVE_I4_TO_F;
6469                                 cfg->has_atomic_cas_i4 = TRUE;
6470                         }
6471 #if SIZEOF_REGISTER == 8
6472                         else if (is_ref ||
6473                                  fsig->params [1]->type == MONO_TYPE_I8 ||
6474                                  fsig->params [1]->type == MONO_TYPE_R8 ||
6475                                  fsig->params [1]->type == MONO_TYPE_I) {
6476                                 opcode = OP_ATOMIC_CAS_I8;
6477                                 f2i_opcode = OP_MOVE_F_TO_I8;
6478                                 i2f_opcode = OP_MOVE_I8_TO_F;
6479                         }
6480 #else
6481                         else if (is_ref || fsig->params [1]->type == MONO_TYPE_I) {
6482                                 opcode = OP_ATOMIC_CAS_I4;
6483                                 cfg->has_atomic_cas_i4 = TRUE;
6484                         }
6485 #endif
6486                         else
6487                                 return NULL;
6488
6489                         if (!mono_arch_opcode_supported (opcode))
6490                                 return NULL;
6491
6492                         if (is_float) {
6493                                 /* TODO: Decompose these opcodes instead of bailing here. */
6494                                 if (COMPILE_SOFT_FLOAT (cfg))
6495                                         return NULL;
6496
6497                                 MONO_INST_NEW (cfg, f2i_new, f2i_opcode);
6498                                 f2i_new->dreg = mono_alloc_ireg (cfg);
6499                                 f2i_new->sreg1 = args [1]->dreg;
6500                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6501                                         f2i_new->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6502                                 MONO_ADD_INS (cfg->cbb, f2i_new);
6503
6504                                 MONO_INST_NEW (cfg, f2i_cmp, f2i_opcode);
6505                                 f2i_cmp->dreg = mono_alloc_ireg (cfg);
6506                                 f2i_cmp->sreg1 = args [2]->dreg;
6507                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6508                                         f2i_cmp->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6509                                 MONO_ADD_INS (cfg->cbb, f2i_cmp);
6510                         }
6511
6512                         MONO_INST_NEW (cfg, ins, opcode);
6513                         ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
6514                         ins->sreg1 = args [0]->dreg;
6515                         ins->sreg2 = is_float ? f2i_new->dreg : args [1]->dreg;
6516                         ins->sreg3 = is_float ? f2i_cmp->dreg : args [2]->dreg;
6517                         MONO_ADD_INS (cfg->cbb, ins);
6518
6519                         switch (fsig->params [1]->type) {
6520                         case MONO_TYPE_I4:
6521                                 ins->type = STACK_I4;
6522                                 break;
6523                         case MONO_TYPE_I8:
6524                                 ins->type = STACK_I8;
6525                                 break;
6526                         case MONO_TYPE_I:
6527 #if SIZEOF_REGISTER == 8
6528                                 ins->type = STACK_I8;
6529 #else
6530                                 ins->type = STACK_I4;
6531 #endif
6532                                 break;
6533                         case MONO_TYPE_R4:
6534                                 ins->type = cfg->r4_stack_type;
6535                                 break;
6536                         case MONO_TYPE_R8:
6537                                 ins->type = STACK_R8;
6538                                 break;
6539                         default:
6540                                 g_assert (mini_type_is_reference (fsig->params [1]));
6541                                 ins->type = STACK_OBJ;
6542                                 break;
6543                         }
6544
6545                         if (is_float) {
6546                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6547                                 i2f->dreg = mono_alloc_freg (cfg);
6548                                 i2f->sreg1 = ins->dreg;
6549                                 i2f->type = STACK_R8;
6550                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6551                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6552                                 MONO_ADD_INS (cfg->cbb, i2f);
6553
6554                                 ins = i2f;
6555                         }
6556
6557                         if (cfg->gen_write_barriers && is_ref)
6558                                 emit_write_barrier (cfg, args [0], args [1]);
6559                 }
6560                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 4 &&
6561                          fsig->params [1]->type == MONO_TYPE_I4) {
6562                         MonoInst *cmp, *ceq;
6563
6564                         if (!mono_arch_opcode_supported (OP_ATOMIC_CAS_I4))
6565                                 return NULL;
6566
6567                         /* int32 r = CAS (location, value, comparand); */
6568                         MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
6569                         ins->dreg = alloc_ireg (cfg);
6570                         ins->sreg1 = args [0]->dreg;
6571                         ins->sreg2 = args [1]->dreg;
6572                         ins->sreg3 = args [2]->dreg;
6573                         ins->type = STACK_I4;
6574                         MONO_ADD_INS (cfg->cbb, ins);
6575
6576                         /* bool result = r == comparand; */
6577                         MONO_INST_NEW (cfg, cmp, OP_ICOMPARE);
6578                         cmp->sreg1 = ins->dreg;
6579                         cmp->sreg2 = args [2]->dreg;
6580                         cmp->type = STACK_I4;
6581                         MONO_ADD_INS (cfg->cbb, cmp);
6582
6583                         MONO_INST_NEW (cfg, ceq, OP_ICEQ);
6584                         ceq->dreg = alloc_ireg (cfg);
6585                         ceq->type = STACK_I4;
6586                         MONO_ADD_INS (cfg->cbb, ceq);
6587
6588                         /* *success = result; */
6589                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, args [3]->dreg, 0, ceq->dreg);
6590
6591                         cfg->has_atomic_cas_i4 = TRUE;
6592                 }
6593                 else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0)
6594                         ins = emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6595
6596                 if (ins)
6597                         return ins;
6598         } else if (cmethod->klass->image == mono_defaults.corlib &&
6599                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6600                            (strcmp (cmethod->klass->name, "Volatile") == 0)) {
6601                 ins = NULL;
6602
6603                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Read") && fsig->param_count == 1) {
6604                         guint32 opcode = 0;
6605                         MonoType *t = fsig->params [0];
6606                         gboolean is_ref;
6607                         gboolean is_float = t->type == MONO_TYPE_R4 || t->type == MONO_TYPE_R8;
6608
6609                         g_assert (t->byref);
6610                         /* t is a byref type, so the reference check is more complicated */
6611                         is_ref = mini_type_is_reference (&mono_class_from_mono_type (t)->byval_arg);
6612                         if (t->type == MONO_TYPE_I1)
6613                                 opcode = OP_ATOMIC_LOAD_I1;
6614                         else if (t->type == MONO_TYPE_U1 || t->type == MONO_TYPE_BOOLEAN)
6615                                 opcode = OP_ATOMIC_LOAD_U1;
6616                         else if (t->type == MONO_TYPE_I2)
6617                                 opcode = OP_ATOMIC_LOAD_I2;
6618                         else if (t->type == MONO_TYPE_U2)
6619                                 opcode = OP_ATOMIC_LOAD_U2;
6620                         else if (t->type == MONO_TYPE_I4)
6621                                 opcode = OP_ATOMIC_LOAD_I4;
6622                         else if (t->type == MONO_TYPE_U4)
6623                                 opcode = OP_ATOMIC_LOAD_U4;
6624                         else if (t->type == MONO_TYPE_R4)
6625                                 opcode = OP_ATOMIC_LOAD_R4;
6626                         else if (t->type == MONO_TYPE_R8)
6627                                 opcode = OP_ATOMIC_LOAD_R8;
6628 #if SIZEOF_REGISTER == 8
6629                         else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_I)
6630                                 opcode = OP_ATOMIC_LOAD_I8;
6631                         else if (is_ref || t->type == MONO_TYPE_U8 || t->type == MONO_TYPE_U)
6632                                 opcode = OP_ATOMIC_LOAD_U8;
6633 #else
6634                         else if (t->type == MONO_TYPE_I)
6635                                 opcode = OP_ATOMIC_LOAD_I4;
6636                         else if (is_ref || t->type == MONO_TYPE_U)
6637                                 opcode = OP_ATOMIC_LOAD_U4;
6638 #endif
6639
6640                         if (opcode) {
6641                                 if (!mono_arch_opcode_supported (opcode))
6642                                         return NULL;
6643
6644                                 MONO_INST_NEW (cfg, ins, opcode);
6645                                 ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : (is_float ? mono_alloc_freg (cfg) : mono_alloc_ireg (cfg));
6646                                 ins->sreg1 = args [0]->dreg;
6647                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_ACQ;
6648                                 MONO_ADD_INS (cfg->cbb, ins);
6649
6650                                 switch (t->type) {
6651                                 case MONO_TYPE_BOOLEAN:
6652                                 case MONO_TYPE_I1:
6653                                 case MONO_TYPE_U1:
6654                                 case MONO_TYPE_I2:
6655                                 case MONO_TYPE_U2:
6656                                 case MONO_TYPE_I4:
6657                                 case MONO_TYPE_U4:
6658                                         ins->type = STACK_I4;
6659                                         break;
6660                                 case MONO_TYPE_I8:
6661                                 case MONO_TYPE_U8:
6662                                         ins->type = STACK_I8;
6663                                         break;
6664                                 case MONO_TYPE_I:
6665                                 case MONO_TYPE_U:
6666 #if SIZEOF_REGISTER == 8
6667                                         ins->type = STACK_I8;
6668 #else
6669                                         ins->type = STACK_I4;
6670 #endif
6671                                         break;
6672                                 case MONO_TYPE_R4:
6673                                         ins->type = cfg->r4_stack_type;
6674                                         break;
6675                                 case MONO_TYPE_R8:
6676                                         ins->type = STACK_R8;
6677                                         break;
6678                                 default:
6679                                         g_assert (is_ref);
6680                                         ins->type = STACK_OBJ;
6681                                         break;
6682                                 }
6683                         }
6684                 }
6685
6686                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Write") && fsig->param_count == 2) {
6687                         guint32 opcode = 0;
6688                         MonoType *t = fsig->params [0];
6689                         gboolean is_ref;
6690
6691                         g_assert (t->byref);
6692                         is_ref = mini_type_is_reference (&mono_class_from_mono_type (t)->byval_arg);
6693                         if (t->type == MONO_TYPE_I1)
6694                                 opcode = OP_ATOMIC_STORE_I1;
6695                         else if (t->type == MONO_TYPE_U1 || t->type == MONO_TYPE_BOOLEAN)
6696                                 opcode = OP_ATOMIC_STORE_U1;
6697                         else if (t->type == MONO_TYPE_I2)
6698                                 opcode = OP_ATOMIC_STORE_I2;
6699                         else if (t->type == MONO_TYPE_U2)
6700                                 opcode = OP_ATOMIC_STORE_U2;
6701                         else if (t->type == MONO_TYPE_I4)
6702                                 opcode = OP_ATOMIC_STORE_I4;
6703                         else if (t->type == MONO_TYPE_U4)
6704                                 opcode = OP_ATOMIC_STORE_U4;
6705                         else if (t->type == MONO_TYPE_R4)
6706                                 opcode = OP_ATOMIC_STORE_R4;
6707                         else if (t->type == MONO_TYPE_R8)
6708                                 opcode = OP_ATOMIC_STORE_R8;
6709 #if SIZEOF_REGISTER == 8
6710                         else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_I)
6711                                 opcode = OP_ATOMIC_STORE_I8;
6712                         else if (is_ref || t->type == MONO_TYPE_U8 || t->type == MONO_TYPE_U)
6713                                 opcode = OP_ATOMIC_STORE_U8;
6714 #else
6715                         else if (t->type == MONO_TYPE_I)
6716                                 opcode = OP_ATOMIC_STORE_I4;
6717                         else if (is_ref || t->type == MONO_TYPE_U)
6718                                 opcode = OP_ATOMIC_STORE_U4;
6719 #endif
6720
6721                         if (opcode) {
6722                                 if (!mono_arch_opcode_supported (opcode))
6723                                         return NULL;
6724
6725                                 MONO_INST_NEW (cfg, ins, opcode);
6726                                 ins->dreg = args [0]->dreg;
6727                                 ins->sreg1 = args [1]->dreg;
6728                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_REL;
6729                                 MONO_ADD_INS (cfg->cbb, ins);
6730
6731                                 if (cfg->gen_write_barriers && is_ref)
6732                                         emit_write_barrier (cfg, args [0], args [1]);
6733                         }
6734                 }
6735
6736                 if (ins)
6737                         return ins;
6738         } else if (cmethod->klass->image == mono_defaults.corlib &&
6739                            (strcmp (cmethod->klass->name_space, "System.Diagnostics") == 0) &&
6740                            (strcmp (cmethod->klass->name, "Debugger") == 0)) {
6741                 if (!strcmp (cmethod->name, "Break") && fsig->param_count == 0) {
6742                         if (should_insert_brekpoint (cfg->method)) {
6743                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
6744                         } else {
6745                                 MONO_INST_NEW (cfg, ins, OP_NOP);
6746                                 MONO_ADD_INS (cfg->cbb, ins);
6747                         }
6748                         return ins;
6749                 }
6750         } else if (cmethod->klass->image == mono_defaults.corlib &&
6751                    (strcmp (cmethod->klass->name_space, "System") == 0) &&
6752                    (strcmp (cmethod->klass->name, "Environment") == 0)) {
6753                 if (!strcmp (cmethod->name, "get_IsRunningOnWindows") && fsig->param_count == 0) {
6754 #ifdef TARGET_WIN32
6755                         EMIT_NEW_ICONST (cfg, ins, 1);
6756 #else
6757                         EMIT_NEW_ICONST (cfg, ins, 0);
6758 #endif
6759                 }
6760         } else if (cmethod->klass->image == mono_defaults.corlib &&
6761                            (strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
6762                            (strcmp (cmethod->klass->name, "Assembly") == 0)) {
6763                 if (cfg->llvm_only && !strcmp (cmethod->name, "GetExecutingAssembly")) {
6764                         /* No stack walks are currently available, so implement this as an intrinsic */
6765                         MonoInst *assembly_ins;
6766
6767                         EMIT_NEW_AOTCONST (cfg, assembly_ins, MONO_PATCH_INFO_IMAGE, cfg->method->klass->image);
6768                         ins = mono_emit_jit_icall (cfg, mono_get_assembly_object, &assembly_ins);
6769                         return ins;
6770                 }
6771         } else if (cmethod->klass->image == mono_defaults.corlib &&
6772                            (strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
6773                            (strcmp (cmethod->klass->name, "MethodBase") == 0)) {
6774                 if (cfg->llvm_only && !strcmp (cmethod->name, "GetCurrentMethod")) {
6775                         /* No stack walks are currently available, so implement this as an intrinsic */
6776                         MonoInst *method_ins;
6777                         MonoMethod *declaring = cfg->method;
6778
6779                         /* This returns the declaring generic method */
6780                         if (declaring->is_inflated)
6781                                 declaring = ((MonoMethodInflated*)cfg->method)->declaring;
6782                         EMIT_NEW_AOTCONST (cfg, method_ins, MONO_PATCH_INFO_METHODCONST, declaring);
6783                         ins = mono_emit_jit_icall (cfg, mono_get_method_object, &method_ins);
6784                         cfg->no_inline = TRUE;
6785                         if (cfg->method != cfg->current_method)
6786                                 inline_failure (cfg, "MethodBase:GetCurrentMethod ()");
6787                         return ins;
6788                 }
6789         } else if (cmethod->klass == mono_defaults.math_class) {
6790                 /* 
6791                  * There is general branchless code for Min/Max, but it does not work for 
6792                  * all inputs:
6793                  * http://everything2.com/?node_id=1051618
6794                  */
6795         } else if (((!strcmp (cmethod->klass->image->assembly->aname.name, "MonoMac") ||
6796                     !strcmp (cmethod->klass->image->assembly->aname.name, "monotouch")) &&
6797                                 !strcmp (cmethod->klass->name_space, "XamCore.ObjCRuntime") &&
6798                                 !strcmp (cmethod->klass->name, "Selector")) ||
6799                            (!strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.iOS") &&
6800                                 !strcmp (cmethod->klass->name_space, "ObjCRuntime") &&
6801                                 !strcmp (cmethod->klass->name, "Selector"))
6802                            ) {
6803                 if (cfg->backend->have_objc_get_selector &&
6804                         !strcmp (cmethod->name, "GetHandle") && fsig->param_count == 1 &&
6805                     (args [0]->opcode == OP_GOT_ENTRY || args [0]->opcode == OP_AOTCONST) &&
6806                     cfg->compile_aot && !cfg->llvm_only) {
6807                         MonoInst *pi;
6808                         MonoJumpInfoToken *ji;
6809                         MonoString *s;
6810
6811                         // FIXME: llvmonly
6812
6813                         cfg->exception_message = g_strdup ("GetHandle");
6814                         cfg->disable_llvm = TRUE;
6815
6816                         if (args [0]->opcode == OP_GOT_ENTRY) {
6817                                 pi = (MonoInst *)args [0]->inst_p1;
6818                                 g_assert (pi->opcode == OP_PATCH_INFO);
6819                                 g_assert (GPOINTER_TO_INT (pi->inst_p1) == MONO_PATCH_INFO_LDSTR);
6820                                 ji = (MonoJumpInfoToken *)pi->inst_p0;
6821                         } else {
6822                                 g_assert (GPOINTER_TO_INT (args [0]->inst_p1) == MONO_PATCH_INFO_LDSTR);
6823                                 ji = (MonoJumpInfoToken *)args [0]->inst_p0;
6824                         }
6825
6826                         NULLIFY_INS (args [0]);
6827
6828                         // FIXME: Ugly
6829                         s = mono_ldstr (cfg->domain, ji->image, mono_metadata_token_index (ji->token));
6830                         MONO_INST_NEW (cfg, ins, OP_OBJC_GET_SELECTOR);
6831                         ins->dreg = mono_alloc_ireg (cfg);
6832                         // FIXME: Leaks
6833                         ins->inst_p0 = mono_string_to_utf8 (s);
6834                         MONO_ADD_INS (cfg->cbb, ins);
6835                         return ins;
6836                 }
6837         }
6838
6839 #ifdef MONO_ARCH_SIMD_INTRINSICS
6840         if (cfg->opt & MONO_OPT_SIMD) {
6841                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
6842                 if (ins)
6843                         return ins;
6844         }
6845 #endif
6846
6847         ins = mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
6848         if (ins)
6849                 return ins;
6850
6851         if (COMPILE_LLVM (cfg)) {
6852                 ins = llvm_emit_inst_for_method (cfg, cmethod, fsig, args);
6853                 if (ins)
6854                         return ins;
6855         }
6856
6857         return mono_arch_emit_inst_for_method (cfg, cmethod, fsig, args);
6858 }
6859
6860 /*
6861  * This entry point could be used later for arbitrary method
6862  * redirection.
6863  */
6864 inline static MonoInst*
6865 mini_redirect_call (MonoCompile *cfg, MonoMethod *method,  
6866                                         MonoMethodSignature *signature, MonoInst **args, MonoInst *this_ins)
6867 {
6868         if (method->klass == mono_defaults.string_class) {
6869                 /* managed string allocation support */
6870                 if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && !(cfg->opt & MONO_OPT_SHARED)) {
6871                         MonoInst *iargs [2];
6872                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
6873                         MonoMethod *managed_alloc = NULL;
6874
6875                         g_assert (vtable); /*Should not fail since it System.String*/
6876 #ifndef MONO_CROSS_COMPILE
6877                         managed_alloc = mono_gc_get_managed_allocator (method->klass, FALSE, FALSE);
6878 #endif
6879                         if (!managed_alloc)
6880                                 return NULL;
6881                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
6882                         iargs [1] = args [0];
6883                         return mono_emit_method_call (cfg, managed_alloc, iargs, this_ins);
6884                 }
6885         }
6886         return NULL;
6887 }
6888
6889 static void
6890 mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp)
6891 {
6892         MonoInst *store, *temp;
6893         int i;
6894
6895         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
6896                 MonoType *argtype = (sig->hasthis && (i == 0)) ? type_from_stack_type (*sp) : sig->params [i - sig->hasthis];
6897
6898                 /*
6899                  * FIXME: We should use *args++ = sp [0], but that would mean the arg
6900                  * would be different than the MonoInst's used to represent arguments, and
6901                  * the ldelema implementation can't deal with that.
6902                  * Solution: When ldelema is used on an inline argument, create a var for 
6903                  * it, emit ldelema on that var, and emit the saving code below in
6904                  * inline_method () if needed.
6905                  */
6906                 temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
6907                 cfg->args [i] = temp;
6908                 /* This uses cfg->args [i] which is set by the preceeding line */
6909                 EMIT_NEW_ARGSTORE (cfg, store, i, *sp);
6910                 store->cil_code = sp [0]->cil_code;
6911                 sp++;
6912         }
6913 }
6914
6915 #define MONO_INLINE_CALLED_LIMITED_METHODS 1
6916 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
6917
6918 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6919 static gboolean
6920 check_inline_called_method_name_limit (MonoMethod *called_method)
6921 {
6922         int strncmp_result;
6923         static const char *limit = NULL;
6924         
6925         if (limit == NULL) {
6926                 const char *limit_string = g_getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
6927
6928                 if (limit_string != NULL)
6929                         limit = limit_string;
6930                 else
6931                         limit = "";
6932         }
6933
6934         if (limit [0] != '\0') {
6935                 char *called_method_name = mono_method_full_name (called_method, TRUE);
6936
6937                 strncmp_result = strncmp (called_method_name, limit, strlen (limit));
6938                 g_free (called_method_name);
6939         
6940                 //return (strncmp_result <= 0);
6941                 return (strncmp_result == 0);
6942         } else {
6943                 return TRUE;
6944         }
6945 }
6946 #endif
6947
6948 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6949 static gboolean
6950 check_inline_caller_method_name_limit (MonoMethod *caller_method)
6951 {
6952         int strncmp_result;
6953         static const char *limit = NULL;
6954         
6955         if (limit == NULL) {
6956                 const char *limit_string = g_getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
6957                 if (limit_string != NULL) {
6958                         limit = limit_string;
6959                 } else {
6960                         limit = "";
6961                 }
6962         }
6963
6964         if (limit [0] != '\0') {
6965                 char *caller_method_name = mono_method_full_name (caller_method, TRUE);
6966
6967                 strncmp_result = strncmp (caller_method_name, limit, strlen (limit));
6968                 g_free (caller_method_name);
6969         
6970                 //return (strncmp_result <= 0);
6971                 return (strncmp_result == 0);
6972         } else {
6973                 return TRUE;
6974         }
6975 }
6976 #endif
6977
6978 static void
6979 emit_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6980 {
6981         static double r8_0 = 0.0;
6982         static float r4_0 = 0.0;
6983         MonoInst *ins;
6984         int t;
6985
6986         rtype = mini_get_underlying_type (rtype);
6987         t = rtype->type;
6988
6989         if (rtype->byref) {
6990                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6991         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6992                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
6993         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6994                 MONO_EMIT_NEW_I8CONST (cfg, dreg, 0);
6995         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6996                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
6997                 ins->type = STACK_R4;
6998                 ins->inst_p0 = (void*)&r4_0;
6999                 ins->dreg = dreg;
7000                 MONO_ADD_INS (cfg->cbb, ins);
7001         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
7002                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
7003                 ins->type = STACK_R8;
7004                 ins->inst_p0 = (void*)&r8_0;
7005                 ins->dreg = dreg;
7006                 MONO_ADD_INS (cfg->cbb, ins);
7007         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
7008                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
7009                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
7010         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
7011                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
7012         } else {
7013                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
7014         }
7015 }
7016
7017 static void
7018 emit_dummy_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
7019 {
7020         int t;
7021
7022         rtype = mini_get_underlying_type (rtype);
7023         t = rtype->type;
7024
7025         if (rtype->byref) {
7026                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_PCONST);
7027         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
7028                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_ICONST);
7029         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
7030                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_I8CONST);
7031         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
7032                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R4CONST);
7033         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
7034                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R8CONST);
7035         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
7036                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
7037                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
7038         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
7039                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
7040         } else {
7041                 emit_init_rvar (cfg, dreg, rtype);
7042         }
7043 }
7044
7045 /* If INIT is FALSE, emit dummy initialization statements to keep the IR valid */
7046 static void
7047 emit_init_local (MonoCompile *cfg, int local, MonoType *type, gboolean init)
7048 {
7049         MonoInst *var = cfg->locals [local];
7050         if (COMPILE_SOFT_FLOAT (cfg)) {
7051                 MonoInst *store;
7052                 int reg = alloc_dreg (cfg, (MonoStackType)var->type);
7053                 emit_init_rvar (cfg, reg, type);
7054                 EMIT_NEW_LOCSTORE (cfg, store, local, cfg->cbb->last_ins);
7055         } else {
7056                 if (init)
7057                         emit_init_rvar (cfg, var->dreg, type);
7058                 else
7059                         emit_dummy_init_rvar (cfg, var->dreg, type);
7060         }
7061 }
7062
7063 /*
7064  * inline_method:
7065  *
7066  *   Return the cost of inlining CMETHOD.
7067  */
7068 static int
7069 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
7070                            guchar *ip, guint real_offset, gboolean inline_always)
7071 {
7072         MonoError error;
7073         MonoInst *ins, *rvar = NULL;
7074         MonoMethodHeader *cheader;
7075         MonoBasicBlock *ebblock, *sbblock;
7076         int i, costs;
7077         MonoMethod *prev_inlined_method;
7078         MonoInst **prev_locals, **prev_args;
7079         MonoType **prev_arg_types;
7080         guint prev_real_offset;
7081         GHashTable *prev_cbb_hash;
7082         MonoBasicBlock **prev_cil_offset_to_bb;
7083         MonoBasicBlock *prev_cbb;
7084         unsigned char* prev_cil_start;
7085         guint32 prev_cil_offset_to_bb_len;
7086         MonoMethod *prev_current_method;
7087         MonoGenericContext *prev_generic_context;
7088         gboolean ret_var_set, prev_ret_var_set, prev_disable_inline, virtual_ = FALSE;
7089
7090         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
7091
7092 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
7093         if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod))
7094                 return 0;
7095 #endif
7096 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
7097         if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method))
7098                 return 0;
7099 #endif
7100
7101         if (!fsig)
7102                 fsig = mono_method_signature (cmethod);
7103
7104         if (cfg->verbose_level > 2)
7105                 printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
7106
7107         if (!cmethod->inline_info) {
7108                 cfg->stat_inlineable_methods++;
7109                 cmethod->inline_info = 1;
7110         }
7111
7112         /* allocate local variables */
7113         cheader = mono_method_get_header_checked (cmethod, &error);
7114         if (!cheader) {
7115                 if (inline_always) {
7116                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
7117                         mono_error_move (&cfg->error, &error);
7118                 } else {
7119                         mono_error_cleanup (&error);
7120                 }
7121                 return 0;
7122         }
7123
7124         /*Must verify before creating locals as it can cause the JIT to assert.*/
7125         if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
7126                 mono_metadata_free_mh (cheader);
7127                 return 0;
7128         }
7129
7130         /* allocate space to store the return value */
7131         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
7132                 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
7133         }
7134
7135         prev_locals = cfg->locals;
7136         cfg->locals = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));
7137         for (i = 0; i < cheader->num_locals; ++i)
7138                 cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
7139
7140         /* allocate start and end blocks */
7141         /* This is needed so if the inline is aborted, we can clean up */
7142         NEW_BBLOCK (cfg, sbblock);
7143         sbblock->real_offset = real_offset;
7144
7145         NEW_BBLOCK (cfg, ebblock);
7146         ebblock->block_num = cfg->num_bblocks++;
7147         ebblock->real_offset = real_offset;
7148
7149         prev_args = cfg->args;
7150         prev_arg_types = cfg->arg_types;
7151         prev_inlined_method = cfg->inlined_method;
7152         cfg->inlined_method = cmethod;
7153         cfg->ret_var_set = FALSE;
7154         cfg->inline_depth ++;
7155         prev_real_offset = cfg->real_offset;
7156         prev_cbb_hash = cfg->cbb_hash;
7157         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
7158         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
7159         prev_cil_start = cfg->cil_start;
7160         prev_cbb = cfg->cbb;
7161         prev_current_method = cfg->current_method;
7162         prev_generic_context = cfg->generic_context;
7163         prev_ret_var_set = cfg->ret_var_set;
7164         prev_disable_inline = cfg->disable_inline;
7165
7166         if (ip && *ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
7167                 virtual_ = TRUE;
7168
7169         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, sp, real_offset, virtual_);
7170
7171         ret_var_set = cfg->ret_var_set;
7172
7173         cfg->inlined_method = prev_inlined_method;
7174         cfg->real_offset = prev_real_offset;
7175         cfg->cbb_hash = prev_cbb_hash;
7176         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
7177         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
7178         cfg->cil_start = prev_cil_start;
7179         cfg->locals = prev_locals;
7180         cfg->args = prev_args;
7181         cfg->arg_types = prev_arg_types;
7182         cfg->current_method = prev_current_method;
7183         cfg->generic_context = prev_generic_context;
7184         cfg->ret_var_set = prev_ret_var_set;
7185         cfg->disable_inline = prev_disable_inline;
7186         cfg->inline_depth --;
7187
7188         if ((costs >= 0 && costs < 60) || inline_always || (costs >= 0 && (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))) {
7189                 if (cfg->verbose_level > 2)
7190                         printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
7191                 
7192                 cfg->stat_inlined_methods++;
7193
7194                 /* always add some code to avoid block split failures */
7195                 MONO_INST_NEW (cfg, ins, OP_NOP);
7196                 MONO_ADD_INS (prev_cbb, ins);
7197
7198                 prev_cbb->next_bb = sbblock;
7199                 link_bblock (cfg, prev_cbb, sbblock);
7200
7201                 /* 
7202                  * Get rid of the begin and end bblocks if possible to aid local
7203                  * optimizations.
7204                  */
7205                 mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
7206
7207                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
7208                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
7209
7210                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
7211                         MonoBasicBlock *prev = ebblock->in_bb [0];
7212
7213                         if (prev->next_bb == ebblock) {
7214                                 mono_merge_basic_blocks (cfg, prev, ebblock);
7215                                 cfg->cbb = prev;
7216                                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
7217                                         mono_merge_basic_blocks (cfg, prev_cbb, prev);
7218                                         cfg->cbb = prev_cbb;
7219                                 }
7220                         } else {
7221                                 /* There could be a bblock after 'prev', and making 'prev' the current bb could cause problems */
7222                                 cfg->cbb = ebblock;
7223                         }
7224                 } else {
7225                         /* 
7226                          * Its possible that the rvar is set in some prev bblock, but not in others.
7227                          * (#1835).
7228                          */
7229                         if (rvar) {
7230                                 MonoBasicBlock *bb;
7231
7232                                 for (i = 0; i < ebblock->in_count; ++i) {
7233                                         bb = ebblock->in_bb [i];
7234
7235                                         if (bb->last_ins && bb->last_ins->opcode == OP_NOT_REACHED) {
7236                                                 cfg->cbb = bb;
7237
7238                                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
7239                                         }
7240                                 }
7241                         }
7242
7243                         cfg->cbb = ebblock;
7244                 }
7245
7246                 if (rvar) {
7247                         /*
7248                          * If the inlined method contains only a throw, then the ret var is not 
7249                          * set, so set it to a dummy value.
7250                          */
7251                         if (!ret_var_set)
7252                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
7253
7254                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
7255                         *sp++ = ins;
7256                 }
7257                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
7258                 return costs + 1;
7259         } else {
7260                 if (cfg->verbose_level > 2)
7261                         printf ("INLINE ABORTED %s (cost %d)\n", mono_method_full_name (cmethod, TRUE), costs);
7262                 cfg->exception_type = MONO_EXCEPTION_NONE;
7263                 mono_loader_clear_error ();
7264
7265                 /* This gets rid of the newly added bblocks */
7266                 cfg->cbb = prev_cbb;
7267         }
7268         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
7269         return 0;
7270 }
7271
7272 /*
7273  * Some of these comments may well be out-of-date.
7274  * Design decisions: we do a single pass over the IL code (and we do bblock 
7275  * splitting/merging in the few cases when it's required: a back jump to an IL
7276  * address that was not already seen as bblock starting point).
7277  * Code is validated as we go (full verification is still better left to metadata/verify.c).
7278  * Complex operations are decomposed in simpler ones right away. We need to let the 
7279  * arch-specific code peek and poke inside this process somehow (except when the 
7280  * optimizations can take advantage of the full semantic info of coarse opcodes).
7281  * All the opcodes of the form opcode.s are 'normalized' to opcode.
7282  * MonoInst->opcode initially is the IL opcode or some simplification of that 
7283  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
7284  * opcode with value bigger than OP_LAST.
7285  * At this point the IR can be handed over to an interpreter, a dumb code generator
7286  * or to the optimizing code generator that will translate it to SSA form.
7287  *
7288  * Profiling directed optimizations.
7289  * We may compile by default with few or no optimizations and instrument the code
7290  * or the user may indicate what methods to optimize the most either in a config file
7291  * or through repeated runs where the compiler applies offline the optimizations to 
7292  * each method and then decides if it was worth it.
7293  */
7294
7295 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
7296 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
7297 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
7298 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
7299 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
7300 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
7301 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
7302 #define CHECK_TYPELOAD(klass) if (!(klass) || mono_class_has_failure (klass)) TYPE_LOAD_ERROR ((klass))
7303
7304 /* offset from br.s -> br like opcodes */
7305 #define BIG_BRANCH_OFFSET 13
7306
7307 static gboolean
7308 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
7309 {
7310         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
7311
7312         return b == NULL || b == bb;
7313 }
7314
7315 static int
7316 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
7317 {
7318         unsigned char *ip = start;
7319         unsigned char *target;
7320         int i;
7321         guint cli_addr;
7322         MonoBasicBlock *bblock;
7323         const MonoOpcode *opcode;
7324
7325         while (ip < end) {
7326                 cli_addr = ip - start;
7327                 i = mono_opcode_value ((const guint8 **)&ip, end);
7328                 if (i < 0)
7329                         UNVERIFIED;
7330                 opcode = &mono_opcodes [i];
7331                 switch (opcode->argument) {
7332                 case MonoInlineNone:
7333                         ip++; 
7334                         break;
7335                 case MonoInlineString:
7336                 case MonoInlineType:
7337                 case MonoInlineField:
7338                 case MonoInlineMethod:
7339                 case MonoInlineTok:
7340                 case MonoInlineSig:
7341                 case MonoShortInlineR:
7342                 case MonoInlineI:
7343                         ip += 5;
7344                         break;
7345                 case MonoInlineVar:
7346                         ip += 3;
7347                         break;
7348                 case MonoShortInlineVar:
7349                 case MonoShortInlineI:
7350                         ip += 2;
7351                         break;
7352                 case MonoShortInlineBrTarget:
7353                         target = start + cli_addr + 2 + (signed char)ip [1];
7354                         GET_BBLOCK (cfg, bblock, target);
7355                         ip += 2;
7356                         if (ip < end)
7357                                 GET_BBLOCK (cfg, bblock, ip);
7358                         break;
7359                 case MonoInlineBrTarget:
7360                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
7361                         GET_BBLOCK (cfg, bblock, target);
7362                         ip += 5;
7363                         if (ip < end)
7364                                 GET_BBLOCK (cfg, bblock, ip);
7365                         break;
7366                 case MonoInlineSwitch: {
7367                         guint32 n = read32 (ip + 1);
7368                         guint32 j;
7369                         ip += 5;
7370                         cli_addr += 5 + 4 * n;
7371                         target = start + cli_addr;
7372                         GET_BBLOCK (cfg, bblock, target);
7373                         
7374                         for (j = 0; j < n; ++j) {
7375                                 target = start + cli_addr + (gint32)read32 (ip);
7376                                 GET_BBLOCK (cfg, bblock, target);
7377                                 ip += 4;
7378                         }
7379                         break;
7380                 }
7381                 case MonoInlineR:
7382                 case MonoInlineI8:
7383                         ip += 9;
7384                         break;
7385                 default:
7386                         g_assert_not_reached ();
7387                 }
7388
7389                 if (i == CEE_THROW) {
7390                         unsigned char *bb_start = ip - 1;
7391                         
7392                         /* Find the start of the bblock containing the throw */
7393                         bblock = NULL;
7394                         while ((bb_start >= start) && !bblock) {
7395                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
7396                                 bb_start --;
7397                         }
7398                         if (bblock)
7399                                 bblock->out_of_line = 1;
7400                 }
7401         }
7402         return 0;
7403 unverified:
7404 exception_exit:
7405         *pos = ip;
7406         return 1;
7407 }
7408
7409 static inline MonoMethod *
7410 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context, MonoError *error)
7411 {
7412         MonoMethod *method;
7413
7414         mono_error_init (error);
7415
7416         if (m->wrapper_type != MONO_WRAPPER_NONE) {
7417                 method = (MonoMethod *)mono_method_get_wrapper_data (m, token);
7418                 if (context) {
7419                         method = mono_class_inflate_generic_method_checked (method, context, error);
7420                 }
7421         } else {
7422                 method = mono_get_method_checked (m->klass->image, token, klass, context, error);
7423         }
7424
7425         return method;
7426 }
7427
7428 static inline MonoMethod *
7429 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
7430 {
7431         MonoError error;
7432         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context, cfg ? &cfg->error : &error);
7433
7434         if (method && cfg && !cfg->gshared && mono_class_is_open_constructed_type (&method->klass->byval_arg)) {
7435                 mono_error_set_bad_image (&cfg->error, cfg->method->klass->image, "Method with open type while not compiling gshared");
7436                 method = NULL;
7437         }
7438
7439         if (!method && !cfg)
7440                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
7441
7442         return method;
7443 }
7444
7445 static inline MonoClass*
7446 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
7447 {
7448         MonoError error;
7449         MonoClass *klass;
7450
7451         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7452                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
7453                 if (context) {
7454                         klass = mono_class_inflate_generic_class_checked (klass, context, &error);
7455                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7456                 }
7457         } else {
7458                 klass = mono_class_get_and_inflate_typespec_checked (method->klass->image, token, context, &error);
7459                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
7460         }
7461         if (klass)
7462                 mono_class_init (klass);
7463         return klass;
7464 }
7465
7466 static inline MonoMethodSignature*
7467 mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context)
7468 {
7469         MonoMethodSignature *fsig;
7470
7471         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7472                 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
7473         } else {
7474                 fsig = mono_metadata_parse_signature (method->klass->image, token);
7475         }
7476         if (context) {
7477                 MonoError error;
7478                 fsig = mono_inflate_generic_signature(fsig, context, &error);
7479                 // FIXME:
7480                 g_assert(mono_error_ok(&error));
7481         }
7482         return fsig;
7483 }
7484
7485 static MonoMethod*
7486 throw_exception (void)
7487 {
7488         static MonoMethod *method = NULL;
7489
7490         if (!method) {
7491                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
7492                 method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
7493         }
7494         g_assert (method);
7495         return method;
7496 }
7497
7498 static void
7499 emit_throw_exception (MonoCompile *cfg, MonoException *ex)
7500 {
7501         MonoMethod *thrower = throw_exception ();
7502         MonoInst *args [1];
7503
7504         EMIT_NEW_PCONST (cfg, args [0], ex);
7505         mono_emit_method_call (cfg, thrower, args, NULL);
7506 }
7507
7508 /*
7509  * Return the original method is a wrapper is specified. We can only access 
7510  * the custom attributes from the original method.
7511  */
7512 static MonoMethod*
7513 get_original_method (MonoMethod *method)
7514 {
7515         if (method->wrapper_type == MONO_WRAPPER_NONE)
7516                 return method;
7517
7518         /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
7519         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
7520                 return NULL;
7521
7522         /* in other cases we need to find the original method */
7523         return mono_marshal_method_from_wrapper (method);
7524 }
7525
7526 static void
7527 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field)
7528 {
7529         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7530         MonoException *ex = mono_security_core_clr_is_field_access_allowed (get_original_method (caller), field);
7531         if (ex)
7532                 emit_throw_exception (cfg, ex);
7533 }
7534
7535 static void
7536 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
7537 {
7538         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7539         MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
7540         if (ex)
7541                 emit_throw_exception (cfg, ex);
7542 }
7543
7544 /*
7545  * Check that the IL instructions at ip are the array initialization
7546  * sequence and return the pointer to the data and the size.
7547  */
7548 static const char*
7549 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
7550 {
7551         /*
7552          * newarr[System.Int32]
7553          * dup
7554          * ldtoken field valuetype ...
7555          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
7556          */
7557         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
7558                 MonoError error;
7559                 guint32 token = read32 (ip + 7);
7560                 guint32 field_token = read32 (ip + 2);
7561                 guint32 field_index = field_token & 0xffffff;
7562                 guint32 rva;
7563                 const char *data_ptr;
7564                 int size = 0;
7565                 MonoMethod *cmethod;
7566                 MonoClass *dummy_class;
7567                 MonoClassField *field = mono_field_from_token_checked (method->klass->image, field_token, &dummy_class, NULL, &error);
7568                 int dummy_align;
7569
7570                 if (!field) {
7571                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7572                         return NULL;
7573                 }
7574
7575                 *out_field_token = field_token;
7576
7577                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
7578                 if (!cmethod)
7579                         return NULL;
7580                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
7581                         return NULL;
7582                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
7583                 case MONO_TYPE_BOOLEAN:
7584                 case MONO_TYPE_I1:
7585                 case MONO_TYPE_U1:
7586                         size = 1; break;
7587                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
7588 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
7589                 case MONO_TYPE_CHAR:
7590                 case MONO_TYPE_I2:
7591                 case MONO_TYPE_U2:
7592                         size = 2; break;
7593                 case MONO_TYPE_I4:
7594                 case MONO_TYPE_U4:
7595                 case MONO_TYPE_R4:
7596                         size = 4; break;
7597                 case MONO_TYPE_R8:
7598                 case MONO_TYPE_I8:
7599                 case MONO_TYPE_U8:
7600                         size = 8; break;
7601 #endif
7602                 default:
7603                         return NULL;
7604                 }
7605                 size *= len;
7606                 if (size > mono_type_size (field->type, &dummy_align))
7607                     return NULL;
7608                 *out_size = size;
7609                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
7610                 if (!image_is_dynamic (method->klass->image)) {
7611                         field_index = read32 (ip + 2) & 0xffffff;
7612                         mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
7613                         data_ptr = mono_image_rva_map (method->klass->image, rva);
7614                         /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
7615                         /* for aot code we do the lookup on load */
7616                         if (aot && data_ptr)
7617                                 return (const char *)GUINT_TO_POINTER (rva);
7618                 } else {
7619                         /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
7620                         g_assert (!aot);
7621                         data_ptr = mono_field_get_data (field);
7622                 }
7623                 return data_ptr;
7624         }
7625         return NULL;
7626 }
7627
7628 static void
7629 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
7630 {
7631         MonoError error;
7632         char *method_fname = mono_method_full_name (method, TRUE);
7633         char *method_code;
7634         MonoMethodHeader *header = mono_method_get_header_checked (method, &error);
7635
7636         if (!header) {
7637                 method_code = g_strdup_printf ("could not parse method body due to %s", mono_error_get_message (&error));
7638                 mono_error_cleanup (&error);
7639         } else if (header->code_size == 0)
7640                 method_code = g_strdup ("method body is empty.");
7641         else
7642                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
7643         mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code));
7644         g_free (method_fname);
7645         g_free (method_code);
7646         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
7647 }
7648
7649 static void
7650 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
7651 {
7652         MonoInst *ins;
7653         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
7654         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
7655                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
7656                 /* Optimize reg-reg moves away */
7657                 /* 
7658                  * Can't optimize other opcodes, since sp[0] might point to
7659                  * the last ins of a decomposed opcode.
7660                  */
7661                 sp [0]->dreg = (cfg)->locals [n]->dreg;
7662         } else {
7663                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
7664         }
7665 }
7666
7667 /*
7668  * ldloca inhibits many optimizations so try to get rid of it in common
7669  * cases.
7670  */
7671 static inline unsigned char *
7672 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
7673 {
7674         int local, token;
7675         MonoClass *klass;
7676         MonoType *type;
7677
7678         if (size == 1) {
7679                 local = ip [1];
7680                 ip += 2;
7681         } else {
7682                 local = read16 (ip + 2);
7683                 ip += 4;
7684         }
7685         
7686         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
7687                 /* From the INITOBJ case */
7688                 token = read32 (ip + 2);
7689                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
7690                 CHECK_TYPELOAD (klass);
7691                 type = mini_get_underlying_type (&klass->byval_arg);
7692                 emit_init_local (cfg, local, type, TRUE);
7693                 return ip + 6;
7694         }
7695  exception_exit:
7696         return NULL;
7697 }
7698
7699 static MonoInst*
7700 emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used, MonoInst **sp)
7701 {
7702         MonoInst *icall_args [16];
7703         MonoInst *call_target, *ins, *vtable_ins;
7704         int arg_reg, this_reg, vtable_reg;
7705         gboolean is_iface = cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE;
7706         gboolean is_gsharedvt = cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig);
7707         gboolean variant_iface = FALSE;
7708         guint32 slot;
7709         int offset;
7710
7711         /*
7712          * In llvm-only mode, vtables contain function descriptors instead of
7713          * method addresses/trampolines.
7714          */
7715         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
7716
7717         if (is_iface)
7718                 slot = mono_method_get_imt_slot (cmethod);
7719         else
7720                 slot = mono_method_get_vtable_index (cmethod);
7721
7722         this_reg = sp [0]->dreg;
7723
7724         if (is_iface && mono_class_has_variant_generic_params (cmethod->klass))
7725                 variant_iface = TRUE;
7726
7727         if (!fsig->generic_param_count && !is_iface && !is_gsharedvt) {
7728                 /*
7729                  * The simplest case, a normal virtual call.
7730                  */
7731                 int slot_reg = alloc_preg (cfg);
7732                 int addr_reg = alloc_preg (cfg);
7733                 int arg_reg = alloc_preg (cfg);
7734                 MonoBasicBlock *non_null_bb;
7735
7736                 vtable_reg = alloc_preg (cfg);
7737                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7738                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) + (slot * SIZEOF_VOID_P);
7739
7740                 /* Load the vtable slot, which contains a function descriptor. */
7741                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7742
7743                 NEW_BBLOCK (cfg, non_null_bb);
7744
7745                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, slot_reg, 0);
7746                 cfg->cbb->last_ins->flags |= MONO_INST_LIKELY;
7747                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, non_null_bb);
7748
7749                 /* Slow path */
7750                 // FIXME: Make the wrapper use the preserveall cconv
7751                 // FIXME: Use one icall per slot for small slot numbers ?
7752                 icall_args [0] = vtable_ins;
7753                 EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7754                 /* Make the icall return the vtable slot value to save some code space */
7755                 ins = mono_emit_jit_icall (cfg, mono_init_vtable_slot, icall_args);
7756                 ins->dreg = slot_reg;
7757                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, non_null_bb);
7758
7759                 /* Fastpath */
7760                 MONO_START_BB (cfg, non_null_bb);
7761                 /* Load the address + arg from the vtable slot */
7762                 EMIT_NEW_LOAD_MEMBASE (cfg, call_target, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7763                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, arg_reg, slot_reg, SIZEOF_VOID_P);
7764
7765                 return emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
7766         }
7767
7768         if (!fsig->generic_param_count && is_iface && !variant_iface && !is_gsharedvt) {
7769                 /*
7770                  * A simple interface call
7771                  *
7772                  * We make a call through an imt slot to obtain the function descriptor we need to call.
7773                  * The imt slot contains a function descriptor for a runtime function + arg.
7774                  */
7775                 int slot_reg = alloc_preg (cfg);
7776                 int addr_reg = alloc_preg (cfg);
7777                 int arg_reg = alloc_preg (cfg);
7778                 MonoInst *thunk_addr_ins, *thunk_arg_ins, *ftndesc_ins;
7779
7780                 vtable_reg = alloc_preg (cfg);
7781                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7782                 offset = ((gint32)slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
7783
7784                 /*
7785                  * The slot is already initialized when the vtable is created so there is no need
7786                  * to check it here.
7787                  */
7788
7789                 /* Load the imt slot, which contains a function descriptor. */
7790                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7791
7792                 /* Load the address + arg of the imt thunk from the imt slot */
7793                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_addr_ins, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7794                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_arg_ins, OP_LOAD_MEMBASE, arg_reg, slot_reg, SIZEOF_VOID_P);
7795                 /*
7796                  * IMT thunks in llvm-only mode are C functions which take an info argument
7797                  * plus the imt method and return the ftndesc to call.
7798                  */
7799                 icall_args [0] = thunk_arg_ins;
7800                 icall_args [1] = emit_get_rgctx_method (cfg, context_used,
7801                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7802                 ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_thunk, icall_args, thunk_addr_ins, NULL, NULL);
7803
7804                 return emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
7805         }
7806
7807         if ((fsig->generic_param_count || variant_iface) && !is_gsharedvt) {
7808                 /*
7809                  * This is similar to the interface case, the vtable slot points to an imt thunk which is
7810                  * dynamically extended as more instantiations are discovered.
7811                  * This handles generic virtual methods both on classes and interfaces.
7812                  */
7813                 int slot_reg = alloc_preg (cfg);
7814                 int addr_reg = alloc_preg (cfg);
7815                 int arg_reg = alloc_preg (cfg);
7816                 int ftndesc_reg = alloc_preg (cfg);
7817                 MonoInst *thunk_addr_ins, *thunk_arg_ins, *ftndesc_ins;
7818                 MonoBasicBlock *slowpath_bb, *end_bb;
7819
7820                 NEW_BBLOCK (cfg, slowpath_bb);
7821                 NEW_BBLOCK (cfg, end_bb);
7822
7823                 vtable_reg = alloc_preg (cfg);
7824                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7825                 if (is_iface)
7826                         offset = ((gint32)slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
7827                 else
7828                         offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) + (slot * SIZEOF_VOID_P);
7829
7830                 /* Load the slot, which contains a function descriptor. */
7831                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7832
7833                 /* These slots are not initialized, so fall back to the slow path until they are initialized */
7834                 /* That happens when mono_method_add_generic_virtual_invocation () creates an IMT thunk */
7835                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, slot_reg, 0);
7836                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, slowpath_bb);
7837
7838                 /* Fastpath */
7839                 /* Same as with iface calls */
7840                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_addr_ins, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7841                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_arg_ins, OP_LOAD_MEMBASE, arg_reg, slot_reg, SIZEOF_VOID_P);
7842                 icall_args [0] = thunk_arg_ins;
7843                 icall_args [1] = emit_get_rgctx_method (cfg, context_used,
7844                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7845                 ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_thunk, icall_args, thunk_addr_ins, NULL, NULL);
7846                 ftndesc_ins->dreg = ftndesc_reg;
7847                 /*
7848                  * Unlike normal iface calls, these imt thunks can return NULL, i.e. when they are passed an instantiation
7849                  * they don't know about yet. Fall back to the slowpath in that case.
7850                  */
7851                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ftndesc_reg, 0);
7852                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, slowpath_bb);
7853
7854                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
7855
7856                 /* Slowpath */
7857                 MONO_START_BB (cfg, slowpath_bb);
7858                 icall_args [0] = vtable_ins;
7859                 EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7860                 icall_args [2] = emit_get_rgctx_method (cfg, context_used,
7861                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7862                 if (is_iface)
7863                         ftndesc_ins = mono_emit_jit_icall (cfg, mono_resolve_generic_virtual_iface_call, icall_args);
7864                 else
7865                         ftndesc_ins = mono_emit_jit_icall (cfg, mono_resolve_generic_virtual_call, icall_args);
7866                 ftndesc_ins->dreg = ftndesc_reg;
7867                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
7868
7869                 /* Common case */
7870                 MONO_START_BB (cfg, end_bb);
7871                 return emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
7872         }
7873
7874         /*
7875          * Non-optimized cases
7876          */
7877         icall_args [0] = sp [0];
7878         EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7879
7880         icall_args [2] = emit_get_rgctx_method (cfg, context_used,
7881                                                                                         cmethod, MONO_RGCTX_INFO_METHOD);
7882
7883         arg_reg = alloc_preg (cfg);
7884         MONO_EMIT_NEW_PCONST (cfg, arg_reg, NULL);
7885         EMIT_NEW_VARLOADA_VREG (cfg, icall_args [3], arg_reg, &mono_defaults.int_class->byval_arg);
7886
7887         g_assert (is_gsharedvt);
7888         if (is_iface)
7889                 call_target = mono_emit_jit_icall (cfg, mono_resolve_iface_call_gsharedvt, icall_args);
7890         else
7891                 call_target = mono_emit_jit_icall (cfg, mono_resolve_vcall_gsharedvt, icall_args);
7892
7893         /*
7894          * Pass the extra argument even if the callee doesn't receive it, most
7895          * calling conventions allow this.
7896          */
7897         return emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
7898 }
7899
7900 static gboolean
7901 is_exception_class (MonoClass *klass)
7902 {
7903         while (klass) {
7904                 if (klass == mono_defaults.exception_class)
7905                         return TRUE;
7906                 klass = klass->parent;
7907         }
7908         return FALSE;
7909 }
7910
7911 /*
7912  * is_jit_optimizer_disabled:
7913  *
7914  *   Determine whenever M's assembly has a DebuggableAttribute with the
7915  * IsJITOptimizerDisabled flag set.
7916  */
7917 static gboolean
7918 is_jit_optimizer_disabled (MonoMethod *m)
7919 {
7920         MonoError error;
7921         MonoAssembly *ass = m->klass->image->assembly;
7922         MonoCustomAttrInfo* attrs;
7923         MonoClass *klass;
7924         int i;
7925         gboolean val = FALSE;
7926
7927         g_assert (ass);
7928         if (ass->jit_optimizer_disabled_inited)
7929                 return ass->jit_optimizer_disabled;
7930
7931         klass = mono_class_try_get_debuggable_attribute_class ();
7932
7933         if (!klass) {
7934                 /* Linked away */
7935                 ass->jit_optimizer_disabled = FALSE;
7936                 mono_memory_barrier ();
7937                 ass->jit_optimizer_disabled_inited = TRUE;
7938                 return FALSE;
7939         }
7940
7941         attrs = mono_custom_attrs_from_assembly_checked (ass, &error);
7942         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7943         if (attrs) {
7944                 for (i = 0; i < attrs->num_attrs; ++i) {
7945                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
7946                         const gchar *p;
7947                         MonoMethodSignature *sig;
7948
7949                         if (!attr->ctor || attr->ctor->klass != klass)
7950                                 continue;
7951                         /* Decode the attribute. See reflection.c */
7952                         p = (const char*)attr->data;
7953                         g_assert (read16 (p) == 0x0001);
7954                         p += 2;
7955
7956                         // FIXME: Support named parameters
7957                         sig = mono_method_signature (attr->ctor);
7958                         if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
7959                                 continue;
7960                         /* Two boolean arguments */
7961                         p ++;
7962                         val = *p;
7963                 }
7964                 mono_custom_attrs_free (attrs);
7965         }
7966
7967         ass->jit_optimizer_disabled = val;
7968         mono_memory_barrier ();
7969         ass->jit_optimizer_disabled_inited = TRUE;
7970
7971         return val;
7972 }
7973
7974 static gboolean
7975 is_supported_tail_call (MonoCompile *cfg, MonoMethod *method, MonoMethod *cmethod, MonoMethodSignature *fsig, int call_opcode)
7976 {
7977         gboolean supported_tail_call;
7978         int i;
7979
7980         supported_tail_call = mono_arch_tail_call_supported (cfg, mono_method_signature (method), mono_method_signature (cmethod));
7981
7982         for (i = 0; i < fsig->param_count; ++i) {
7983                 if (fsig->params [i]->byref || fsig->params [i]->type == MONO_TYPE_PTR || fsig->params [i]->type == MONO_TYPE_FNPTR)
7984                         /* These can point to the current method's stack */
7985                         supported_tail_call = FALSE;
7986         }
7987         if (fsig->hasthis && cmethod->klass->valuetype)
7988                 /* this might point to the current method's stack */
7989                 supported_tail_call = FALSE;
7990         if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
7991                 supported_tail_call = FALSE;
7992         if (cfg->method->save_lmf)
7993                 supported_tail_call = FALSE;
7994         if (cmethod->wrapper_type && cmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
7995                 supported_tail_call = FALSE;
7996         if (call_opcode != CEE_CALL)
7997                 supported_tail_call = FALSE;
7998
7999         /* Debugging support */
8000 #if 0
8001         if (supported_tail_call) {
8002                 if (!mono_debug_count ())
8003                         supported_tail_call = FALSE;
8004         }
8005 #endif
8006
8007         return supported_tail_call;
8008 }
8009
8010 /*
8011  * handle_ctor_call:
8012  *
8013  *   Handle calls made to ctors from NEWOBJ opcodes.
8014  */
8015 static void
8016 handle_ctor_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used,
8017                                   MonoInst **sp, guint8 *ip, int *inline_costs)
8018 {
8019         MonoInst *vtable_arg = NULL, *callvirt_this_arg = NULL, *ins;
8020
8021         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
8022                                         mono_method_is_generic_sharable (cmethod, TRUE)) {
8023                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
8024                         mono_class_vtable (cfg->domain, cmethod->klass);
8025                         CHECK_TYPELOAD (cmethod->klass);
8026
8027                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
8028                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
8029                 } else {
8030                         if (context_used) {
8031                                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
8032                                                                                                    cmethod->klass, MONO_RGCTX_INFO_VTABLE);
8033                         } else {
8034                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
8035
8036                                 CHECK_TYPELOAD (cmethod->klass);
8037                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
8038                         }
8039                 }
8040         }
8041
8042         /* Avoid virtual calls to ctors if possible */
8043         if (mono_class_is_marshalbyref (cmethod->klass))
8044                 callvirt_this_arg = sp [0];
8045
8046         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
8047                 g_assert (MONO_TYPE_IS_VOID (fsig->ret));
8048                 CHECK_CFG_EXCEPTION;
8049         } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
8050                            mono_method_check_inlining (cfg, cmethod) &&
8051                            !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE)) {
8052                 int costs;
8053
8054                 if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, FALSE))) {
8055                         cfg->real_offset += 5;
8056
8057                         *inline_costs += costs - 5;
8058                 } else {
8059                         INLINE_FAILURE ("inline failure");
8060                         // FIXME-VT: Clean this up
8061                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
8062                                 GSHAREDVT_FAILURE(*ip);
8063                         mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, callvirt_this_arg, NULL, NULL);
8064                 }
8065         } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
8066                 MonoInst *addr;
8067
8068                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
8069
8070                 if (cfg->llvm_only) {
8071                         // FIXME: Avoid initializing vtable_arg
8072                         emit_llvmonly_calli (cfg, fsig, sp, addr);
8073                 } else {
8074                         mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
8075                 }
8076         } else if (context_used &&
8077                            ((!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
8078                                  !mono_class_generic_sharing_enabled (cmethod->klass)) || cfg->gsharedvt)) {
8079                 MonoInst *cmethod_addr;
8080
8081                 /* Generic calls made out of gsharedvt methods cannot be patched, so use an indirect call */
8082
8083                 if (cfg->llvm_only) {
8084                         MonoInst *addr = emit_get_rgctx_method (cfg, context_used, cmethod,
8085                                                                                                         MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
8086                         emit_llvmonly_calli (cfg, fsig, sp, addr);
8087                 } else {
8088                         cmethod_addr = emit_get_rgctx_method (cfg, context_used,
8089                                                                                                   cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
8090
8091                         mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
8092                 }
8093         } else {
8094                 INLINE_FAILURE ("ctor call");
8095                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
8096                                                                                   callvirt_this_arg, NULL, vtable_arg);
8097         }
8098  exception_exit:
8099         return;
8100 }
8101
8102 static void
8103 emit_setret (MonoCompile *cfg, MonoInst *val)
8104 {
8105         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (cfg->method)->ret);
8106         MonoInst *ins;
8107
8108         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
8109                 MonoInst *ret_addr;
8110
8111                 if (!cfg->vret_addr) {
8112                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, val);
8113                 } else {
8114                         EMIT_NEW_RETLOADA (cfg, ret_addr);
8115
8116                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, val->dreg);
8117                         ins->klass = mono_class_from_mono_type (ret_type);
8118                 }
8119         } else {
8120 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
8121                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
8122                         MonoInst *iargs [1];
8123                         MonoInst *conv;
8124
8125                         iargs [0] = val;
8126                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
8127                         mono_arch_emit_setret (cfg, cfg->method, conv);
8128                 } else {
8129                         mono_arch_emit_setret (cfg, cfg->method, val);
8130                 }
8131 #else
8132                 mono_arch_emit_setret (cfg, cfg->method, val);
8133 #endif
8134         }
8135 }
8136
8137 /*
8138  * mono_method_to_ir:
8139  *
8140  *   Translate the .net IL into linear IR.
8141  */
8142 int
8143 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
8144                    MonoInst *return_var, MonoInst **inline_args, 
8145                    guint inline_offset, gboolean is_virtual_call)
8146 {
8147         MonoError error;
8148         MonoInst *ins, **sp, **stack_start;
8149         MonoBasicBlock *tblock = NULL, *init_localsbb = NULL;
8150         MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
8151         MonoMethod *cmethod, *method_definition;
8152         MonoInst **arg_array;
8153         MonoMethodHeader *header;
8154         MonoImage *image;
8155         guint32 token, ins_flag;
8156         MonoClass *klass;
8157         MonoClass *constrained_class = NULL;
8158         unsigned char *ip, *end, *target, *err_pos;
8159         MonoMethodSignature *sig;
8160         MonoGenericContext *generic_context = NULL;
8161         MonoGenericContainer *generic_container = NULL;
8162         MonoType **param_types;
8163         int i, n, start_new_bblock, dreg;
8164         int num_calls = 0, inline_costs = 0;
8165         int breakpoint_id = 0;
8166         guint num_args;
8167         GSList *class_inits = NULL;
8168         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
8169         int context_used;
8170         gboolean init_locals, seq_points, skip_dead_blocks;
8171         gboolean sym_seq_points = FALSE;
8172         MonoDebugMethodInfo *minfo;
8173         MonoBitSet *seq_point_locs = NULL;
8174         MonoBitSet *seq_point_set_locs = NULL;
8175
8176         cfg->disable_inline = is_jit_optimizer_disabled (method);
8177
8178         /* serialization and xdomain stuff may need access to private fields and methods */
8179         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
8180         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
8181         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
8182         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
8183         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
8184         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
8185
8186         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
8187         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
8188         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
8189         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
8190         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF;
8191
8192         image = method->klass->image;
8193         header = mono_method_get_header_checked (method, &cfg->error);
8194         if (!header) {
8195                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
8196                 goto exception_exit;
8197         }
8198         generic_container = mono_method_get_generic_container (method);
8199         sig = mono_method_signature (method);
8200         num_args = sig->hasthis + sig->param_count;
8201         ip = (unsigned char*)header->code;
8202         cfg->cil_start = ip;
8203         end = ip + header->code_size;
8204         cfg->stat_cil_code_size += header->code_size;
8205
8206         seq_points = cfg->gen_seq_points && cfg->method == method;
8207
8208         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
8209                 /* We could hit a seq point before attaching to the JIT (#8338) */
8210                 seq_points = FALSE;
8211         }
8212
8213         if (cfg->gen_sdb_seq_points && cfg->method == method) {
8214                 minfo = mono_debug_lookup_method (method);
8215                 if (minfo) {
8216                         MonoSymSeqPoint *sps;
8217                         int i, n_il_offsets;
8218
8219                         mono_debug_get_seq_points (minfo, NULL, NULL, NULL, &sps, &n_il_offsets);
8220                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
8221                         seq_point_set_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
8222                         sym_seq_points = TRUE;
8223                         for (i = 0; i < n_il_offsets; ++i) {
8224                                 if (sps [i].il_offset < header->code_size)
8225                                         mono_bitset_set_fast (seq_point_locs, sps [i].il_offset);
8226                         }
8227                         g_free (sps);
8228                 } else if (!method->wrapper_type && !method->dynamic && mono_debug_image_has_debug_info (method->klass->image)) {
8229                         /* Methods without line number info like auto-generated property accessors */
8230                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
8231                         seq_point_set_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
8232                         sym_seq_points = TRUE;
8233                 }
8234         }
8235
8236         /* 
8237          * Methods without init_locals set could cause asserts in various passes
8238          * (#497220). To work around this, we emit dummy initialization opcodes
8239          * (OP_DUMMY_ICONST etc.) which generate no code. These are only supported
8240          * on some platforms.
8241          */
8242         if ((cfg->opt & MONO_OPT_UNSAFE) && cfg->backend->have_dummy_init)
8243                 init_locals = header->init_locals;
8244         else
8245                 init_locals = TRUE;
8246
8247         method_definition = method;
8248         while (method_definition->is_inflated) {
8249                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
8250                 method_definition = imethod->declaring;
8251         }
8252
8253         /* SkipVerification is not allowed if core-clr is enabled */
8254         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
8255                 dont_verify = TRUE;
8256                 dont_verify_stloc = TRUE;
8257         }
8258
8259         if (sig->is_inflated)
8260                 generic_context = mono_method_get_context (method);
8261         else if (generic_container)
8262                 generic_context = &generic_container->context;
8263         cfg->generic_context = generic_context;
8264
8265         if (!cfg->gshared)
8266                 g_assert (!sig->has_type_parameters);
8267
8268         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
8269                 g_assert (method->is_inflated);
8270                 g_assert (mono_method_get_context (method)->method_inst);
8271         }
8272         if (method->is_inflated && mono_method_get_context (method)->method_inst)
8273                 g_assert (sig->generic_param_count);
8274
8275         if (cfg->method == method) {
8276                 cfg->real_offset = 0;
8277         } else {
8278                 cfg->real_offset = inline_offset;
8279         }
8280
8281         cfg->cil_offset_to_bb = (MonoBasicBlock **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
8282         cfg->cil_offset_to_bb_len = header->code_size;
8283
8284         cfg->current_method = method;
8285
8286         if (cfg->verbose_level > 2)
8287                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
8288
8289         param_types = (MonoType **)mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
8290         if (sig->hasthis)
8291                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
8292         for (n = 0; n < sig->param_count; ++n)
8293                 param_types [n + sig->hasthis] = sig->params [n];
8294         cfg->arg_types = param_types;
8295
8296         cfg->dont_inline = g_list_prepend (cfg->dont_inline, method);
8297         if (cfg->method == method) {
8298
8299                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
8300                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
8301
8302                 /* ENTRY BLOCK */
8303                 NEW_BBLOCK (cfg, start_bblock);
8304                 cfg->bb_entry = start_bblock;
8305                 start_bblock->cil_code = NULL;
8306                 start_bblock->cil_length = 0;
8307
8308                 /* EXIT BLOCK */
8309                 NEW_BBLOCK (cfg, end_bblock);
8310                 cfg->bb_exit = end_bblock;
8311                 end_bblock->cil_code = NULL;
8312                 end_bblock->cil_length = 0;
8313                 end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
8314                 g_assert (cfg->num_bblocks == 2);
8315
8316                 arg_array = cfg->args;
8317
8318                 if (header->num_clauses) {
8319                         cfg->spvars = g_hash_table_new (NULL, NULL);
8320                         cfg->exvars = g_hash_table_new (NULL, NULL);
8321                 }
8322                 /* handle exception clauses */
8323                 for (i = 0; i < header->num_clauses; ++i) {
8324                         MonoBasicBlock *try_bb;
8325                         MonoExceptionClause *clause = &header->clauses [i];
8326                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
8327
8328                         try_bb->real_offset = clause->try_offset;
8329                         try_bb->try_start = TRUE;
8330                         try_bb->region = ((i + 1) << 8) | clause->flags;
8331                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
8332                         tblock->real_offset = clause->handler_offset;
8333                         tblock->flags |= BB_EXCEPTION_HANDLER;
8334
8335                         /*
8336                          * Linking the try block with the EH block hinders inlining as we won't be able to 
8337                          * merge the bblocks from inlining and produce an artificial hole for no good reason.
8338                          */
8339                         if (COMPILE_LLVM (cfg))
8340                                 link_bblock (cfg, try_bb, tblock);
8341
8342                         if (*(ip + clause->handler_offset) == CEE_POP)
8343                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
8344
8345                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
8346                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
8347                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
8348                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
8349                                 MONO_ADD_INS (tblock, ins);
8350
8351                                 if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FILTER) {
8352                                         /* finally clauses already have a seq point */
8353                                         /* seq points for filter clauses are emitted below */
8354                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
8355                                         MONO_ADD_INS (tblock, ins);
8356                                 }
8357
8358                                 /* todo: is a fault block unsafe to optimize? */
8359                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
8360                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
8361                         }
8362
8363                         /*printf ("clause try IL_%04x to IL_%04x handler %d at IL_%04x to IL_%04x\n", clause->try_offset, clause->try_offset + clause->try_len, clause->flags, clause->handler_offset, clause->handler_offset + clause->handler_len);
8364                           while (p < end) {
8365                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
8366                           }*/
8367                         /* catch and filter blocks get the exception object on the stack */
8368                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
8369                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8370
8371                                 /* mostly like handle_stack_args (), but just sets the input args */
8372                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
8373                                 tblock->in_scount = 1;
8374                                 tblock->in_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
8375                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
8376
8377                                 cfg->cbb = tblock;
8378
8379 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
8380                                 /* The EH code passes in the exception in a register to both JITted and LLVM compiled code */
8381                                 if (!cfg->compile_llvm) {
8382                                         MONO_INST_NEW (cfg, ins, OP_GET_EX_OBJ);
8383                                         ins->dreg = tblock->in_stack [0]->dreg;
8384                                         MONO_ADD_INS (tblock, ins);
8385                                 }
8386 #else
8387                                 MonoInst *dummy_use;
8388
8389                                 /* 
8390                                  * Add a dummy use for the exvar so its liveness info will be
8391                                  * correct.
8392                                  */
8393                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
8394 #endif
8395
8396                                 if (seq_points && clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8397                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
8398                                         MONO_ADD_INS (tblock, ins);
8399                                 }
8400                                 
8401                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8402                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
8403                                         tblock->flags |= BB_EXCEPTION_HANDLER;
8404                                         tblock->real_offset = clause->data.filter_offset;
8405                                         tblock->in_scount = 1;
8406                                         tblock->in_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
8407                                         /* The filter block shares the exvar with the handler block */
8408                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
8409                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
8410                                         MONO_ADD_INS (tblock, ins);
8411                                 }
8412                         }
8413
8414                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
8415                                         clause->data.catch_class &&
8416                                         cfg->gshared &&
8417                                         mono_class_check_context_used (clause->data.catch_class)) {
8418                                 /*
8419                                  * In shared generic code with catch
8420                                  * clauses containing type variables
8421                                  * the exception handling code has to
8422                                  * be able to get to the rgctx.
8423                                  * Therefore we have to make sure that
8424                                  * the vtable/mrgctx argument (for
8425                                  * static or generic methods) or the
8426                                  * "this" argument (for non-static
8427                                  * methods) are live.
8428                                  */
8429                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8430                                                 mini_method_get_context (method)->method_inst ||
8431                                                 method->klass->valuetype) {
8432                                         mono_get_vtable_var (cfg);
8433                                 } else {
8434                                         MonoInst *dummy_use;
8435
8436                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
8437                                 }
8438                         }
8439                 }
8440         } else {
8441                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
8442                 cfg->cbb = start_bblock;
8443                 cfg->args = arg_array;
8444                 mono_save_args (cfg, sig, inline_args);
8445         }
8446
8447         /* FIRST CODE BLOCK */
8448         NEW_BBLOCK (cfg, tblock);
8449         tblock->cil_code = ip;
8450         cfg->cbb = tblock;
8451         cfg->ip = ip;
8452
8453         ADD_BBLOCK (cfg, tblock);
8454
8455         if (cfg->method == method) {
8456                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
8457                 if (breakpoint_id) {
8458                         MONO_INST_NEW (cfg, ins, OP_BREAK);
8459                         MONO_ADD_INS (cfg->cbb, ins);
8460                 }
8461         }
8462
8463         /* we use a separate basic block for the initialization code */
8464         NEW_BBLOCK (cfg, init_localsbb);
8465         cfg->bb_init = init_localsbb;
8466         init_localsbb->real_offset = cfg->real_offset;
8467         start_bblock->next_bb = init_localsbb;
8468         init_localsbb->next_bb = cfg->cbb;
8469         link_bblock (cfg, start_bblock, init_localsbb);
8470         link_bblock (cfg, init_localsbb, cfg->cbb);
8471                 
8472         cfg->cbb = init_localsbb;
8473
8474         if (cfg->gsharedvt && cfg->method == method) {
8475                 MonoGSharedVtMethodInfo *info;
8476                 MonoInst *var, *locals_var;
8477                 int dreg;
8478
8479                 info = (MonoGSharedVtMethodInfo *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoGSharedVtMethodInfo));
8480                 info->method = cfg->method;
8481                 info->count_entries = 16;
8482                 info->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
8483                 cfg->gsharedvt_info = info;
8484
8485                 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8486                 /* prevent it from being register allocated */
8487                 //var->flags |= MONO_INST_VOLATILE;
8488                 cfg->gsharedvt_info_var = var;
8489
8490                 ins = emit_get_rgctx_gsharedvt_method (cfg, mini_method_check_context_used (cfg, method), method, info);
8491                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, var->dreg, ins->dreg);
8492
8493                 /* Allocate locals */
8494                 locals_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8495                 /* prevent it from being register allocated */
8496                 //locals_var->flags |= MONO_INST_VOLATILE;
8497                 cfg->gsharedvt_locals_var = locals_var;
8498
8499                 dreg = alloc_ireg (cfg);
8500                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, dreg, var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, locals_size));
8501
8502                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
8503                 ins->dreg = locals_var->dreg;
8504                 ins->sreg1 = dreg;
8505                 MONO_ADD_INS (cfg->cbb, ins);
8506                 cfg->gsharedvt_locals_var_ins = ins;
8507                 
8508                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
8509                 /*
8510                 if (init_locals)
8511                         ins->flags |= MONO_INST_INIT;
8512                 */
8513         }
8514
8515         if (mono_security_core_clr_enabled ()) {
8516                 /* check if this is native code, e.g. an icall or a p/invoke */
8517                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
8518                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
8519                         if (wrapped) {
8520                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
8521                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
8522
8523                                 /* if this ia a native call then it can only be JITted from platform code */
8524                                 if ((icall || pinvk) && method->klass && method->klass->image) {
8525                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
8526                                                 MonoException *ex = icall ? mono_get_exception_security () : 
8527                                                         mono_get_exception_method_access ();
8528                                                 emit_throw_exception (cfg, ex);
8529                                         }
8530                                 }
8531                         }
8532                 }
8533         }
8534
8535         CHECK_CFG_EXCEPTION;
8536
8537         if (header->code_size == 0)
8538                 UNVERIFIED;
8539
8540         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
8541                 ip = err_pos;
8542                 UNVERIFIED;
8543         }
8544
8545         if (cfg->method == method)
8546                 mono_debug_init_method (cfg, cfg->cbb, breakpoint_id);
8547
8548         for (n = 0; n < header->num_locals; ++n) {
8549                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
8550                         UNVERIFIED;
8551         }
8552         class_inits = NULL;
8553
8554         /* We force the vtable variable here for all shared methods
8555            for the possibility that they might show up in a stack
8556            trace where their exact instantiation is needed. */
8557         if (cfg->gshared && method == cfg->method) {
8558                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8559                                 mini_method_get_context (method)->method_inst ||
8560                                 method->klass->valuetype) {
8561                         mono_get_vtable_var (cfg);
8562                 } else {
8563                         /* FIXME: Is there a better way to do this?
8564                            We need the variable live for the duration
8565                            of the whole method. */
8566                         cfg->args [0]->flags |= MONO_INST_VOLATILE;
8567                 }
8568         }
8569
8570         /* add a check for this != NULL to inlined methods */
8571         if (is_virtual_call) {
8572                 MonoInst *arg_ins;
8573
8574                 NEW_ARGLOAD (cfg, arg_ins, 0);
8575                 MONO_ADD_INS (cfg->cbb, arg_ins);
8576                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
8577         }
8578
8579         skip_dead_blocks = !dont_verify;
8580         if (skip_dead_blocks) {
8581                 original_bb = bb = mono_basic_block_split (method, &cfg->error);
8582                 CHECK_CFG_ERROR;
8583                 g_assert (bb);
8584         }
8585
8586         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
8587         stack_start = sp = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
8588
8589         ins_flag = 0;
8590         start_new_bblock = 0;
8591         while (ip < end) {
8592                 if (cfg->method == method)
8593                         cfg->real_offset = ip - header->code;
8594                 else
8595                         cfg->real_offset = inline_offset;
8596                 cfg->ip = ip;
8597
8598                 context_used = 0;
8599
8600                 if (start_new_bblock) {
8601                         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
8602                         if (start_new_bblock == 2) {
8603                                 g_assert (ip == tblock->cil_code);
8604                         } else {
8605                                 GET_BBLOCK (cfg, tblock, ip);
8606                         }
8607                         cfg->cbb->next_bb = tblock;
8608                         cfg->cbb = tblock;
8609                         start_new_bblock = 0;
8610                         for (i = 0; i < cfg->cbb->in_scount; ++i) {
8611                                 if (cfg->verbose_level > 3)
8612                                         printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8613                                 EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8614                                 *sp++ = ins;
8615                         }
8616                         if (class_inits)
8617                                 g_slist_free (class_inits);
8618                         class_inits = NULL;
8619                 } else {
8620                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != cfg->cbb)) {
8621                                 link_bblock (cfg, cfg->cbb, tblock);
8622                                 if (sp != stack_start) {
8623                                         handle_stack_args (cfg, stack_start, sp - stack_start);
8624                                         sp = stack_start;
8625                                         CHECK_UNVERIFIABLE (cfg);
8626                                 }
8627                                 cfg->cbb->next_bb = tblock;
8628                                 cfg->cbb = tblock;
8629                                 for (i = 0; i < cfg->cbb->in_scount; ++i) {
8630                                         if (cfg->verbose_level > 3)
8631                                                 printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8632                                         EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8633                                         *sp++ = ins;
8634                                 }
8635                                 g_slist_free (class_inits);
8636                                 class_inits = NULL;
8637                         }
8638                 }
8639
8640                 if (skip_dead_blocks) {
8641                         int ip_offset = ip - header->code;
8642
8643                         if (ip_offset == bb->end)
8644                                 bb = bb->next;
8645
8646                         if (bb->dead) {
8647                                 int op_size = mono_opcode_size (ip, end);
8648                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
8649
8650                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
8651
8652                                 if (ip_offset + op_size == bb->end) {
8653                                         MONO_INST_NEW (cfg, ins, OP_NOP);
8654                                         MONO_ADD_INS (cfg->cbb, ins);
8655                                         start_new_bblock = 1;
8656                                 }
8657
8658                                 ip += op_size;
8659                                 continue;
8660                         }
8661                 }
8662                 /*
8663                  * Sequence points are points where the debugger can place a breakpoint.
8664                  * Currently, we generate these automatically at points where the IL
8665                  * stack is empty.
8666                  */
8667                 if (seq_points && ((!sym_seq_points && (sp == stack_start)) || (sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code)))) {
8668                         /*
8669                          * Make methods interruptable at the beginning, and at the targets of
8670                          * backward branches.
8671                          * Also, do this at the start of every bblock in methods with clauses too,
8672                          * to be able to handle instructions with inprecise control flow like
8673                          * throw/endfinally.
8674                          * Backward branches are handled at the end of method-to-ir ().
8675                          */
8676                         gboolean intr_loc = ip == header->code || (!cfg->cbb->last_ins && cfg->header->num_clauses);
8677                         gboolean sym_seq_point = sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code);
8678
8679                         /* Avoid sequence points on empty IL like .volatile */
8680                         // FIXME: Enable this
8681                         //if (!(cfg->cbb->last_ins && cfg->cbb->last_ins->opcode == OP_SEQ_POINT)) {
8682                         NEW_SEQ_POINT (cfg, ins, ip - header->code, intr_loc);
8683                         if ((sp != stack_start) && !sym_seq_point)
8684                                 ins->flags |= MONO_INST_NONEMPTY_STACK;
8685                         MONO_ADD_INS (cfg->cbb, ins);
8686
8687                         if (sym_seq_points)
8688                                 mono_bitset_set_fast (seq_point_set_locs, ip - header->code);
8689                 }
8690
8691                 cfg->cbb->real_offset = cfg->real_offset;
8692
8693                 if ((cfg->method == method) && cfg->coverage_info) {
8694                         guint32 cil_offset = ip - header->code;
8695                         cfg->coverage_info->data [cil_offset].cil_code = ip;
8696
8697                         /* TODO: Use an increment here */
8698 #if defined(TARGET_X86)
8699                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
8700                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
8701                         ins->inst_imm = 1;
8702                         MONO_ADD_INS (cfg->cbb, ins);
8703 #else
8704                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
8705                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
8706 #endif
8707                 }
8708
8709                 if (cfg->verbose_level > 3)
8710                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
8711
8712                 switch (*ip) {
8713                 case CEE_NOP:
8714                         if (seq_points && !sym_seq_points && sp != stack_start) {
8715                                 /*
8716                                  * The C# compiler uses these nops to notify the JIT that it should
8717                                  * insert seq points.
8718                                  */
8719                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, FALSE);
8720                                 MONO_ADD_INS (cfg->cbb, ins);
8721                         }
8722                         if (cfg->keep_cil_nops)
8723                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
8724                         else
8725                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8726                         ip++;
8727                         MONO_ADD_INS (cfg->cbb, ins);
8728                         break;
8729                 case CEE_BREAK:
8730                         if (should_insert_brekpoint (cfg->method)) {
8731                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
8732                         } else {
8733                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8734                         }
8735                         ip++;
8736                         MONO_ADD_INS (cfg->cbb, ins);
8737                         break;
8738                 case CEE_LDARG_0:
8739                 case CEE_LDARG_1:
8740                 case CEE_LDARG_2:
8741                 case CEE_LDARG_3:
8742                         CHECK_STACK_OVF (1);
8743                         n = (*ip)-CEE_LDARG_0;
8744                         CHECK_ARG (n);
8745                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8746                         ip++;
8747                         *sp++ = ins;
8748                         break;
8749                 case CEE_LDLOC_0:
8750                 case CEE_LDLOC_1:
8751                 case CEE_LDLOC_2:
8752                 case CEE_LDLOC_3:
8753                         CHECK_STACK_OVF (1);
8754                         n = (*ip)-CEE_LDLOC_0;
8755                         CHECK_LOCAL (n);
8756                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8757                         ip++;
8758                         *sp++ = ins;
8759                         break;
8760                 case CEE_STLOC_0:
8761                 case CEE_STLOC_1:
8762                 case CEE_STLOC_2:
8763                 case CEE_STLOC_3: {
8764                         CHECK_STACK (1);
8765                         n = (*ip)-CEE_STLOC_0;
8766                         CHECK_LOCAL (n);
8767                         --sp;
8768                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
8769                                 UNVERIFIED;
8770                         emit_stloc_ir (cfg, sp, header, n);
8771                         ++ip;
8772                         inline_costs += 1;
8773                         break;
8774                         }
8775                 case CEE_LDARG_S:
8776                         CHECK_OPSIZE (2);
8777                         CHECK_STACK_OVF (1);
8778                         n = ip [1];
8779                         CHECK_ARG (n);
8780                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8781                         *sp++ = ins;
8782                         ip += 2;
8783                         break;
8784                 case CEE_LDARGA_S:
8785                         CHECK_OPSIZE (2);
8786                         CHECK_STACK_OVF (1);
8787                         n = ip [1];
8788                         CHECK_ARG (n);
8789                         NEW_ARGLOADA (cfg, ins, n);
8790                         MONO_ADD_INS (cfg->cbb, ins);
8791                         *sp++ = ins;
8792                         ip += 2;
8793                         break;
8794                 case CEE_STARG_S:
8795                         CHECK_OPSIZE (2);
8796                         CHECK_STACK (1);
8797                         --sp;
8798                         n = ip [1];
8799                         CHECK_ARG (n);
8800                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
8801                                 UNVERIFIED;
8802                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
8803                         ip += 2;
8804                         break;
8805                 case CEE_LDLOC_S:
8806                         CHECK_OPSIZE (2);
8807                         CHECK_STACK_OVF (1);
8808                         n = ip [1];
8809                         CHECK_LOCAL (n);
8810                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8811                         *sp++ = ins;
8812                         ip += 2;
8813                         break;
8814                 case CEE_LDLOCA_S: {
8815                         unsigned char *tmp_ip;
8816                         CHECK_OPSIZE (2);
8817                         CHECK_STACK_OVF (1);
8818                         CHECK_LOCAL (ip [1]);
8819
8820                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
8821                                 ip = tmp_ip;
8822                                 inline_costs += 1;
8823                                 break;
8824                         }
8825
8826                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
8827                         *sp++ = ins;
8828                         ip += 2;
8829                         break;
8830                 }
8831                 case CEE_STLOC_S:
8832                         CHECK_OPSIZE (2);
8833                         CHECK_STACK (1);
8834                         --sp;
8835                         CHECK_LOCAL (ip [1]);
8836                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
8837                                 UNVERIFIED;
8838                         emit_stloc_ir (cfg, sp, header, ip [1]);
8839                         ip += 2;
8840                         inline_costs += 1;
8841                         break;
8842                 case CEE_LDNULL:
8843                         CHECK_STACK_OVF (1);
8844                         EMIT_NEW_PCONST (cfg, ins, NULL);
8845                         ins->type = STACK_OBJ;
8846                         ++ip;
8847                         *sp++ = ins;
8848                         break;
8849                 case CEE_LDC_I4_M1:
8850                         CHECK_STACK_OVF (1);
8851                         EMIT_NEW_ICONST (cfg, ins, -1);
8852                         ++ip;
8853                         *sp++ = ins;
8854                         break;
8855                 case CEE_LDC_I4_0:
8856                 case CEE_LDC_I4_1:
8857                 case CEE_LDC_I4_2:
8858                 case CEE_LDC_I4_3:
8859                 case CEE_LDC_I4_4:
8860                 case CEE_LDC_I4_5:
8861                 case CEE_LDC_I4_6:
8862                 case CEE_LDC_I4_7:
8863                 case CEE_LDC_I4_8:
8864                         CHECK_STACK_OVF (1);
8865                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
8866                         ++ip;
8867                         *sp++ = ins;
8868                         break;
8869                 case CEE_LDC_I4_S:
8870                         CHECK_OPSIZE (2);
8871                         CHECK_STACK_OVF (1);
8872                         ++ip;
8873                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
8874                         ++ip;
8875                         *sp++ = ins;
8876                         break;
8877                 case CEE_LDC_I4:
8878                         CHECK_OPSIZE (5);
8879                         CHECK_STACK_OVF (1);
8880                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
8881                         ip += 5;
8882                         *sp++ = ins;
8883                         break;
8884                 case CEE_LDC_I8:
8885                         CHECK_OPSIZE (9);
8886                         CHECK_STACK_OVF (1);
8887                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
8888                         ins->type = STACK_I8;
8889                         ins->dreg = alloc_dreg (cfg, STACK_I8);
8890                         ++ip;
8891                         ins->inst_l = (gint64)read64 (ip);
8892                         MONO_ADD_INS (cfg->cbb, ins);
8893                         ip += 8;
8894                         *sp++ = ins;
8895                         break;
8896                 case CEE_LDC_R4: {
8897                         float *f;
8898                         gboolean use_aotconst = FALSE;
8899
8900 #ifdef TARGET_POWERPC
8901                         /* FIXME: Clean this up */
8902                         if (cfg->compile_aot)
8903                                 use_aotconst = TRUE;
8904 #endif
8905
8906                         /* FIXME: we should really allocate this only late in the compilation process */
8907                         f = (float *)mono_domain_alloc (cfg->domain, sizeof (float));
8908                         CHECK_OPSIZE (5);
8909                         CHECK_STACK_OVF (1);
8910
8911                         if (use_aotconst) {
8912                                 MonoInst *cons;
8913                                 int dreg;
8914
8915                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
8916
8917                                 dreg = alloc_freg (cfg);
8918                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
8919                                 ins->type = cfg->r4_stack_type;
8920                         } else {
8921                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
8922                                 ins->type = cfg->r4_stack_type;
8923                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8924                                 ins->inst_p0 = f;
8925                                 MONO_ADD_INS (cfg->cbb, ins);
8926                         }
8927                         ++ip;
8928                         readr4 (ip, f);
8929                         ip += 4;
8930                         *sp++ = ins;                    
8931                         break;
8932                 }
8933                 case CEE_LDC_R8: {
8934                         double *d;
8935                         gboolean use_aotconst = FALSE;
8936
8937 #ifdef TARGET_POWERPC
8938                         /* FIXME: Clean this up */
8939                         if (cfg->compile_aot)
8940                                 use_aotconst = TRUE;
8941 #endif
8942
8943                         /* FIXME: we should really allocate this only late in the compilation process */
8944                         d = (double *)mono_domain_alloc (cfg->domain, sizeof (double));
8945                         CHECK_OPSIZE (9);
8946                         CHECK_STACK_OVF (1);
8947
8948                         if (use_aotconst) {
8949                                 MonoInst *cons;
8950                                 int dreg;
8951
8952                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
8953
8954                                 dreg = alloc_freg (cfg);
8955                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
8956                                 ins->type = STACK_R8;
8957                         } else {
8958                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
8959                                 ins->type = STACK_R8;
8960                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8961                                 ins->inst_p0 = d;
8962                                 MONO_ADD_INS (cfg->cbb, ins);
8963                         }
8964                         ++ip;
8965                         readr8 (ip, d);
8966                         ip += 8;
8967                         *sp++ = ins;
8968                         break;
8969                 }
8970                 case CEE_DUP: {
8971                         MonoInst *temp, *store;
8972                         CHECK_STACK (1);
8973                         CHECK_STACK_OVF (1);
8974                         sp--;
8975                         ins = *sp;
8976
8977                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
8978                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
8979
8980                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8981                         *sp++ = ins;
8982
8983                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8984                         *sp++ = ins;
8985
8986                         ++ip;
8987                         inline_costs += 2;
8988                         break;
8989                 }
8990                 case CEE_POP:
8991                         CHECK_STACK (1);
8992                         ip++;
8993                         --sp;
8994
8995 #ifdef TARGET_X86
8996                         if (sp [0]->type == STACK_R8)
8997                                 /* we need to pop the value from the x86 FP stack */
8998                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
8999 #endif
9000                         break;
9001                 case CEE_JMP: {
9002                         MonoCallInst *call;
9003                         MonoMethodSignature *fsig;
9004                         int i, n;
9005
9006                         INLINE_FAILURE ("jmp");
9007                         GSHAREDVT_FAILURE (*ip);
9008
9009                         CHECK_OPSIZE (5);
9010                         if (stack_start != sp)
9011                                 UNVERIFIED;
9012                         token = read32 (ip + 1);
9013                         /* FIXME: check the signature matches */
9014                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
9015                         CHECK_CFG_ERROR;
9016  
9017                         if (cfg->gshared && mono_method_check_context_used (cmethod))
9018                                 GENERIC_SHARING_FAILURE (CEE_JMP);
9019
9020                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
9021
9022                         fsig = mono_method_signature (cmethod);
9023                         n = fsig->param_count + fsig->hasthis;
9024                         if (cfg->llvm_only) {
9025                                 MonoInst **args;
9026
9027                                 args = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
9028                                 for (i = 0; i < n; ++i)
9029                                         EMIT_NEW_ARGLOAD (cfg, args [i], i);
9030                                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, TRUE, args, NULL, NULL, NULL);
9031                                 /*
9032                                  * The code in mono-basic-block.c treats the rest of the code as dead, but we
9033                                  * have to emit a normal return since llvm expects it.
9034                                  */
9035                                 if (cfg->ret)
9036                                         emit_setret (cfg, ins);
9037                                 MONO_INST_NEW (cfg, ins, OP_BR);
9038                                 ins->inst_target_bb = end_bblock;
9039                                 MONO_ADD_INS (cfg->cbb, ins);
9040                                 link_bblock (cfg, cfg->cbb, end_bblock);
9041                                 ip += 5;
9042                                 break;
9043                         } else if (cfg->backend->have_op_tail_call) {
9044                                 /* Handle tail calls similarly to calls */
9045                                 DISABLE_AOT (cfg);
9046
9047                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
9048                                 call->method = cmethod;
9049                                 call->tail_call = TRUE;
9050                                 call->signature = mono_method_signature (cmethod);
9051                                 call->args = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
9052                                 call->inst.inst_p0 = cmethod;
9053                                 for (i = 0; i < n; ++i)
9054                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
9055
9056                                 mono_arch_emit_call (cfg, call);
9057                                 cfg->param_area = MAX(cfg->param_area, call->stack_usage);
9058                                 MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
9059                         } else {
9060                                 for (i = 0; i < num_args; ++i)
9061                                         /* Prevent arguments from being optimized away */
9062                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
9063
9064                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9065                                 ins = (MonoInst*)call;
9066                                 ins->inst_p0 = cmethod;
9067                                 MONO_ADD_INS (cfg->cbb, ins);
9068                         }
9069
9070                         ip += 5;
9071                         start_new_bblock = 1;
9072                         break;
9073                 }
9074                 case CEE_CALLI: {
9075                         MonoInst *addr;
9076                         MonoMethodSignature *fsig;
9077
9078                         CHECK_OPSIZE (5);
9079                         token = read32 (ip + 1);
9080
9081                         ins = NULL;
9082
9083                         //GSHAREDVT_FAILURE (*ip);
9084                         cmethod = NULL;
9085                         CHECK_STACK (1);
9086                         --sp;
9087                         addr = *sp;
9088                         fsig = mini_get_signature (method, token, generic_context);
9089
9090                         if (method->dynamic && fsig->pinvoke) {
9091                                 MonoInst *args [3];
9092
9093                                 /*
9094                                  * This is a call through a function pointer using a pinvoke
9095                                  * signature. Have to create a wrapper and call that instead.
9096                                  * FIXME: This is very slow, need to create a wrapper at JIT time
9097                                  * instead based on the signature.
9098                                  */
9099                                 EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
9100                                 EMIT_NEW_PCONST (cfg, args [1], fsig);
9101                                 args [2] = addr;
9102                                 addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
9103                         }
9104
9105                         n = fsig->param_count + fsig->hasthis;
9106
9107                         CHECK_STACK (n);
9108
9109                         //g_assert (!virtual_ || fsig->hasthis);
9110
9111                         sp -= n;
9112
9113                         inline_costs += 10 * num_calls++;
9114
9115                         /*
9116                          * Making generic calls out of gsharedvt methods.
9117                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9118                          * patching gshared method addresses into a gsharedvt method.
9119                          */
9120                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
9121                                 /*
9122                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
9123                                  */
9124                                 MonoInst *callee = addr;
9125
9126                                 if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
9127                                         /* Not tested */
9128                                         GSHAREDVT_FAILURE (*ip);
9129
9130                                 if (cfg->llvm_only)
9131                                         // FIXME:
9132                                         GSHAREDVT_FAILURE (*ip);
9133
9134                                 addr = emit_get_rgctx_sig (cfg, context_used,
9135                                                                                           fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
9136                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
9137                                 goto calli_end;
9138                         }
9139
9140                         /* Prevent inlining of methods with indirect calls */
9141                         INLINE_FAILURE ("indirect call");
9142
9143                         if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
9144                                 MonoJumpInfoType info_type;
9145                                 gpointer info_data;
9146
9147                                 /*
9148                                  * Instead of emitting an indirect call, emit a direct call
9149                                  * with the contents of the aotconst as the patch info.
9150                                  */
9151                                 if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
9152                                         info_type = (MonoJumpInfoType)addr->inst_c1;
9153                                         info_data = addr->inst_p0;
9154                                 } else {
9155                                         info_type = (MonoJumpInfoType)addr->inst_right->inst_c1;
9156                                         info_data = addr->inst_right->inst_left;
9157                                 }
9158
9159                                 if (info_type == MONO_PATCH_INFO_ICALL_ADDR) {
9160                                         ins = (MonoInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_ICALL_ADDR_CALL, info_data, fsig, sp);
9161                                         NULLIFY_INS (addr);
9162                                         goto calli_end;
9163                                 } else if (info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
9164                                         ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
9165                                         NULLIFY_INS (addr);
9166                                         goto calli_end;
9167                                 }
9168                         }
9169                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9170
9171                         calli_end:
9172
9173                         /* End of call, INS should contain the result of the call, if any */
9174
9175                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9176                                 g_assert (ins);
9177                                 *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
9178                         }
9179
9180                         CHECK_CFG_EXCEPTION;
9181
9182                         ip += 5;
9183                         ins_flag = 0;
9184                         constrained_class = NULL;
9185                         break;
9186                 }
9187                 case CEE_CALL:
9188                 case CEE_CALLVIRT: {
9189                         MonoInst *addr = NULL;
9190                         MonoMethodSignature *fsig = NULL;
9191                         int array_rank = 0;
9192                         int virtual_ = *ip == CEE_CALLVIRT;
9193                         gboolean pass_imt_from_rgctx = FALSE;
9194                         MonoInst *imt_arg = NULL;
9195                         MonoInst *keep_this_alive = NULL;
9196                         gboolean pass_vtable = FALSE;
9197                         gboolean pass_mrgctx = FALSE;
9198                         MonoInst *vtable_arg = NULL;
9199                         gboolean check_this = FALSE;
9200                         gboolean supported_tail_call = FALSE;
9201                         gboolean tail_call = FALSE;
9202                         gboolean need_seq_point = FALSE;
9203                         guint32 call_opcode = *ip;
9204                         gboolean emit_widen = TRUE;
9205                         gboolean push_res = TRUE;
9206                         gboolean skip_ret = FALSE;
9207                         gboolean delegate_invoke = FALSE;
9208                         gboolean direct_icall = FALSE;
9209                         gboolean constrained_partial_call = FALSE;
9210                         MonoMethod *cil_method;
9211
9212                         CHECK_OPSIZE (5);
9213                         token = read32 (ip + 1);
9214
9215                         ins = NULL;
9216
9217                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
9218                         CHECK_CFG_ERROR;
9219
9220                         cil_method = cmethod;
9221                                 
9222                         if (constrained_class) {
9223                                 if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
9224                                         if (!mini_is_gsharedvt_klass (constrained_class)) {
9225                                                 g_assert (!cmethod->klass->valuetype);
9226                                                 if (!mini_type_is_reference (&constrained_class->byval_arg))
9227                                                         constrained_partial_call = TRUE;
9228                                         }
9229                                 }
9230
9231                                 if (method->wrapper_type != MONO_WRAPPER_NONE) {
9232                                         if (cfg->verbose_level > 2)
9233                                                 printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_class));
9234                                         if (!((constrained_class->byval_arg.type == MONO_TYPE_VAR ||
9235                                                    constrained_class->byval_arg.type == MONO_TYPE_MVAR) &&
9236                                                   cfg->gshared)) {
9237                                                 cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_class, generic_context, &cfg->error);
9238                                                 CHECK_CFG_ERROR;
9239                                         }
9240                                 } else {
9241                                         if (cfg->verbose_level > 2)
9242                                                 printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_class));
9243
9244                                         if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
9245                                                 /* 
9246                                                  * This is needed since get_method_constrained can't find 
9247                                                  * the method in klass representing a type var.
9248                                                  * The type var is guaranteed to be a reference type in this
9249                                                  * case.
9250                                                  */
9251                                                 if (!mini_is_gsharedvt_klass (constrained_class))
9252                                                         g_assert (!cmethod->klass->valuetype);
9253                                         } else {
9254                                                 cmethod = mono_get_method_constrained_checked (image, token, constrained_class, generic_context, &cil_method, &cfg->error);
9255                                                 CHECK_CFG_ERROR;
9256                                         }
9257                                 }
9258                         }
9259                                         
9260                         if (!dont_verify && !cfg->skip_visibility) {
9261                                 MonoMethod *target_method = cil_method;
9262                                 if (method->is_inflated) {
9263                                         target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context), &cfg->error);
9264                                         CHECK_CFG_ERROR;
9265                                 }
9266                                 if (!mono_method_can_access_method (method_definition, target_method) &&
9267                                         !mono_method_can_access_method (method, cil_method))
9268                                         METHOD_ACCESS_FAILURE (method, cil_method);
9269                         }
9270
9271                         if (mono_security_core_clr_enabled ())
9272                                 ensure_method_is_allowed_to_call_method (cfg, method, cil_method);
9273
9274                         if (!virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
9275                                 /* MS.NET seems to silently convert this to a callvirt */
9276                                 virtual_ = 1;
9277
9278                         {
9279                                 /*
9280                                  * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
9281                                  * converts to a callvirt.
9282                                  *
9283                                  * tests/bug-515884.il is an example of this behavior
9284                                  */
9285                                 const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
9286                                 const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
9287                                 if (!virtual_ && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
9288                                         virtual_ = 1;
9289                         }
9290
9291                         if (!cmethod->klass->inited)
9292                                 if (!mono_class_init (cmethod->klass))
9293                                         TYPE_LOAD_ERROR (cmethod->klass);
9294
9295                         fsig = mono_method_signature (cmethod);
9296                         if (!fsig)
9297                                 LOAD_ERROR;
9298                         if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
9299                                 mini_class_is_system_array (cmethod->klass)) {
9300                                 array_rank = cmethod->klass->rank;
9301                         } else if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && icall_is_direct_callable (cfg, cmethod)) {
9302                                 direct_icall = TRUE;
9303                         } else if (fsig->pinvoke) {
9304                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
9305                                 fsig = mono_method_signature (wrapper);
9306                         } else if (constrained_class) {
9307                         } else {
9308                                 fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
9309                                 CHECK_CFG_ERROR;
9310                         }
9311
9312                         if (cfg->llvm_only && !cfg->method->wrapper_type)
9313                                 cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, fsig);
9314
9315                         /* See code below */
9316                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
9317                                 MonoBasicBlock *tbb;
9318
9319                                 GET_BBLOCK (cfg, tbb, ip + 5);
9320                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
9321                                         /*
9322                                          * We want to extend the try block to cover the call, but we can't do it if the
9323                                          * call is made directly since its followed by an exception check.
9324                                          */
9325                                         direct_icall = FALSE;
9326                                 }
9327                         }
9328
9329                         mono_save_token_info (cfg, image, token, cil_method);
9330
9331                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip + 5 - header->code)))
9332                                 need_seq_point = TRUE;
9333
9334                         /* Don't support calls made using type arguments for now */
9335                         /*
9336                           if (cfg->gsharedvt) {
9337                           if (mini_is_gsharedvt_signature (fsig))
9338                           GSHAREDVT_FAILURE (*ip);
9339                           }
9340                         */
9341
9342                         if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
9343                                 g_assert_not_reached ();
9344
9345                         n = fsig->param_count + fsig->hasthis;
9346
9347                         if (!cfg->gshared && cmethod->klass->generic_container)
9348                                 UNVERIFIED;
9349
9350                         if (!cfg->gshared)
9351                                 g_assert (!mono_method_check_context_used (cmethod));
9352
9353                         CHECK_STACK (n);
9354
9355                         //g_assert (!virtual_ || fsig->hasthis);
9356
9357                         sp -= n;
9358
9359                         /*
9360                          * We have the `constrained.' prefix opcode.
9361                          */
9362                         if (constrained_class) {
9363                                 if (mini_is_gsharedvt_klass (constrained_class)) {
9364                                         if ((cmethod->klass != mono_defaults.object_class) && constrained_class->valuetype && cmethod->klass->valuetype) {
9365                                                 /* The 'Own method' case below */
9366                                         } else if (cmethod->klass->image != mono_defaults.corlib && !(cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !cmethod->klass->valuetype) {
9367                                                 /* 'The type parameter is instantiated as a reference type' case below. */
9368                                         } else {
9369                                                 ins = handle_constrained_gsharedvt_call (cfg, cmethod, fsig, sp, constrained_class, &emit_widen);
9370                                                 CHECK_CFG_EXCEPTION;
9371                                                 g_assert (ins);
9372                                                 goto call_end;
9373                                         }
9374                                 }
9375
9376                                 if (constrained_partial_call) {
9377                                         gboolean need_box = TRUE;
9378
9379                                         /*
9380                                          * The receiver is a valuetype, but the exact type is not known at compile time. This means the
9381                                          * called method is not known at compile time either. The called method could end up being
9382                                          * one of the methods on the parent classes (object/valuetype/enum), in which case we need
9383                                          * to box the receiver.
9384                                          * A simple solution would be to box always and make a normal virtual call, but that would
9385                                          * be bad performance wise.
9386                                          */
9387                                         if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE && cmethod->klass->generic_class) {
9388                                                 /*
9389                                                  * The parent classes implement no generic interfaces, so the called method will be a vtype method, so no boxing neccessary.
9390                                                  */
9391                                                 need_box = FALSE;
9392                                         }
9393
9394                                         if (!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
9395                                                 /* The called method is not virtual, i.e. Object:GetType (), the receiver is a vtype, has to box */
9396                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9397                                                 ins->klass = constrained_class;
9398                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9399                                                 CHECK_CFG_EXCEPTION;
9400                                         } else if (need_box) {
9401                                                 MonoInst *box_type;
9402                                                 MonoBasicBlock *is_ref_bb, *end_bb;
9403                                                 MonoInst *nonbox_call;
9404
9405                                                 /*
9406                                                  * Determine at runtime whenever the called method is defined on object/valuetype/enum, and emit a boxing call
9407                                                  * if needed.
9408                                                  * FIXME: It is possible to inline the called method in a lot of cases, i.e. for T_INT,
9409                                                  * the no-box case goes to a method in Int32, while the box case goes to a method in Enum.
9410                                                  */
9411                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
9412
9413                                                 NEW_BBLOCK (cfg, is_ref_bb);
9414                                                 NEW_BBLOCK (cfg, end_bb);
9415
9416                                                 box_type = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE);
9417                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, box_type->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
9418                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
9419
9420                                                 /* Non-ref case */
9421                                                 nonbox_call = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9422
9423                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9424
9425                                                 /* Ref case */
9426                                                 MONO_START_BB (cfg, is_ref_bb);
9427                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9428                                                 ins->klass = constrained_class;
9429                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9430                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9431
9432                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9433
9434                                                 MONO_START_BB (cfg, end_bb);
9435                                                 cfg->cbb = end_bb;
9436
9437                                                 nonbox_call->dreg = ins->dreg;
9438                                                 goto call_end;
9439                                         } else {
9440                                                 g_assert (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
9441                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
9442                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9443                                                 goto call_end;
9444                                         }
9445                                 } else if (constrained_class->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
9446                                         /*
9447                                          * The type parameter is instantiated as a valuetype,
9448                                          * but that type doesn't override the method we're
9449                                          * calling, so we need to box `this'.
9450                                          */
9451                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9452                                         ins->klass = constrained_class;
9453                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9454                                         CHECK_CFG_EXCEPTION;
9455                                 } else if (!constrained_class->valuetype) {
9456                                         int dreg = alloc_ireg_ref (cfg);
9457
9458                                         /*
9459                                          * The type parameter is instantiated as a reference
9460                                          * type.  We have a managed pointer on the stack, so
9461                                          * we need to dereference it here.
9462                                          */
9463                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
9464                                         ins->type = STACK_OBJ;
9465                                         sp [0] = ins;
9466                                 } else {
9467                                         if (cmethod->klass->valuetype) {
9468                                                 /* Own method */
9469                                         } else {
9470                                                 /* Interface method */
9471                                                 int ioffset, slot;
9472
9473                                                 mono_class_setup_vtable (constrained_class);
9474                                                 CHECK_TYPELOAD (constrained_class);
9475                                                 ioffset = mono_class_interface_offset (constrained_class, cmethod->klass);
9476                                                 if (ioffset == -1)
9477                                                         TYPE_LOAD_ERROR (constrained_class);
9478                                                 slot = mono_method_get_vtable_slot (cmethod);
9479                                                 if (slot == -1)
9480                                                         TYPE_LOAD_ERROR (cmethod->klass);
9481                                                 cmethod = constrained_class->vtable [ioffset + slot];
9482
9483                                                 if (cmethod->klass == mono_defaults.enum_class) {
9484                                                         /* Enum implements some interfaces, so treat this as the first case */
9485                                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9486                                                         ins->klass = constrained_class;
9487                                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9488                                                         CHECK_CFG_EXCEPTION;
9489                                                 }
9490                                         }
9491                                         virtual_ = 0;
9492                                 }
9493                                 constrained_class = NULL;
9494                         }
9495
9496                         if (check_call_signature (cfg, fsig, sp))
9497                                 UNVERIFIED;
9498
9499                         if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
9500                                 delegate_invoke = TRUE;
9501
9502                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
9503                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9504                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9505                                         emit_widen = FALSE;
9506                                 }
9507
9508                                 goto call_end;
9509                         }
9510
9511                         /* 
9512                          * If the callee is a shared method, then its static cctor
9513                          * might not get called after the call was patched.
9514                          */
9515                         if (cfg->gshared && cmethod->klass != method->klass && cmethod->klass->generic_class && mono_method_is_generic_sharable (cmethod, TRUE) && mono_class_needs_cctor_run (cmethod->klass, method)) {
9516                                 emit_class_init (cfg, cmethod->klass);
9517                                 CHECK_TYPELOAD (cmethod->klass);
9518                         }
9519
9520                         check_method_sharing (cfg, cmethod, &pass_vtable, &pass_mrgctx);
9521
9522                         if (cfg->gshared) {
9523                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
9524
9525                                 context_used = mini_method_check_context_used (cfg, cmethod);
9526
9527                                 if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9528                                         /* Generic method interface
9529                                            calls are resolved via a
9530                                            helper function and don't
9531                                            need an imt. */
9532                                         if (!cmethod_context || !cmethod_context->method_inst)
9533                                                 pass_imt_from_rgctx = TRUE;
9534                                 }
9535
9536                                 /*
9537                                  * If a shared method calls another
9538                                  * shared method then the caller must
9539                                  * have a generic sharing context
9540                                  * because the magic trampoline
9541                                  * requires it.  FIXME: We shouldn't
9542                                  * have to force the vtable/mrgctx
9543                                  * variable here.  Instead there
9544                                  * should be a flag in the cfg to
9545                                  * request a generic sharing context.
9546                                  */
9547                                 if (context_used &&
9548                                                 ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
9549                                         mono_get_vtable_var (cfg);
9550                         }
9551
9552                         if (pass_vtable) {
9553                                 if (context_used) {
9554                                         vtable_arg = emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
9555                                 } else {
9556                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
9557
9558                                         CHECK_TYPELOAD (cmethod->klass);
9559                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
9560                                 }
9561                         }
9562
9563                         if (pass_mrgctx) {
9564                                 g_assert (!vtable_arg);
9565
9566                                 if (!cfg->compile_aot) {
9567                                         /* 
9568                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
9569                                          * for type load errors before.
9570                                          */
9571                                         mono_class_setup_vtable (cmethod->klass);
9572                                         CHECK_TYPELOAD (cmethod->klass);
9573                                 }
9574
9575                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
9576
9577                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
9578                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
9579                                          MONO_METHOD_IS_FINAL (cmethod)) &&
9580                                         !mono_class_is_marshalbyref (cmethod->klass)) {
9581                                         if (virtual_)
9582                                                 check_this = TRUE;
9583                                         virtual_ = 0;
9584                                 }
9585                         }
9586
9587                         if (pass_imt_from_rgctx) {
9588                                 g_assert (!pass_vtable);
9589
9590                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9591                                         cmethod, MONO_RGCTX_INFO_METHOD);
9592                         }
9593
9594                         if (check_this)
9595                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9596
9597                         /* Calling virtual generic methods */
9598                         if (virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) &&
9599                             !(MONO_METHOD_IS_FINAL (cmethod) && 
9600                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
9601                             fsig->generic_param_count && 
9602                                 !(cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) &&
9603                                 !cfg->llvm_only) {
9604                                 MonoInst *this_temp, *this_arg_temp, *store;
9605                                 MonoInst *iargs [4];
9606
9607                                 g_assert (fsig->is_inflated);
9608
9609                                 /* Prevent inlining of methods that contain indirect calls */
9610                                 INLINE_FAILURE ("virtual generic call");
9611
9612                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
9613                                         GSHAREDVT_FAILURE (*ip);
9614
9615                                 if (cfg->backend->have_generalized_imt_thunk && cfg->backend->gshared_supported && cmethod->wrapper_type == MONO_WRAPPER_NONE) {
9616                                         g_assert (!imt_arg);
9617                                         if (!context_used)
9618                                                 g_assert (cmethod->is_inflated);
9619                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
9620                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
9621                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, sp [0], imt_arg, NULL);
9622                                 } else {
9623                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
9624                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
9625                                         MONO_ADD_INS (cfg->cbb, store);
9626
9627                                         /* FIXME: This should be a managed pointer */
9628                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
9629
9630                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
9631                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
9632                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
9633                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
9634                                         addr = mono_emit_jit_icall (cfg,
9635                                                                                                 mono_helper_compile_generic_method, iargs);
9636
9637                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
9638
9639                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9640                                 }
9641
9642                                 goto call_end;
9643                         }
9644
9645                         /*
9646                          * Implement a workaround for the inherent races involved in locking:
9647                          * Monitor.Enter ()
9648                          * try {
9649                          * } finally {
9650                          *    Monitor.Exit ()
9651                          * }
9652                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
9653                          * try block, the Exit () won't be executed, see:
9654                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
9655                          * To work around this, we extend such try blocks to include the last x bytes
9656                          * of the Monitor.Enter () call.
9657                          */
9658                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
9659                                 MonoBasicBlock *tbb;
9660
9661                                 GET_BBLOCK (cfg, tbb, ip + 5);
9662                                 /* 
9663                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
9664                                  * from Monitor.Enter like ArgumentNullException.
9665                                  */
9666                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
9667                                         /* Mark this bblock as needing to be extended */
9668                                         tbb->extend_try_block = TRUE;
9669                                 }
9670                         }
9671
9672                         /* Conversion to a JIT intrinsic */
9673                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
9674                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9675                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9676                                         emit_widen = FALSE;
9677                                 }
9678                                 goto call_end;
9679                         }
9680
9681                         /* Inlining */
9682                         if ((cfg->opt & MONO_OPT_INLINE) &&
9683                                 (!virtual_ || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
9684                             mono_method_check_inlining (cfg, cmethod)) {
9685                                 int costs;
9686                                 gboolean always = FALSE;
9687
9688                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
9689                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
9690                                         /* Prevent inlining of methods that call wrappers */
9691                                         INLINE_FAILURE ("wrapper call");
9692                                         cmethod = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
9693                                         always = TRUE;
9694                                 }
9695
9696                                 costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, always);
9697                                 if (costs) {
9698                                         cfg->real_offset += 5;
9699
9700                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9701                                                 /* *sp is already set by inline_method */
9702                                                 sp++;
9703                                                 push_res = FALSE;
9704                                         }
9705
9706                                         inline_costs += costs;
9707
9708                                         goto call_end;
9709                                 }
9710                         }
9711
9712                         /* Tail recursion elimination */
9713                         if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
9714                                 gboolean has_vtargs = FALSE;
9715                                 int i;
9716
9717                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9718                                 INLINE_FAILURE ("tail call");
9719
9720                                 /* keep it simple */
9721                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
9722                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
9723                                                 has_vtargs = TRUE;
9724                                 }
9725
9726                                 if (!has_vtargs) {
9727                                         for (i = 0; i < n; ++i)
9728                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9729                                         MONO_INST_NEW (cfg, ins, OP_BR);
9730                                         MONO_ADD_INS (cfg->cbb, ins);
9731                                         tblock = start_bblock->out_bb [0];
9732                                         link_bblock (cfg, cfg->cbb, tblock);
9733                                         ins->inst_target_bb = tblock;
9734                                         start_new_bblock = 1;
9735
9736                                         /* skip the CEE_RET, too */
9737                                         if (ip_in_bb (cfg, cfg->cbb, ip + 5))
9738                                                 skip_ret = TRUE;
9739                                         push_res = FALSE;
9740                                         goto call_end;
9741                                 }
9742                         }
9743
9744                         inline_costs += 10 * num_calls++;
9745
9746                         /*
9747                          * Making generic calls out of gsharedvt methods.
9748                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9749                          * patching gshared method addresses into a gsharedvt method.
9750                          */
9751                         if (cfg->gsharedvt && (mini_is_gsharedvt_signature (fsig) || cmethod->is_inflated || cmethod->klass->generic_class) &&
9752                                 !(cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY) &&
9753                                 (!(cfg->llvm_only && virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)))) {
9754                                 MonoRgctxInfoType info_type;
9755
9756                                 if (virtual_) {
9757                                         //if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
9758                                                 //GSHAREDVT_FAILURE (*ip);
9759                                         // disable for possible remoting calls
9760                                         if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
9761                                                 GSHAREDVT_FAILURE (*ip);
9762                                         if (fsig->generic_param_count) {
9763                                                 /* virtual generic call */
9764                                                 g_assert (!imt_arg);
9765                                                 /* Same as the virtual generic case above */
9766                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9767                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9768                                                 /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
9769                                                 vtable_arg = NULL;
9770                                         } else if ((cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !imt_arg) {
9771                                                 /* This can happen when we call a fully instantiated iface method */
9772                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9773                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9774                                                 vtable_arg = NULL;
9775                                         }
9776                                 }
9777
9778                                 if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
9779                                         keep_this_alive = sp [0];
9780
9781                                 if (virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
9782                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
9783                                 else
9784                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
9785                                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
9786
9787                                 if (cfg->llvm_only) {
9788                                         // FIXME: Avoid initializing vtable_arg
9789                                         ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
9790                                 } else {
9791                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9792                                 }
9793                                 goto call_end;
9794                         }
9795
9796                         /* Generic sharing */
9797
9798                         /*
9799                          * Use this if the callee is gsharedvt sharable too, since
9800                          * at runtime we might find an instantiation so the call cannot
9801                          * be patched (the 'no_patch' code path in mini-trampolines.c).
9802                          */
9803                         if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
9804                                 (!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
9805                                  !mono_class_generic_sharing_enabled (cmethod->klass)) &&
9806                                 (!virtual_ || MONO_METHOD_IS_FINAL (cmethod) ||
9807                                  !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
9808                                 INLINE_FAILURE ("gshared");
9809
9810                                 g_assert (cfg->gshared && cmethod);
9811                                 g_assert (!addr);
9812
9813                                 /*
9814                                  * We are compiling a call to a
9815                                  * generic method from shared code,
9816                                  * which means that we have to look up
9817                                  * the method in the rgctx and do an
9818                                  * indirect call.
9819                                  */
9820                                 if (fsig->hasthis)
9821                                         MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9822
9823                                 if (cfg->llvm_only) {
9824                                         if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig))
9825                                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER);
9826                                         else
9827                                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9828                                         // FIXME: Avoid initializing imt_arg/vtable_arg
9829                                         ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
9830                                 } else {
9831                                         addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9832                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9833                                 }
9834                                 goto call_end;
9835                         }
9836
9837                         /* Direct calls to icalls */
9838                         if (direct_icall) {
9839                                 MonoMethod *wrapper;
9840                                 int costs;
9841
9842                                 /* Inline the wrapper */
9843                                 wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
9844
9845                                 costs = inline_method (cfg, wrapper, fsig, sp, ip, cfg->real_offset, TRUE);
9846                                 g_assert (costs > 0);
9847                                 cfg->real_offset += 5;
9848
9849                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9850                                         /* *sp is already set by inline_method */
9851                                         sp++;
9852                                         push_res = FALSE;
9853                                 }
9854
9855                                 inline_costs += costs;
9856
9857                                 goto call_end;
9858                         }
9859                                         
9860                         /* Array methods */
9861                         if (array_rank) {
9862                                 MonoInst *addr;
9863
9864                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
9865                                         MonoInst *val = sp [fsig->param_count];
9866
9867                                         if (val->type == STACK_OBJ) {
9868                                                 MonoInst *iargs [2];
9869
9870                                                 iargs [0] = sp [0];
9871                                                 iargs [1] = val;
9872                                                 
9873                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
9874                                         }
9875                                         
9876                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
9877                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
9878                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !(val->opcode == OP_PCONST && val->inst_c0 == 0))
9879                                                 emit_write_barrier (cfg, addr, val);
9880                                         if (cfg->gen_write_barriers && mini_is_gsharedvt_klass (cmethod->klass))
9881                                                 GSHAREDVT_FAILURE (*ip);
9882                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
9883                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9884
9885                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
9886                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
9887                                         if (!cmethod->klass->element_class->valuetype && !readonly)
9888                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
9889                                         CHECK_TYPELOAD (cmethod->klass);
9890                                         
9891                                         readonly = FALSE;
9892                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9893                                         ins = addr;
9894                                 } else {
9895                                         g_assert_not_reached ();
9896                                 }
9897
9898                                 emit_widen = FALSE;
9899                                 goto call_end;
9900                         }
9901
9902                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual_ ? sp [0] : NULL);
9903                         if (ins)
9904                                 goto call_end;
9905
9906                         /* Tail prefix / tail call optimization */
9907
9908                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
9909                         /* FIXME: runtime generic context pointer for jumps? */
9910                         /* FIXME: handle this for generic sharing eventually */
9911                         if ((ins_flag & MONO_INST_TAILCALL) &&
9912                                 !vtable_arg && !cfg->gshared && is_supported_tail_call (cfg, method, cmethod, fsig, call_opcode))
9913                                 supported_tail_call = TRUE;
9914
9915                         if (supported_tail_call) {
9916                                 MonoCallInst *call;
9917
9918                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9919                                 INLINE_FAILURE ("tail call");
9920
9921                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
9922
9923                                 if (cfg->backend->have_op_tail_call) {
9924                                         /* Handle tail calls similarly to normal calls */
9925                                         tail_call = TRUE;
9926                                 } else {
9927                                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
9928
9929                                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9930                                         call->tail_call = TRUE;
9931                                         call->method = cmethod;
9932                                         call->signature = mono_method_signature (cmethod);
9933
9934                                         /*
9935                                          * We implement tail calls by storing the actual arguments into the 
9936                                          * argument variables, then emitting a CEE_JMP.
9937                                          */
9938                                         for (i = 0; i < n; ++i) {
9939                                                 /* Prevent argument from being register allocated */
9940                                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
9941                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9942                                         }
9943                                         ins = (MonoInst*)call;
9944                                         ins->inst_p0 = cmethod;
9945                                         ins->inst_p1 = arg_array [0];
9946                                         MONO_ADD_INS (cfg->cbb, ins);
9947                                         link_bblock (cfg, cfg->cbb, end_bblock);
9948                                         start_new_bblock = 1;
9949
9950                                         // FIXME: Eliminate unreachable epilogs
9951
9952                                         /*
9953                                          * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9954                                          * only reachable from this call.
9955                                          */
9956                                         GET_BBLOCK (cfg, tblock, ip + 5);
9957                                         if (tblock == cfg->cbb || tblock->in_count == 0)
9958                                                 skip_ret = TRUE;
9959                                         push_res = FALSE;
9960
9961                                         goto call_end;
9962                                 }
9963                         }
9964
9965                         /* 
9966                          * Synchronized wrappers.
9967                          * Its hard to determine where to replace a method with its synchronized
9968                          * wrapper without causing an infinite recursion. The current solution is
9969                          * to add the synchronized wrapper in the trampolines, and to
9970                          * change the called method to a dummy wrapper, and resolve that wrapper
9971                          * to the real method in mono_jit_compile_method ().
9972                          */
9973                         if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
9974                                 MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
9975                                 if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
9976                                         cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
9977                         }
9978
9979                         /*
9980                          * Virtual calls in llvm-only mode.
9981                          */
9982                         if (cfg->llvm_only && virtual_ && cmethod && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
9983                                 ins = emit_llvmonly_virtual_call (cfg, cmethod, fsig, context_used, sp);
9984                                 goto call_end;
9985                         }
9986
9987                         /* Common call */
9988                         INLINE_FAILURE ("call");
9989                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual_ ? sp [0] : NULL,
9990                                                                                           imt_arg, vtable_arg);
9991
9992                         if (tail_call && !cfg->llvm_only) {
9993                                 link_bblock (cfg, cfg->cbb, end_bblock);
9994                                 start_new_bblock = 1;
9995
9996                                 // FIXME: Eliminate unreachable epilogs
9997
9998                                 /*
9999                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
10000                                  * only reachable from this call.
10001                                  */
10002                                 GET_BBLOCK (cfg, tblock, ip + 5);
10003                                 if (tblock == cfg->cbb || tblock->in_count == 0)
10004                                         skip_ret = TRUE;
10005                                 push_res = FALSE;
10006                         }
10007
10008                         call_end:
10009
10010                         /* End of call, INS should contain the result of the call, if any */
10011
10012                         if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
10013                                 g_assert (ins);
10014                                 if (emit_widen)
10015                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
10016                                 else
10017                                         *sp++ = ins;
10018                         }
10019
10020                         if (keep_this_alive) {
10021                                 MonoInst *dummy_use;
10022
10023                                 /* See mono_emit_method_call_full () */
10024                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
10025                         }
10026
10027                         CHECK_CFG_EXCEPTION;
10028
10029                         ip += 5;
10030                         if (skip_ret) {
10031                                 g_assert (*ip == CEE_RET);
10032                                 ip += 1;
10033                         }
10034                         ins_flag = 0;
10035                         constrained_class = NULL;
10036                         if (need_seq_point)
10037                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10038                         break;
10039                 }
10040                 case CEE_RET:
10041                         if (cfg->method != method) {
10042                                 /* return from inlined method */
10043                                 /* 
10044                                  * If in_count == 0, that means the ret is unreachable due to
10045                                  * being preceeded by a throw. In that case, inline_method () will
10046                                  * handle setting the return value 
10047                                  * (test case: test_0_inline_throw ()).
10048                                  */
10049                                 if (return_var && cfg->cbb->in_count) {
10050                                         MonoType *ret_type = mono_method_signature (method)->ret;
10051
10052                                         MonoInst *store;
10053                                         CHECK_STACK (1);
10054                                         --sp;
10055
10056                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
10057                                                 UNVERIFIED;
10058
10059                                         //g_assert (returnvar != -1);
10060                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
10061                                         cfg->ret_var_set = TRUE;
10062                                 } 
10063                         } else {
10064                                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
10065
10066                                 if (cfg->lmf_var && cfg->cbb->in_count && !cfg->llvm_only)
10067                                         emit_pop_lmf (cfg);
10068
10069                                 if (cfg->ret) {
10070                                         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (method)->ret);
10071
10072                                         if (seq_points && !sym_seq_points) {
10073                                                 /* 
10074                                                  * Place a seq point here too even through the IL stack is not
10075                                                  * empty, so a step over on
10076                                                  * call <FOO>
10077                                                  * ret
10078                                                  * will work correctly.
10079                                                  */
10080                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
10081                                                 MONO_ADD_INS (cfg->cbb, ins);
10082                                         }
10083
10084                                         g_assert (!return_var);
10085                                         CHECK_STACK (1);
10086                                         --sp;
10087
10088                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
10089                                                 UNVERIFIED;
10090
10091                                         emit_setret (cfg, *sp);
10092                                 }
10093                         }
10094                         if (sp != stack_start)
10095                                 UNVERIFIED;
10096                         MONO_INST_NEW (cfg, ins, OP_BR);
10097                         ip++;
10098                         ins->inst_target_bb = end_bblock;
10099                         MONO_ADD_INS (cfg->cbb, ins);
10100                         link_bblock (cfg, cfg->cbb, end_bblock);
10101                         start_new_bblock = 1;
10102                         break;
10103                 case CEE_BR_S:
10104                         CHECK_OPSIZE (2);
10105                         MONO_INST_NEW (cfg, ins, OP_BR);
10106                         ip++;
10107                         target = ip + 1 + (signed char)(*ip);
10108                         ++ip;
10109                         GET_BBLOCK (cfg, tblock, target);
10110                         link_bblock (cfg, cfg->cbb, tblock);
10111                         ins->inst_target_bb = tblock;
10112                         if (sp != stack_start) {
10113                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10114                                 sp = stack_start;
10115                                 CHECK_UNVERIFIABLE (cfg);
10116                         }
10117                         MONO_ADD_INS (cfg->cbb, ins);
10118                         start_new_bblock = 1;
10119                         inline_costs += BRANCH_COST;
10120                         break;
10121                 case CEE_BEQ_S:
10122                 case CEE_BGE_S:
10123                 case CEE_BGT_S:
10124                 case CEE_BLE_S:
10125                 case CEE_BLT_S:
10126                 case CEE_BNE_UN_S:
10127                 case CEE_BGE_UN_S:
10128                 case CEE_BGT_UN_S:
10129                 case CEE_BLE_UN_S:
10130                 case CEE_BLT_UN_S:
10131                         CHECK_OPSIZE (2);
10132                         CHECK_STACK (2);
10133                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
10134                         ip++;
10135                         target = ip + 1 + *(signed char*)ip;
10136                         ip++;
10137
10138                         ADD_BINCOND (NULL);
10139
10140                         sp = stack_start;
10141                         inline_costs += BRANCH_COST;
10142                         break;
10143                 case CEE_BR:
10144                         CHECK_OPSIZE (5);
10145                         MONO_INST_NEW (cfg, ins, OP_BR);
10146                         ip++;
10147
10148                         target = ip + 4 + (gint32)read32(ip);
10149                         ip += 4;
10150                         GET_BBLOCK (cfg, tblock, target);
10151                         link_bblock (cfg, cfg->cbb, tblock);
10152                         ins->inst_target_bb = tblock;
10153                         if (sp != stack_start) {
10154                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10155                                 sp = stack_start;
10156                                 CHECK_UNVERIFIABLE (cfg);
10157                         }
10158
10159                         MONO_ADD_INS (cfg->cbb, ins);
10160
10161                         start_new_bblock = 1;
10162                         inline_costs += BRANCH_COST;
10163                         break;
10164                 case CEE_BRFALSE_S:
10165                 case CEE_BRTRUE_S:
10166                 case CEE_BRFALSE:
10167                 case CEE_BRTRUE: {
10168                         MonoInst *cmp;
10169                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
10170                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
10171                         guint32 opsize = is_short ? 1 : 4;
10172
10173                         CHECK_OPSIZE (opsize);
10174                         CHECK_STACK (1);
10175                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
10176                                 UNVERIFIED;
10177                         ip ++;
10178                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
10179                         ip += opsize;
10180
10181                         sp--;
10182
10183                         GET_BBLOCK (cfg, tblock, target);
10184                         link_bblock (cfg, cfg->cbb, tblock);
10185                         GET_BBLOCK (cfg, tblock, ip);
10186                         link_bblock (cfg, cfg->cbb, tblock);
10187
10188                         if (sp != stack_start) {
10189                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10190                                 CHECK_UNVERIFIABLE (cfg);
10191                         }
10192
10193                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
10194                         cmp->sreg1 = sp [0]->dreg;
10195                         type_from_op (cfg, cmp, sp [0], NULL);
10196                         CHECK_TYPE (cmp);
10197
10198 #if SIZEOF_REGISTER == 4
10199                         if (cmp->opcode == OP_LCOMPARE_IMM) {
10200                                 /* Convert it to OP_LCOMPARE */
10201                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
10202                                 ins->type = STACK_I8;
10203                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
10204                                 ins->inst_l = 0;
10205                                 MONO_ADD_INS (cfg->cbb, ins);
10206                                 cmp->opcode = OP_LCOMPARE;
10207                                 cmp->sreg2 = ins->dreg;
10208                         }
10209 #endif
10210                         MONO_ADD_INS (cfg->cbb, cmp);
10211
10212                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
10213                         type_from_op (cfg, ins, sp [0], NULL);
10214                         MONO_ADD_INS (cfg->cbb, ins);
10215                         ins->inst_many_bb = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
10216                         GET_BBLOCK (cfg, tblock, target);
10217                         ins->inst_true_bb = tblock;
10218                         GET_BBLOCK (cfg, tblock, ip);
10219                         ins->inst_false_bb = tblock;
10220                         start_new_bblock = 2;
10221
10222                         sp = stack_start;
10223                         inline_costs += BRANCH_COST;
10224                         break;
10225                 }
10226                 case CEE_BEQ:
10227                 case CEE_BGE:
10228                 case CEE_BGT:
10229                 case CEE_BLE:
10230                 case CEE_BLT:
10231                 case CEE_BNE_UN:
10232                 case CEE_BGE_UN:
10233                 case CEE_BGT_UN:
10234                 case CEE_BLE_UN:
10235                 case CEE_BLT_UN:
10236                         CHECK_OPSIZE (5);
10237                         CHECK_STACK (2);
10238                         MONO_INST_NEW (cfg, ins, *ip);
10239                         ip++;
10240                         target = ip + 4 + (gint32)read32(ip);
10241                         ip += 4;
10242
10243                         ADD_BINCOND (NULL);
10244
10245                         sp = stack_start;
10246                         inline_costs += BRANCH_COST;
10247                         break;
10248                 case CEE_SWITCH: {
10249                         MonoInst *src1;
10250                         MonoBasicBlock **targets;
10251                         MonoBasicBlock *default_bblock;
10252                         MonoJumpInfoBBTable *table;
10253                         int offset_reg = alloc_preg (cfg);
10254                         int target_reg = alloc_preg (cfg);
10255                         int table_reg = alloc_preg (cfg);
10256                         int sum_reg = alloc_preg (cfg);
10257                         gboolean use_op_switch;
10258
10259                         CHECK_OPSIZE (5);
10260                         CHECK_STACK (1);
10261                         n = read32 (ip + 1);
10262                         --sp;
10263                         src1 = sp [0];
10264                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
10265                                 UNVERIFIED;
10266
10267                         ip += 5;
10268                         CHECK_OPSIZE (n * sizeof (guint32));
10269                         target = ip + n * sizeof (guint32);
10270
10271                         GET_BBLOCK (cfg, default_bblock, target);
10272                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
10273
10274                         targets = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
10275                         for (i = 0; i < n; ++i) {
10276                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
10277                                 targets [i] = tblock;
10278                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
10279                                 ip += 4;
10280                         }
10281
10282                         if (sp != stack_start) {
10283                                 /* 
10284                                  * Link the current bb with the targets as well, so handle_stack_args
10285                                  * will set their in_stack correctly.
10286                                  */
10287                                 link_bblock (cfg, cfg->cbb, default_bblock);
10288                                 for (i = 0; i < n; ++i)
10289                                         link_bblock (cfg, cfg->cbb, targets [i]);
10290
10291                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10292                                 sp = stack_start;
10293                                 CHECK_UNVERIFIABLE (cfg);
10294
10295                                 /* Undo the links */
10296                                 mono_unlink_bblock (cfg, cfg->cbb, default_bblock);
10297                                 for (i = 0; i < n; ++i)
10298                                         mono_unlink_bblock (cfg, cfg->cbb, targets [i]);
10299                         }
10300
10301                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
10302                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
10303
10304                         for (i = 0; i < n; ++i)
10305                                 link_bblock (cfg, cfg->cbb, targets [i]);
10306
10307                         table = (MonoJumpInfoBBTable *)mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
10308                         table->table = targets;
10309                         table->table_size = n;
10310
10311                         use_op_switch = FALSE;
10312 #ifdef TARGET_ARM
10313                         /* ARM implements SWITCH statements differently */
10314                         /* FIXME: Make it use the generic implementation */
10315                         if (!cfg->compile_aot)
10316                                 use_op_switch = TRUE;
10317 #endif
10318
10319                         if (COMPILE_LLVM (cfg))
10320                                 use_op_switch = TRUE;
10321
10322                         cfg->cbb->has_jump_table = 1;
10323
10324                         if (use_op_switch) {
10325                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
10326                                 ins->sreg1 = src1->dreg;
10327                                 ins->inst_p0 = table;
10328                                 ins->inst_many_bb = targets;
10329                                 ins->klass = (MonoClass *)GUINT_TO_POINTER (n);
10330                                 MONO_ADD_INS (cfg->cbb, ins);
10331                         } else {
10332                                 if (sizeof (gpointer) == 8)
10333                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
10334                                 else
10335                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
10336
10337 #if SIZEOF_REGISTER == 8
10338                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
10339                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
10340 #endif
10341
10342                                 if (cfg->compile_aot) {
10343                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
10344                                 } else {
10345                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
10346                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
10347                                         ins->inst_p0 = table;
10348                                         ins->dreg = table_reg;
10349                                         MONO_ADD_INS (cfg->cbb, ins);
10350                                 }
10351
10352                                 /* FIXME: Use load_memindex */
10353                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
10354                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
10355                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
10356                         }
10357                         start_new_bblock = 1;
10358                         inline_costs += (BRANCH_COST * 2);
10359                         break;
10360                 }
10361                 case CEE_LDIND_I1:
10362                 case CEE_LDIND_U1:
10363                 case CEE_LDIND_I2:
10364                 case CEE_LDIND_U2:
10365                 case CEE_LDIND_I4:
10366                 case CEE_LDIND_U4:
10367                 case CEE_LDIND_I8:
10368                 case CEE_LDIND_I:
10369                 case CEE_LDIND_R4:
10370                 case CEE_LDIND_R8:
10371                 case CEE_LDIND_REF:
10372                         CHECK_STACK (1);
10373                         --sp;
10374
10375                         switch (*ip) {
10376                         case CEE_LDIND_R4:
10377                         case CEE_LDIND_R8:
10378                                 dreg = alloc_freg (cfg);
10379                                 break;
10380                         case CEE_LDIND_I8:
10381                                 dreg = alloc_lreg (cfg);
10382                                 break;
10383                         case CEE_LDIND_REF:
10384                                 dreg = alloc_ireg_ref (cfg);
10385                                 break;
10386                         default:
10387                                 dreg = alloc_preg (cfg);
10388                         }
10389
10390                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
10391                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
10392                         if (*ip == CEE_LDIND_R4)
10393                                 ins->type = cfg->r4_stack_type;
10394                         ins->flags |= ins_flag;
10395                         MONO_ADD_INS (cfg->cbb, ins);
10396                         *sp++ = ins;
10397                         if (ins_flag & MONO_INST_VOLATILE) {
10398                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10399                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10400                         }
10401                         ins_flag = 0;
10402                         ++ip;
10403                         break;
10404                 case CEE_STIND_REF:
10405                 case CEE_STIND_I1:
10406                 case CEE_STIND_I2:
10407                 case CEE_STIND_I4:
10408                 case CEE_STIND_I8:
10409                 case CEE_STIND_R4:
10410                 case CEE_STIND_R8:
10411                 case CEE_STIND_I:
10412                         CHECK_STACK (2);
10413                         sp -= 2;
10414
10415                         if (ins_flag & MONO_INST_VOLATILE) {
10416                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
10417                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
10418                         }
10419
10420                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
10421                         ins->flags |= ins_flag;
10422                         ins_flag = 0;
10423
10424                         MONO_ADD_INS (cfg->cbb, ins);
10425
10426                         if (cfg->gen_write_barriers && *ip == CEE_STIND_REF && method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER && !((sp [1]->opcode == OP_PCONST) && (sp [1]->inst_p0 == 0)))
10427                                 emit_write_barrier (cfg, sp [0], sp [1]);
10428
10429                         inline_costs += 1;
10430                         ++ip;
10431                         break;
10432
10433                 case CEE_MUL:
10434                         CHECK_STACK (2);
10435
10436                         MONO_INST_NEW (cfg, ins, (*ip));
10437                         sp -= 2;
10438                         ins->sreg1 = sp [0]->dreg;
10439                         ins->sreg2 = sp [1]->dreg;
10440                         type_from_op (cfg, ins, sp [0], sp [1]);
10441                         CHECK_TYPE (ins);
10442                         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type);
10443
10444                         /* Use the immediate opcodes if possible */
10445                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
10446                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
10447                                 if (imm_opcode != -1) {
10448                                         ins->opcode = imm_opcode;
10449                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
10450                                         ins->sreg2 = -1;
10451
10452                                         NULLIFY_INS (sp [1]);
10453                                 }
10454                         }
10455
10456                         MONO_ADD_INS ((cfg)->cbb, (ins));
10457
10458                         *sp++ = mono_decompose_opcode (cfg, ins);
10459                         ip++;
10460                         break;
10461                 case CEE_ADD:
10462                 case CEE_SUB:
10463                 case CEE_DIV:
10464                 case CEE_DIV_UN:
10465                 case CEE_REM:
10466                 case CEE_REM_UN:
10467                 case CEE_AND:
10468                 case CEE_OR:
10469                 case CEE_XOR:
10470                 case CEE_SHL:
10471                 case CEE_SHR:
10472                 case CEE_SHR_UN:
10473                         CHECK_STACK (2);
10474
10475                         MONO_INST_NEW (cfg, ins, (*ip));
10476                         sp -= 2;
10477                         ins->sreg1 = sp [0]->dreg;
10478                         ins->sreg2 = sp [1]->dreg;
10479                         type_from_op (cfg, ins, sp [0], sp [1]);
10480                         CHECK_TYPE (ins);
10481                         add_widen_op (cfg, ins, &sp [0], &sp [1]);
10482                         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type);
10483
10484                         /* FIXME: Pass opcode to is_inst_imm */
10485
10486                         /* Use the immediate opcodes if possible */
10487                         if (((sp [1]->opcode == OP_ICONST) || (sp [1]->opcode == OP_I8CONST)) && mono_arch_is_inst_imm (sp [1]->opcode == OP_ICONST ? sp [1]->inst_c0 : sp [1]->inst_l)) {
10488                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
10489                                 if (imm_opcode != -1) {
10490                                         ins->opcode = imm_opcode;
10491                                         if (sp [1]->opcode == OP_I8CONST) {
10492 #if SIZEOF_REGISTER == 8
10493                                                 ins->inst_imm = sp [1]->inst_l;
10494 #else
10495                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
10496                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
10497 #endif
10498                                         }
10499                                         else
10500                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
10501                                         ins->sreg2 = -1;
10502
10503                                         /* Might be followed by an instruction added by add_widen_op */
10504                                         if (sp [1]->next == NULL)
10505                                                 NULLIFY_INS (sp [1]);
10506                                 }
10507                         }
10508                         MONO_ADD_INS ((cfg)->cbb, (ins));
10509
10510                         *sp++ = mono_decompose_opcode (cfg, ins);
10511                         ip++;
10512                         break;
10513                 case CEE_NEG:
10514                 case CEE_NOT:
10515                 case CEE_CONV_I1:
10516                 case CEE_CONV_I2:
10517                 case CEE_CONV_I4:
10518                 case CEE_CONV_R4:
10519                 case CEE_CONV_R8:
10520                 case CEE_CONV_U4:
10521                 case CEE_CONV_I8:
10522                 case CEE_CONV_U8:
10523                 case CEE_CONV_OVF_I8:
10524                 case CEE_CONV_OVF_U8:
10525                 case CEE_CONV_R_UN:
10526                         CHECK_STACK (1);
10527
10528                         /* Special case this earlier so we have long constants in the IR */
10529                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
10530                                 int data = sp [-1]->inst_c0;
10531                                 sp [-1]->opcode = OP_I8CONST;
10532                                 sp [-1]->type = STACK_I8;
10533 #if SIZEOF_REGISTER == 8
10534                                 if ((*ip) == CEE_CONV_U8)
10535                                         sp [-1]->inst_c0 = (guint32)data;
10536                                 else
10537                                         sp [-1]->inst_c0 = data;
10538 #else
10539                                 sp [-1]->inst_ls_word = data;
10540                                 if ((*ip) == CEE_CONV_U8)
10541                                         sp [-1]->inst_ms_word = 0;
10542                                 else
10543                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
10544 #endif
10545                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
10546                         }
10547                         else {
10548                                 ADD_UNOP (*ip);
10549                         }
10550                         ip++;
10551                         break;
10552                 case CEE_CONV_OVF_I4:
10553                 case CEE_CONV_OVF_I1:
10554                 case CEE_CONV_OVF_I2:
10555                 case CEE_CONV_OVF_I:
10556                 case CEE_CONV_OVF_U:
10557                         CHECK_STACK (1);
10558
10559                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10560                                 ADD_UNOP (CEE_CONV_OVF_I8);
10561                                 ADD_UNOP (*ip);
10562                         } else {
10563                                 ADD_UNOP (*ip);
10564                         }
10565                         ip++;
10566                         break;
10567                 case CEE_CONV_OVF_U1:
10568                 case CEE_CONV_OVF_U2:
10569                 case CEE_CONV_OVF_U4:
10570                         CHECK_STACK (1);
10571
10572                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10573                                 ADD_UNOP (CEE_CONV_OVF_U8);
10574                                 ADD_UNOP (*ip);
10575                         } else {
10576                                 ADD_UNOP (*ip);
10577                         }
10578                         ip++;
10579                         break;
10580                 case CEE_CONV_OVF_I1_UN:
10581                 case CEE_CONV_OVF_I2_UN:
10582                 case CEE_CONV_OVF_I4_UN:
10583                 case CEE_CONV_OVF_I8_UN:
10584                 case CEE_CONV_OVF_U1_UN:
10585                 case CEE_CONV_OVF_U2_UN:
10586                 case CEE_CONV_OVF_U4_UN:
10587                 case CEE_CONV_OVF_U8_UN:
10588                 case CEE_CONV_OVF_I_UN:
10589                 case CEE_CONV_OVF_U_UN:
10590                 case CEE_CONV_U2:
10591                 case CEE_CONV_U1:
10592                 case CEE_CONV_I:
10593                 case CEE_CONV_U:
10594                         CHECK_STACK (1);
10595                         ADD_UNOP (*ip);
10596                         CHECK_CFG_EXCEPTION;
10597                         ip++;
10598                         break;
10599                 case CEE_ADD_OVF:
10600                 case CEE_ADD_OVF_UN:
10601                 case CEE_MUL_OVF:
10602                 case CEE_MUL_OVF_UN:
10603                 case CEE_SUB_OVF:
10604                 case CEE_SUB_OVF_UN:
10605                         CHECK_STACK (2);
10606                         ADD_BINOP (*ip);
10607                         ip++;
10608                         break;
10609                 case CEE_CPOBJ:
10610                         GSHAREDVT_FAILURE (*ip);
10611                         CHECK_OPSIZE (5);
10612                         CHECK_STACK (2);
10613                         token = read32 (ip + 1);
10614                         klass = mini_get_class (method, token, generic_context);
10615                         CHECK_TYPELOAD (klass);
10616                         sp -= 2;
10617                         if (generic_class_is_reference_type (cfg, klass)) {
10618                                 MonoInst *store, *load;
10619                                 int dreg = alloc_ireg_ref (cfg);
10620
10621                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
10622                                 load->flags |= ins_flag;
10623                                 MONO_ADD_INS (cfg->cbb, load);
10624
10625                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
10626                                 store->flags |= ins_flag;
10627                                 MONO_ADD_INS (cfg->cbb, store);
10628
10629                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
10630                                         emit_write_barrier (cfg, sp [0], sp [1]);
10631                         } else {
10632                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10633                         }
10634                         ins_flag = 0;
10635                         ip += 5;
10636                         break;
10637                 case CEE_LDOBJ: {
10638                         int loc_index = -1;
10639                         int stloc_len = 0;
10640
10641                         CHECK_OPSIZE (5);
10642                         CHECK_STACK (1);
10643                         --sp;
10644                         token = read32 (ip + 1);
10645                         klass = mini_get_class (method, token, generic_context);
10646                         CHECK_TYPELOAD (klass);
10647
10648                         /* Optimize the common ldobj+stloc combination */
10649                         switch (ip [5]) {
10650                         case CEE_STLOC_S:
10651                                 loc_index = ip [6];
10652                                 stloc_len = 2;
10653                                 break;
10654                         case CEE_STLOC_0:
10655                         case CEE_STLOC_1:
10656                         case CEE_STLOC_2:
10657                         case CEE_STLOC_3:
10658                                 loc_index = ip [5] - CEE_STLOC_0;
10659                                 stloc_len = 1;
10660                                 break;
10661                         default:
10662                                 break;
10663                         }
10664
10665                         if ((loc_index != -1) && ip_in_bb (cfg, cfg->cbb, ip + 5)) {
10666                                 CHECK_LOCAL (loc_index);
10667
10668                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10669                                 ins->dreg = cfg->locals [loc_index]->dreg;
10670                                 ins->flags |= ins_flag;
10671                                 ip += 5;
10672                                 ip += stloc_len;
10673                                 if (ins_flag & MONO_INST_VOLATILE) {
10674                                         /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10675                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10676                                 }
10677                                 ins_flag = 0;
10678                                 break;
10679                         }
10680
10681                         /* Optimize the ldobj+stobj combination */
10682                         /* The reference case ends up being a load+store anyway */
10683                         /* Skip this if the operation is volatile. */
10684                         if (((ip [5] == CEE_STOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 5) && read32 (ip + 6) == token) && !generic_class_is_reference_type (cfg, klass) && !(ins_flag & MONO_INST_VOLATILE)) {
10685                                 CHECK_STACK (1);
10686
10687                                 sp --;
10688
10689                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10690
10691                                 ip += 5 + 5;
10692                                 ins_flag = 0;
10693                                 break;
10694                         }
10695
10696                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10697                         ins->flags |= ins_flag;
10698                         *sp++ = ins;
10699
10700                         if (ins_flag & MONO_INST_VOLATILE) {
10701                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10702                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10703                         }
10704
10705                         ip += 5;
10706                         ins_flag = 0;
10707                         inline_costs += 1;
10708                         break;
10709                 }
10710                 case CEE_LDSTR:
10711                         CHECK_STACK_OVF (1);
10712                         CHECK_OPSIZE (5);
10713                         n = read32 (ip + 1);
10714
10715                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
10716                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
10717                                 ins->type = STACK_OBJ;
10718                                 *sp = ins;
10719                         }
10720                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
10721                                 MonoInst *iargs [1];
10722                                 char *str = (char *)mono_method_get_wrapper_data (method, n);
10723
10724                                 if (cfg->compile_aot)
10725                                         EMIT_NEW_LDSTRLITCONST (cfg, iargs [0], str);
10726                                 else
10727                                         EMIT_NEW_PCONST (cfg, iargs [0], str);
10728                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
10729                         } else {
10730                                 if (cfg->opt & MONO_OPT_SHARED) {
10731                                         MonoInst *iargs [3];
10732
10733                                         if (cfg->compile_aot) {
10734                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
10735                                         }
10736                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10737                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
10738                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
10739                                         *sp = mono_emit_jit_icall (cfg, mono_ldstr, iargs);
10740                                         mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
10741                                 } else {
10742                                         if (cfg->cbb->out_of_line) {
10743                                                 MonoInst *iargs [2];
10744
10745                                                 if (image == mono_defaults.corlib) {
10746                                                         /* 
10747                                                          * Avoid relocations in AOT and save some space by using a 
10748                                                          * version of helper_ldstr specialized to mscorlib.
10749                                                          */
10750                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
10751                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
10752                                                 } else {
10753                                                         /* Avoid creating the string object */
10754                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
10755                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
10756                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
10757                                                 }
10758                                         } 
10759                                         else
10760                                         if (cfg->compile_aot) {
10761                                                 NEW_LDSTRCONST (cfg, ins, image, n);
10762                                                 *sp = ins;
10763                                                 MONO_ADD_INS (cfg->cbb, ins);
10764                                         } 
10765                                         else {
10766                                                 NEW_PCONST (cfg, ins, NULL);
10767                                                 ins->type = STACK_OBJ;
10768                                                 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
10769                                                 if (!ins->inst_p0)
10770                                                         OUT_OF_MEMORY_FAILURE;
10771
10772                                                 *sp = ins;
10773                                                 MONO_ADD_INS (cfg->cbb, ins);
10774                                         }
10775                                 }
10776                         }
10777
10778                         sp++;
10779                         ip += 5;
10780                         break;
10781                 case CEE_NEWOBJ: {
10782                         MonoInst *iargs [2];
10783                         MonoMethodSignature *fsig;
10784                         MonoInst this_ins;
10785                         MonoInst *alloc;
10786                         MonoInst *vtable_arg = NULL;
10787
10788                         CHECK_OPSIZE (5);
10789                         token = read32 (ip + 1);
10790                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
10791                         CHECK_CFG_ERROR;
10792
10793                         fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
10794                         CHECK_CFG_ERROR;
10795
10796                         mono_save_token_info (cfg, image, token, cmethod);
10797
10798                         if (!mono_class_init (cmethod->klass))
10799                                 TYPE_LOAD_ERROR (cmethod->klass);
10800
10801                         context_used = mini_method_check_context_used (cfg, cmethod);
10802
10803                         if (mono_security_core_clr_enabled ())
10804                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
10805
10806                         if (cfg->gshared && cmethod && cmethod->klass != method->klass && cmethod->klass->generic_class && mono_method_is_generic_sharable (cmethod, TRUE) && mono_class_needs_cctor_run (cmethod->klass, method)) {
10807                                 emit_class_init (cfg, cmethod->klass);
10808                                 CHECK_TYPELOAD (cmethod->klass);
10809                         }
10810
10811                         /*
10812                         if (cfg->gsharedvt) {
10813                                 if (mini_is_gsharedvt_variable_signature (sig))
10814                                         GSHAREDVT_FAILURE (*ip);
10815                         }
10816                         */
10817
10818                         n = fsig->param_count;
10819                         CHECK_STACK (n);
10820
10821                         /* 
10822                          * Generate smaller code for the common newobj <exception> instruction in
10823                          * argument checking code.
10824                          */
10825                         if (cfg->cbb->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
10826                                 is_exception_class (cmethod->klass) && n <= 2 &&
10827                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
10828                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
10829                                 MonoInst *iargs [3];
10830
10831                                 sp -= n;
10832
10833                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
10834                                 switch (n) {
10835                                 case 0:
10836                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
10837                                         break;
10838                                 case 1:
10839                                         iargs [1] = sp [0];
10840                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
10841                                         break;
10842                                 case 2:
10843                                         iargs [1] = sp [0];
10844                                         iargs [2] = sp [1];
10845                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
10846                                         break;
10847                                 default:
10848                                         g_assert_not_reached ();
10849                                 }
10850
10851                                 ip += 5;
10852                                 inline_costs += 5;
10853                                 break;
10854                         }
10855
10856                         /* move the args to allow room for 'this' in the first position */
10857                         while (n--) {
10858                                 --sp;
10859                                 sp [1] = sp [0];
10860                         }
10861
10862                         /* check_call_signature () requires sp[0] to be set */
10863                         this_ins.type = STACK_OBJ;
10864                         sp [0] = &this_ins;
10865                         if (check_call_signature (cfg, fsig, sp))
10866                                 UNVERIFIED;
10867
10868                         iargs [0] = NULL;
10869
10870                         if (mini_class_is_system_array (cmethod->klass)) {
10871                                 *sp = emit_get_rgctx_method (cfg, context_used,
10872                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
10873
10874                                 /* Avoid varargs in the common case */
10875                                 if (fsig->param_count == 1)
10876                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
10877                                 else if (fsig->param_count == 2)
10878                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
10879                                 else if (fsig->param_count == 3)
10880                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
10881                                 else if (fsig->param_count == 4)
10882                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
10883                                 else
10884                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
10885                         } else if (cmethod->string_ctor) {
10886                                 g_assert (!context_used);
10887                                 g_assert (!vtable_arg);
10888                                 /* we simply pass a null pointer */
10889                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
10890                                 /* now call the string ctor */
10891                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
10892                         } else {
10893                                 if (cmethod->klass->valuetype) {
10894                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
10895                                         emit_init_rvar (cfg, iargs [0]->dreg, &cmethod->klass->byval_arg);
10896                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
10897
10898                                         alloc = NULL;
10899
10900                                         /* 
10901                                          * The code generated by mini_emit_virtual_call () expects
10902                                          * iargs [0] to be a boxed instance, but luckily the vcall
10903                                          * will be transformed into a normal call there.
10904                                          */
10905                                 } else if (context_used) {
10906                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
10907                                         *sp = alloc;
10908                                 } else {
10909                                         MonoVTable *vtable = NULL;
10910
10911                                         if (!cfg->compile_aot)
10912                                                 vtable = mono_class_vtable (cfg->domain, cmethod->klass);
10913                                         CHECK_TYPELOAD (cmethod->klass);
10914
10915                                         /*
10916                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
10917                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
10918                                          * As a workaround, we call class cctors before allocating objects.
10919                                          */
10920                                         if (mini_field_access_needs_cctor_run (cfg, method, cmethod->klass, vtable) && !(g_slist_find (class_inits, cmethod->klass))) {
10921                                                 emit_class_init (cfg, cmethod->klass);
10922                                                 if (cfg->verbose_level > 2)
10923                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
10924                                                 class_inits = g_slist_prepend (class_inits, cmethod->klass);
10925                                         }
10926
10927                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
10928                                         *sp = alloc;
10929                                 }
10930                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
10931
10932                                 if (alloc)
10933                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
10934
10935                                 /* Now call the actual ctor */
10936                                 handle_ctor_call (cfg, cmethod, fsig, context_used, sp, ip, &inline_costs);
10937                                 CHECK_CFG_EXCEPTION;
10938                         }
10939
10940                         if (alloc == NULL) {
10941                                 /* Valuetype */
10942                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
10943                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
10944                                 *sp++= ins;
10945                         } else {
10946                                 *sp++ = alloc;
10947                         }
10948                         
10949                         ip += 5;
10950                         inline_costs += 5;
10951                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip - header->code)))
10952                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10953                         break;
10954                 }
10955                 case CEE_CASTCLASS:
10956                         CHECK_STACK (1);
10957                         --sp;
10958                         CHECK_OPSIZE (5);
10959                         token = read32 (ip + 1);
10960                         klass = mini_get_class (method, token, generic_context);
10961                         CHECK_TYPELOAD (klass);
10962                         if (sp [0]->type != STACK_OBJ)
10963                                 UNVERIFIED;
10964
10965                         ins = handle_castclass (cfg, klass, *sp, ip, &inline_costs);
10966                         CHECK_CFG_EXCEPTION;
10967
10968                         *sp ++ = ins;
10969                         ip += 5;
10970                         break;
10971                 case CEE_ISINST: {
10972                         CHECK_STACK (1);
10973                         --sp;
10974                         CHECK_OPSIZE (5);
10975                         token = read32 (ip + 1);
10976                         klass = mini_get_class (method, token, generic_context);
10977                         CHECK_TYPELOAD (klass);
10978                         if (sp [0]->type != STACK_OBJ)
10979                                 UNVERIFIED;
10980  
10981                         context_used = mini_class_check_context_used (cfg, klass);
10982
10983                         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
10984                                 MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
10985                                 MonoInst *args [3];
10986                                 int idx;
10987
10988                                 /* obj */
10989                                 args [0] = *sp;
10990
10991                                 /* klass */
10992                                 EMIT_NEW_CLASSCONST (cfg, args [1], klass);
10993
10994                                 /* inline cache*/
10995                                 idx = get_castclass_cache_idx (cfg);
10996                                 args [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
10997
10998                                 *sp++ = mono_emit_method_call (cfg, mono_isinst, args, NULL);
10999                                 ip += 5;
11000                                 inline_costs += 2;
11001                         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
11002                                 MonoMethod *mono_isinst;
11003                                 MonoInst *iargs [1];
11004                                 int costs;
11005
11006                                 mono_isinst = mono_marshal_get_isinst (klass); 
11007                                 iargs [0] = sp [0];
11008
11009                                 costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), 
11010                                                                            iargs, ip, cfg->real_offset, TRUE);
11011                                 CHECK_CFG_EXCEPTION;
11012                                 g_assert (costs > 0);
11013                                 
11014                                 ip += 5;
11015                                 cfg->real_offset += 5;
11016
11017                                 *sp++= iargs [0];
11018
11019                                 inline_costs += costs;
11020                         }
11021                         else {
11022                                 ins = handle_isinst (cfg, klass, *sp, context_used);
11023                                 CHECK_CFG_EXCEPTION;
11024                                 *sp ++ = ins;
11025                                 ip += 5;
11026                         }
11027                         break;
11028                 }
11029                 case CEE_UNBOX_ANY: {
11030                         MonoInst *res, *addr;
11031
11032                         CHECK_STACK (1);
11033                         --sp;
11034                         CHECK_OPSIZE (5);
11035                         token = read32 (ip + 1);
11036                         klass = mini_get_class (method, token, generic_context);
11037                         CHECK_TYPELOAD (klass);
11038
11039                         mono_save_token_info (cfg, image, token, klass);
11040
11041                         context_used = mini_class_check_context_used (cfg, klass);
11042
11043                         if (mini_is_gsharedvt_klass (klass)) {
11044                                 res = handle_unbox_gsharedvt (cfg, klass, *sp);
11045                                 inline_costs += 2;
11046                         } else if (generic_class_is_reference_type (cfg, klass)) {
11047                                 res = handle_castclass (cfg, klass, *sp, ip, &inline_costs);
11048                                 CHECK_CFG_EXCEPTION;
11049                         } else if (mono_class_is_nullable (klass)) {
11050                                 res = handle_unbox_nullable (cfg, *sp, klass, context_used);
11051                         } else {
11052                                 addr = handle_unbox (cfg, klass, sp, context_used);
11053                                 /* LDOBJ */
11054                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11055                                 res = ins;
11056                                 inline_costs += 2;
11057                         }
11058
11059                         *sp ++ = res;
11060                         ip += 5;
11061                         break;
11062                 }
11063                 case CEE_BOX: {
11064                         MonoInst *val;
11065                         MonoClass *enum_class;
11066                         MonoMethod *has_flag;
11067
11068                         CHECK_STACK (1);
11069                         --sp;
11070                         val = *sp;
11071                         CHECK_OPSIZE (5);
11072                         token = read32 (ip + 1);
11073                         klass = mini_get_class (method, token, generic_context);
11074                         CHECK_TYPELOAD (klass);
11075
11076                         mono_save_token_info (cfg, image, token, klass);
11077
11078                         context_used = mini_class_check_context_used (cfg, klass);
11079
11080                         if (generic_class_is_reference_type (cfg, klass)) {
11081                                 *sp++ = val;
11082                                 ip += 5;
11083                                 break;
11084                         }
11085
11086                         if (klass == mono_defaults.void_class)
11087                                 UNVERIFIED;
11088                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
11089                                 UNVERIFIED;
11090                         /* frequent check in generic code: box (struct), brtrue */
11091
11092                         /*
11093                          * Look for:
11094                          *
11095                          *   <push int/long ptr>
11096                          *   <push int/long>
11097                          *   box MyFlags
11098                          *   constrained. MyFlags
11099                          *   callvirt instace bool class [mscorlib] System.Enum::HasFlag (class [mscorlib] System.Enum)
11100                          *
11101                          * If we find this sequence and the operand types on box and constrained
11102                          * are equal, we can emit a specialized instruction sequence instead of
11103                          * the very slow HasFlag () call.
11104                          */
11105                         if ((cfg->opt & MONO_OPT_INTRINS) &&
11106                             /* Cheap checks first. */
11107                             ip + 5 + 6 + 5 < end &&
11108                             ip [5] == CEE_PREFIX1 &&
11109                             ip [6] == CEE_CONSTRAINED_ &&
11110                             ip [11] == CEE_CALLVIRT &&
11111                             ip_in_bb (cfg, cfg->cbb, ip + 5 + 6 + 5) &&
11112                             mono_class_is_enum (klass) &&
11113                             (enum_class = mini_get_class (method, read32 (ip + 7), generic_context)) &&
11114                             (has_flag = mini_get_method (cfg, method, read32 (ip + 12), NULL, generic_context)) &&
11115                             has_flag->klass == mono_defaults.enum_class &&
11116                             !strcmp (has_flag->name, "HasFlag") &&
11117                             has_flag->signature->hasthis &&
11118                             has_flag->signature->param_count == 1) {
11119                                 CHECK_TYPELOAD (enum_class);
11120
11121                                 if (enum_class == klass) {
11122                                         MonoInst *enum_this, *enum_flag;
11123
11124                                         ip += 5 + 6 + 5;
11125                                         --sp;
11126
11127                                         enum_this = sp [0];
11128                                         enum_flag = sp [1];
11129
11130                                         *sp++ = handle_enum_has_flag (cfg, klass, enum_this, enum_flag);
11131                                         break;
11132                                 }
11133                         }
11134
11135                         // FIXME: LLVM can't handle the inconsistent bb linking
11136                         if (!mono_class_is_nullable (klass) &&
11137                                 !mini_is_gsharedvt_klass (klass) &&
11138                                 ip + 5 < end && ip_in_bb (cfg, cfg->cbb, ip + 5) &&
11139                                 (ip [5] == CEE_BRTRUE || 
11140                                  ip [5] == CEE_BRTRUE_S ||
11141                                  ip [5] == CEE_BRFALSE ||
11142                                  ip [5] == CEE_BRFALSE_S)) {
11143                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
11144                                 int dreg;
11145                                 MonoBasicBlock *true_bb, *false_bb;
11146
11147                                 ip += 5;
11148
11149                                 if (cfg->verbose_level > 3) {
11150                                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
11151                                         printf ("<box+brtrue opt>\n");
11152                                 }
11153
11154                                 switch (*ip) {
11155                                 case CEE_BRTRUE_S:
11156                                 case CEE_BRFALSE_S:
11157                                         CHECK_OPSIZE (2);
11158                                         ip++;
11159                                         target = ip + 1 + (signed char)(*ip);
11160                                         ip++;
11161                                         break;
11162                                 case CEE_BRTRUE:
11163                                 case CEE_BRFALSE:
11164                                         CHECK_OPSIZE (5);
11165                                         ip++;
11166                                         target = ip + 4 + (gint)(read32 (ip));
11167                                         ip += 4;
11168                                         break;
11169                                 default:
11170                                         g_assert_not_reached ();
11171                                 }
11172
11173                                 /* 
11174                                  * We need to link both bblocks, since it is needed for handling stack
11175                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
11176                                  * Branching to only one of them would lead to inconsistencies, so
11177                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
11178                                  */
11179                                 GET_BBLOCK (cfg, true_bb, target);
11180                                 GET_BBLOCK (cfg, false_bb, ip);
11181
11182                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
11183                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
11184
11185                                 if (sp != stack_start) {
11186                                         handle_stack_args (cfg, stack_start, sp - stack_start);
11187                                         sp = stack_start;
11188                                         CHECK_UNVERIFIABLE (cfg);
11189                                 }
11190
11191                                 if (COMPILE_LLVM (cfg)) {
11192                                         dreg = alloc_ireg (cfg);
11193                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
11194                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
11195
11196                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
11197                                 } else {
11198                                         /* The JIT can't eliminate the iconst+compare */
11199                                         MONO_INST_NEW (cfg, ins, OP_BR);
11200                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
11201                                         MONO_ADD_INS (cfg->cbb, ins);
11202                                 }
11203
11204                                 start_new_bblock = 1;
11205                                 break;
11206                         }
11207
11208                         *sp++ = handle_box (cfg, val, klass, context_used);
11209
11210                         CHECK_CFG_EXCEPTION;
11211                         ip += 5;
11212                         inline_costs += 1;
11213                         break;
11214                 }
11215                 case CEE_UNBOX: {
11216                         CHECK_STACK (1);
11217                         --sp;
11218                         CHECK_OPSIZE (5);
11219                         token = read32 (ip + 1);
11220                         klass = mini_get_class (method, token, generic_context);
11221                         CHECK_TYPELOAD (klass);
11222
11223                         mono_save_token_info (cfg, image, token, klass);
11224
11225                         context_used = mini_class_check_context_used (cfg, klass);
11226
11227                         if (mono_class_is_nullable (klass)) {
11228                                 MonoInst *val;
11229
11230                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
11231                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
11232
11233                                 *sp++= ins;
11234                         } else {
11235                                 ins = handle_unbox (cfg, klass, sp, context_used);
11236                                 *sp++ = ins;
11237                         }
11238                         ip += 5;
11239                         inline_costs += 2;
11240                         break;
11241                 }
11242                 case CEE_LDFLD:
11243                 case CEE_LDFLDA:
11244                 case CEE_STFLD:
11245                 case CEE_LDSFLD:
11246                 case CEE_LDSFLDA:
11247                 case CEE_STSFLD: {
11248                         MonoClassField *field;
11249 #ifndef DISABLE_REMOTING
11250                         int costs;
11251 #endif
11252                         guint foffset;
11253                         gboolean is_instance;
11254                         int op;
11255                         gpointer addr = NULL;
11256                         gboolean is_special_static;
11257                         MonoType *ftype;
11258                         MonoInst *store_val = NULL;
11259                         MonoInst *thread_ins;
11260
11261                         op = *ip;
11262                         is_instance = (op == CEE_LDFLD || op == CEE_LDFLDA || op == CEE_STFLD);
11263                         if (is_instance) {
11264                                 if (op == CEE_STFLD) {
11265                                         CHECK_STACK (2);
11266                                         sp -= 2;
11267                                         store_val = sp [1];
11268                                 } else {
11269                                         CHECK_STACK (1);
11270                                         --sp;
11271                                 }
11272                                 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
11273                                         UNVERIFIED;
11274                                 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
11275                                         UNVERIFIED;
11276                         } else {
11277                                 if (op == CEE_STSFLD) {
11278                                         CHECK_STACK (1);
11279                                         sp--;
11280                                         store_val = sp [0];
11281                                 }
11282                         }
11283
11284                         CHECK_OPSIZE (5);
11285                         token = read32 (ip + 1);
11286                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
11287                                 field = (MonoClassField *)mono_method_get_wrapper_data (method, token);
11288                                 klass = field->parent;
11289                         }
11290                         else {
11291                                 field = mono_field_from_token_checked (image, token, &klass, generic_context, &cfg->error);
11292                                 CHECK_CFG_ERROR;
11293                         }
11294                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
11295                                 FIELD_ACCESS_FAILURE (method, field);
11296                         mono_class_init (klass);
11297
11298                         /* if the class is Critical then transparent code cannot access it's fields */
11299                         if (!is_instance && mono_security_core_clr_enabled ())
11300                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
11301
11302                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
11303                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
11304                         if (mono_security_core_clr_enabled ())
11305                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
11306                         */
11307
11308                         ftype = mono_field_get_type (field);
11309
11310                         /*
11311                          * LDFLD etc. is usable on static fields as well, so convert those cases to
11312                          * the static case.
11313                          */
11314                         if (is_instance && ftype->attrs & FIELD_ATTRIBUTE_STATIC) {
11315                                 switch (op) {
11316                                 case CEE_LDFLD:
11317                                         op = CEE_LDSFLD;
11318                                         break;
11319                                 case CEE_STFLD:
11320                                         op = CEE_STSFLD;
11321                                         break;
11322                                 case CEE_LDFLDA:
11323                                         op = CEE_LDSFLDA;
11324                                         break;
11325                                 default:
11326                                         g_assert_not_reached ();
11327                                 }
11328                                 is_instance = FALSE;
11329                         }
11330
11331                         context_used = mini_class_check_context_used (cfg, klass);
11332
11333                         /* INSTANCE CASE */
11334
11335                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
11336                         if (op == CEE_STFLD) {
11337                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
11338                                         UNVERIFIED;
11339 #ifndef DISABLE_REMOTING
11340                                 if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
11341                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
11342                                         MonoInst *iargs [5];
11343
11344                                         GSHAREDVT_FAILURE (op);
11345
11346                                         iargs [0] = sp [0];
11347                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11348                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
11349                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
11350                                                     field->offset);
11351                                         iargs [4] = sp [1];
11352
11353                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
11354                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
11355                                                                                            iargs, ip, cfg->real_offset, TRUE);
11356                                                 CHECK_CFG_EXCEPTION;
11357                                                 g_assert (costs > 0);
11358                                                       
11359                                                 cfg->real_offset += 5;
11360
11361                                                 inline_costs += costs;
11362                                         } else {
11363                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
11364                                         }
11365                                 } else
11366 #endif
11367                                 {
11368                                         MonoInst *store;
11369
11370                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
11371
11372                                         if (mini_is_gsharedvt_klass (klass)) {
11373                                                 MonoInst *offset_ins;
11374
11375                                                 context_used = mini_class_check_context_used (cfg, klass);
11376
11377                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11378                                                 /* The value is offset by 1 */
11379                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11380                                                 dreg = alloc_ireg_mp (cfg);
11381                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11382                                                 /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
11383                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
11384                                         } else {
11385                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
11386                                         }
11387                                         if (sp [0]->opcode != OP_LDADDR)
11388                                                 store->flags |= MONO_INST_FAULT;
11389
11390                                 if (cfg->gen_write_barriers && mini_type_to_stind (cfg, field->type) == CEE_STIND_REF && !(sp [1]->opcode == OP_PCONST && sp [1]->inst_c0 == 0)) {
11391                                         /* insert call to write barrier */
11392                                         MonoInst *ptr;
11393                                         int dreg;
11394
11395                                         dreg = alloc_ireg_mp (cfg);
11396                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
11397                                         emit_write_barrier (cfg, ptr, sp [1]);
11398                                 }
11399
11400                                         store->flags |= ins_flag;
11401                                 }
11402                                 ins_flag = 0;
11403                                 ip += 5;
11404                                 break;
11405                         }
11406
11407 #ifndef DISABLE_REMOTING
11408                         if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
11409                                 MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
11410                                 MonoInst *iargs [4];
11411
11412                                 GSHAREDVT_FAILURE (op);
11413
11414                                 iargs [0] = sp [0];
11415                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11416                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
11417                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
11418                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
11419                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
11420                                                                                    iargs, ip, cfg->real_offset, TRUE);
11421                                         CHECK_CFG_EXCEPTION;
11422                                         g_assert (costs > 0);
11423                                                       
11424                                         cfg->real_offset += 5;
11425
11426                                         *sp++ = iargs [0];
11427
11428                                         inline_costs += costs;
11429                                 } else {
11430                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
11431                                         *sp++ = ins;
11432                                 }
11433                         } else 
11434 #endif
11435                         if (is_instance) {
11436                                 if (sp [0]->type == STACK_VTYPE) {
11437                                         MonoInst *var;
11438
11439                                         /* Have to compute the address of the variable */
11440
11441                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
11442                                         if (!var)
11443                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
11444                                         else
11445                                                 g_assert (var->klass == klass);
11446                                         
11447                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
11448                                         sp [0] = ins;
11449                                 }
11450
11451                                 if (op == CEE_LDFLDA) {
11452                                         if (sp [0]->type == STACK_OBJ) {
11453                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
11454                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
11455                                         }
11456
11457                                         dreg = alloc_ireg_mp (cfg);
11458
11459                                         if (mini_is_gsharedvt_klass (klass)) {
11460                                                 MonoInst *offset_ins;
11461
11462                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11463                                                 /* The value is offset by 1 */
11464                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11465                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11466                                         } else {
11467                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
11468                                         }
11469                                         ins->klass = mono_class_from_mono_type (field->type);
11470                                         ins->type = STACK_MP;
11471                                         *sp++ = ins;
11472                                 } else {
11473                                         MonoInst *load;
11474
11475                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
11476
11477                                         if (mini_is_gsharedvt_klass (klass)) {
11478                                                 MonoInst *offset_ins;
11479
11480                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11481                                                 /* The value is offset by 1 */
11482                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11483                                                 dreg = alloc_ireg_mp (cfg);
11484                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11485                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
11486                                         } else {
11487                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
11488                                         }
11489                                         load->flags |= ins_flag;
11490                                         if (sp [0]->opcode != OP_LDADDR)
11491                                                 load->flags |= MONO_INST_FAULT;
11492                                         *sp++ = load;
11493                                 }
11494                         }
11495
11496                         if (is_instance) {
11497                                 ins_flag = 0;
11498                                 ip += 5;
11499                                 break;
11500                         }
11501
11502                         /* STATIC CASE */
11503                         context_used = mini_class_check_context_used (cfg, klass);
11504
11505                         if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL) {
11506                                 mono_error_set_field_load (&cfg->error, field->parent, field->name, "Using static instructions with literal field");
11507                                 CHECK_CFG_ERROR;
11508                         }
11509
11510                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
11511                          * to be called here.
11512                          */
11513                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
11514                                 mono_class_vtable (cfg->domain, klass);
11515                                 CHECK_TYPELOAD (klass);
11516                         }
11517                         mono_domain_lock (cfg->domain);
11518                         if (cfg->domain->special_static_fields)
11519                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
11520                         mono_domain_unlock (cfg->domain);
11521
11522                         is_special_static = mono_class_field_is_special_static (field);
11523
11524                         if (is_special_static && ((gsize)addr & 0x80000000) == 0)
11525                                 thread_ins = mono_get_thread_intrinsic (cfg);
11526                         else
11527                                 thread_ins = NULL;
11528
11529                         /* Generate IR to compute the field address */
11530                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && thread_ins && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
11531                                 /*
11532                                  * Fast access to TLS data
11533                                  * Inline version of get_thread_static_data () in
11534                                  * threads.c.
11535                                  */
11536                                 guint32 offset;
11537                                 int idx, static_data_reg, array_reg, dreg;
11538
11539                                 GSHAREDVT_FAILURE (op);
11540
11541                                 MONO_ADD_INS (cfg->cbb, thread_ins);
11542                                 static_data_reg = alloc_ireg (cfg);
11543                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
11544
11545                                 if (cfg->compile_aot) {
11546                                         int offset_reg, offset2_reg, idx_reg;
11547
11548                                         /* For TLS variables, this will return the TLS offset */
11549                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
11550                                         offset_reg = ins->dreg;
11551                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
11552                                         idx_reg = alloc_ireg (cfg);
11553                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, idx_reg, offset_reg, 0x3f);
11554                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
11555                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
11556                                         array_reg = alloc_ireg (cfg);
11557                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
11558                                         offset2_reg = alloc_ireg (cfg);
11559                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, offset2_reg, offset_reg, 6);
11560                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset2_reg, 0x1ffffff);
11561                                         dreg = alloc_ireg (cfg);
11562                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
11563                                 } else {
11564                                         offset = (gsize)addr & 0x7fffffff;
11565                                         idx = offset & 0x3f;
11566
11567                                         array_reg = alloc_ireg (cfg);
11568                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
11569                                         dreg = alloc_ireg (cfg);
11570                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, ((offset >> 6) & 0x1ffffff));
11571                                 }
11572                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
11573                                         (cfg->compile_aot && is_special_static) ||
11574                                         (context_used && is_special_static)) {
11575                                 MonoInst *iargs [2];
11576
11577                                 g_assert (field->parent);
11578                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11579                                 if (context_used) {
11580                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
11581                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
11582                                 } else {
11583                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11584                                 }
11585                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11586                         } else if (context_used) {
11587                                 MonoInst *static_data;
11588
11589                                 /*
11590                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
11591                                         method->klass->name_space, method->klass->name, method->name,
11592                                         depth, field->offset);
11593                                 */
11594
11595                                 if (mono_class_needs_cctor_run (klass, method))
11596                                         emit_class_init (cfg, klass);
11597
11598                                 /*
11599                                  * The pointer we're computing here is
11600                                  *
11601                                  *   super_info.static_data + field->offset
11602                                  */
11603                                 static_data = emit_get_rgctx_klass (cfg, context_used,
11604                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
11605
11606                                 if (mini_is_gsharedvt_klass (klass)) {
11607                                         MonoInst *offset_ins;
11608
11609                                         offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11610                                         /* The value is offset by 1 */
11611                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11612                                         dreg = alloc_ireg_mp (cfg);
11613                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
11614                                 } else if (field->offset == 0) {
11615                                         ins = static_data;
11616                                 } else {
11617                                         int addr_reg = mono_alloc_preg (cfg);
11618                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
11619                                 }
11620                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
11621                                 MonoInst *iargs [2];
11622
11623                                 g_assert (field->parent);
11624                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11625                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11626                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11627                         } else {
11628                                 MonoVTable *vtable = NULL;
11629
11630                                 if (!cfg->compile_aot)
11631                                         vtable = mono_class_vtable (cfg->domain, klass);
11632                                 CHECK_TYPELOAD (klass);
11633
11634                                 if (!addr) {
11635                                         if (mini_field_access_needs_cctor_run (cfg, method, klass, vtable)) {
11636                                                 if (!(g_slist_find (class_inits, klass))) {
11637                                                         emit_class_init (cfg, klass);
11638                                                         if (cfg->verbose_level > 2)
11639                                                                 printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
11640                                                         class_inits = g_slist_prepend (class_inits, klass);
11641                                                 }
11642                                         } else {
11643                                                 if (cfg->run_cctors) {
11644                                                         /* This makes so that inline cannot trigger */
11645                                                         /* .cctors: too many apps depend on them */
11646                                                         /* running with a specific order... */
11647                                                         g_assert (vtable);
11648                                                         if (! vtable->initialized)
11649                                                                 INLINE_FAILURE ("class init");
11650                                                         if (!mono_runtime_class_init_full (vtable, &cfg->error)) {
11651                                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
11652                                                                 goto exception_exit;
11653                                                         }
11654                                                 }
11655                                         }
11656                                         if (cfg->compile_aot)
11657                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
11658                                         else {
11659                                                 g_assert (vtable);
11660                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11661                                                 g_assert (addr);
11662                                                 EMIT_NEW_PCONST (cfg, ins, addr);
11663                                         }
11664                                 } else {
11665                                         MonoInst *iargs [1];
11666                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
11667                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
11668                                 }
11669                         }
11670
11671                         /* Generate IR to do the actual load/store operation */
11672
11673                         if ((op == CEE_STFLD || op == CEE_STSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11674                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11675                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11676                         }
11677
11678                         if (op == CEE_LDSFLDA) {
11679                                 ins->klass = mono_class_from_mono_type (ftype);
11680                                 ins->type = STACK_PTR;
11681                                 *sp++ = ins;
11682                         } else if (op == CEE_STSFLD) {
11683                                 MonoInst *store;
11684
11685                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
11686                                 store->flags |= ins_flag;
11687                         } else {
11688                                 gboolean is_const = FALSE;
11689                                 MonoVTable *vtable = NULL;
11690                                 gpointer addr = NULL;
11691
11692                                 if (!context_used) {
11693                                         vtable = mono_class_vtable (cfg->domain, klass);
11694                                         CHECK_TYPELOAD (klass);
11695                                 }
11696                                 if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) ||
11697                                                 (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) {
11698                                         int ro_type = ftype->type;
11699                                         if (!addr)
11700                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11701                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
11702                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
11703                                         }
11704
11705                                         GSHAREDVT_FAILURE (op);
11706
11707                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
11708                                         is_const = TRUE;
11709                                         switch (ro_type) {
11710                                         case MONO_TYPE_BOOLEAN:
11711                                         case MONO_TYPE_U1:
11712                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
11713                                                 sp++;
11714                                                 break;
11715                                         case MONO_TYPE_I1:
11716                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
11717                                                 sp++;
11718                                                 break;                                          
11719                                         case MONO_TYPE_CHAR:
11720                                         case MONO_TYPE_U2:
11721                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
11722                                                 sp++;
11723                                                 break;
11724                                         case MONO_TYPE_I2:
11725                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
11726                                                 sp++;
11727                                                 break;
11728                                                 break;
11729                                         case MONO_TYPE_I4:
11730                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
11731                                                 sp++;
11732                                                 break;                                          
11733                                         case MONO_TYPE_U4:
11734                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
11735                                                 sp++;
11736                                                 break;
11737                                         case MONO_TYPE_I:
11738                                         case MONO_TYPE_U:
11739                                         case MONO_TYPE_PTR:
11740                                         case MONO_TYPE_FNPTR:
11741                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11742                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
11743                                                 sp++;
11744                                                 break;
11745                                         case MONO_TYPE_STRING:
11746                                         case MONO_TYPE_OBJECT:
11747                                         case MONO_TYPE_CLASS:
11748                                         case MONO_TYPE_SZARRAY:
11749                                         case MONO_TYPE_ARRAY:
11750                                                 if (!mono_gc_is_moving ()) {
11751                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11752                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
11753                                                         sp++;
11754                                                 } else {
11755                                                         is_const = FALSE;
11756                                                 }
11757                                                 break;
11758                                         case MONO_TYPE_I8:
11759                                         case MONO_TYPE_U8:
11760                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
11761                                                 sp++;
11762                                                 break;
11763                                         case MONO_TYPE_R4:
11764                                         case MONO_TYPE_R8:
11765                                         case MONO_TYPE_VALUETYPE:
11766                                         default:
11767                                                 is_const = FALSE;
11768                                                 break;
11769                                         }
11770                                 }
11771
11772                                 if (!is_const) {
11773                                         MonoInst *load;
11774
11775                                         CHECK_STACK_OVF (1);
11776
11777                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
11778                                         load->flags |= ins_flag;
11779                                         ins_flag = 0;
11780                                         *sp++ = load;
11781                                 }
11782                         }
11783
11784                         if ((op == CEE_LDFLD || op == CEE_LDSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11785                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
11786                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
11787                         }
11788
11789                         ins_flag = 0;
11790                         ip += 5;
11791                         break;
11792                 }
11793                 case CEE_STOBJ:
11794                         CHECK_STACK (2);
11795                         sp -= 2;
11796                         CHECK_OPSIZE (5);
11797                         token = read32 (ip + 1);
11798                         klass = mini_get_class (method, token, generic_context);
11799                         CHECK_TYPELOAD (klass);
11800                         if (ins_flag & MONO_INST_VOLATILE) {
11801                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11802                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11803                         }
11804                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
11805                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
11806                         ins->flags |= ins_flag;
11807                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
11808                                         generic_class_is_reference_type (cfg, klass)) {
11809                                 /* insert call to write barrier */
11810                                 emit_write_barrier (cfg, sp [0], sp [1]);
11811                         }
11812                         ins_flag = 0;
11813                         ip += 5;
11814                         inline_costs += 1;
11815                         break;
11816
11817                         /*
11818                          * Array opcodes
11819                          */
11820                 case CEE_NEWARR: {
11821                         MonoInst *len_ins;
11822                         const char *data_ptr;
11823                         int data_size = 0;
11824                         guint32 field_token;
11825
11826                         CHECK_STACK (1);
11827                         --sp;
11828
11829                         CHECK_OPSIZE (5);
11830                         token = read32 (ip + 1);
11831
11832                         klass = mini_get_class (method, token, generic_context);
11833                         CHECK_TYPELOAD (klass);
11834
11835                         context_used = mini_class_check_context_used (cfg, klass);
11836
11837                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
11838                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_OVF_U4);
11839                                 ins->sreg1 = sp [0]->dreg;
11840                                 ins->type = STACK_I4;
11841                                 ins->dreg = alloc_ireg (cfg);
11842                                 MONO_ADD_INS (cfg->cbb, ins);
11843                                 *sp = mono_decompose_opcode (cfg, ins);
11844                         }
11845
11846                         if (context_used) {
11847                                 MonoInst *args [3];
11848                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11849                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
11850
11851                                 /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
11852
11853                                 /* vtable */
11854                                 args [0] = emit_get_rgctx_klass (cfg, context_used,
11855                                         array_class, MONO_RGCTX_INFO_VTABLE);
11856                                 /* array len */
11857                                 args [1] = sp [0];
11858
11859                                 if (managed_alloc)
11860                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
11861                                 else
11862                                         ins = mono_emit_jit_icall (cfg, ves_icall_array_new_specific, args);
11863                         } else {
11864                                 if (cfg->opt & MONO_OPT_SHARED) {
11865                                         /* Decompose now to avoid problems with references to the domainvar */
11866                                         MonoInst *iargs [3];
11867
11868                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11869                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11870                                         iargs [2] = sp [0];
11871
11872                                         ins = mono_emit_jit_icall (cfg, mono_array_new, iargs);
11873                                 } else {
11874                                         /* Decompose later since it is needed by abcrem */
11875                                         MonoClass *array_type = mono_array_class_get (klass, 1);
11876                                         mono_class_vtable (cfg->domain, array_type);
11877                                         CHECK_TYPELOAD (array_type);
11878
11879                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
11880                                         ins->dreg = alloc_ireg_ref (cfg);
11881                                         ins->sreg1 = sp [0]->dreg;
11882                                         ins->inst_newa_class = klass;
11883                                         ins->type = STACK_OBJ;
11884                                         ins->klass = array_type;
11885                                         MONO_ADD_INS (cfg->cbb, ins);
11886                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11887                                         cfg->cbb->has_array_access = TRUE;
11888
11889                                         /* Needed so mono_emit_load_get_addr () gets called */
11890                                         mono_get_got_var (cfg);
11891                                 }
11892                         }
11893
11894                         len_ins = sp [0];
11895                         ip += 5;
11896                         *sp++ = ins;
11897                         inline_costs += 1;
11898
11899                         /* 
11900                          * we inline/optimize the initialization sequence if possible.
11901                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
11902                          * for small sizes open code the memcpy
11903                          * ensure the rva field is big enough
11904                          */
11905                         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))) {
11906                                 MonoMethod *memcpy_method = get_memcpy_method ();
11907                                 MonoInst *iargs [3];
11908                                 int add_reg = alloc_ireg_mp (cfg);
11909
11910                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, MONO_STRUCT_OFFSET (MonoArray, vector));
11911                                 if (cfg->compile_aot) {
11912                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
11913                                 } else {
11914                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
11915                                 }
11916                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
11917                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
11918                                 ip += 11;
11919                         }
11920
11921                         break;
11922                 }
11923                 case CEE_LDLEN:
11924                         CHECK_STACK (1);
11925                         --sp;
11926                         if (sp [0]->type != STACK_OBJ)
11927                                 UNVERIFIED;
11928
11929                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
11930                         ins->dreg = alloc_preg (cfg);
11931                         ins->sreg1 = sp [0]->dreg;
11932                         ins->type = STACK_I4;
11933                         /* This flag will be inherited by the decomposition */
11934                         ins->flags |= MONO_INST_FAULT;
11935                         MONO_ADD_INS (cfg->cbb, ins);
11936                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11937                         cfg->cbb->has_array_access = TRUE;
11938                         ip ++;
11939                         *sp++ = ins;
11940                         break;
11941                 case CEE_LDELEMA:
11942                         CHECK_STACK (2);
11943                         sp -= 2;
11944                         CHECK_OPSIZE (5);
11945                         if (sp [0]->type != STACK_OBJ)
11946                                 UNVERIFIED;
11947
11948                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11949
11950                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11951                         CHECK_TYPELOAD (klass);
11952                         /* we need to make sure that this array is exactly the type it needs
11953                          * to be for correctness. the wrappers are lax with their usage
11954                          * so we need to ignore them here
11955                          */
11956                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
11957                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11958                                 mini_emit_check_array_type (cfg, sp [0], array_class);
11959                                 CHECK_TYPELOAD (array_class);
11960                         }
11961
11962                         readonly = FALSE;
11963                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11964                         *sp++ = ins;
11965                         ip += 5;
11966                         break;
11967                 case CEE_LDELEM:
11968                 case CEE_LDELEM_I1:
11969                 case CEE_LDELEM_U1:
11970                 case CEE_LDELEM_I2:
11971                 case CEE_LDELEM_U2:
11972                 case CEE_LDELEM_I4:
11973                 case CEE_LDELEM_U4:
11974                 case CEE_LDELEM_I8:
11975                 case CEE_LDELEM_I:
11976                 case CEE_LDELEM_R4:
11977                 case CEE_LDELEM_R8:
11978                 case CEE_LDELEM_REF: {
11979                         MonoInst *addr;
11980
11981                         CHECK_STACK (2);
11982                         sp -= 2;
11983
11984                         if (*ip == CEE_LDELEM) {
11985                                 CHECK_OPSIZE (5);
11986                                 token = read32 (ip + 1);
11987                                 klass = mini_get_class (method, token, generic_context);
11988                                 CHECK_TYPELOAD (klass);
11989                                 mono_class_init (klass);
11990                         }
11991                         else
11992                                 klass = array_access_to_klass (*ip);
11993
11994                         if (sp [0]->type != STACK_OBJ)
11995                                 UNVERIFIED;
11996
11997                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11998
11999                         if (mini_is_gsharedvt_variable_klass (klass)) {
12000                                 // FIXME-VT: OP_ICONST optimization
12001                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
12002                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
12003                                 ins->opcode = OP_LOADV_MEMBASE;
12004                         } else if (sp [1]->opcode == OP_ICONST) {
12005                                 int array_reg = sp [0]->dreg;
12006                                 int index_reg = sp [1]->dreg;
12007                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
12008
12009                                 if (SIZEOF_REGISTER == 8 && COMPILE_LLVM (cfg))
12010                                         MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, index_reg);
12011
12012                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
12013                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
12014                         } else {
12015                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
12016                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
12017                         }
12018                         *sp++ = ins;
12019                         if (*ip == CEE_LDELEM)
12020                                 ip += 5;
12021                         else
12022                                 ++ip;
12023                         break;
12024                 }
12025                 case CEE_STELEM_I:
12026                 case CEE_STELEM_I1:
12027                 case CEE_STELEM_I2:
12028                 case CEE_STELEM_I4:
12029                 case CEE_STELEM_I8:
12030                 case CEE_STELEM_R4:
12031                 case CEE_STELEM_R8:
12032                 case CEE_STELEM_REF:
12033                 case CEE_STELEM: {
12034                         CHECK_STACK (3);
12035                         sp -= 3;
12036
12037                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
12038
12039                         if (*ip == CEE_STELEM) {
12040                                 CHECK_OPSIZE (5);
12041                                 token = read32 (ip + 1);
12042                                 klass = mini_get_class (method, token, generic_context);
12043                                 CHECK_TYPELOAD (klass);
12044                                 mono_class_init (klass);
12045                         }
12046                         else
12047                                 klass = array_access_to_klass (*ip);
12048
12049                         if (sp [0]->type != STACK_OBJ)
12050                                 UNVERIFIED;
12051
12052                         emit_array_store (cfg, klass, sp, TRUE);
12053
12054                         if (*ip == CEE_STELEM)
12055                                 ip += 5;
12056                         else
12057                                 ++ip;
12058                         inline_costs += 1;
12059                         break;
12060                 }
12061                 case CEE_CKFINITE: {
12062                         CHECK_STACK (1);
12063                         --sp;
12064
12065                         if (cfg->llvm_only) {
12066                                 MonoInst *iargs [1];
12067
12068                                 iargs [0] = sp [0];
12069                                 *sp++ = mono_emit_jit_icall (cfg, mono_ckfinite, iargs);
12070                         } else  {
12071                                 MONO_INST_NEW (cfg, ins, OP_CKFINITE);
12072                                 ins->sreg1 = sp [0]->dreg;
12073                                 ins->dreg = alloc_freg (cfg);
12074                                 ins->type = STACK_R8;
12075                                 MONO_ADD_INS (cfg->cbb, ins);
12076
12077                                 *sp++ = mono_decompose_opcode (cfg, ins);
12078                         }
12079
12080                         ++ip;
12081                         break;
12082                 }
12083                 case CEE_REFANYVAL: {
12084                         MonoInst *src_var, *src;
12085
12086                         int klass_reg = alloc_preg (cfg);
12087                         int dreg = alloc_preg (cfg);
12088
12089                         GSHAREDVT_FAILURE (*ip);
12090
12091                         CHECK_STACK (1);
12092                         MONO_INST_NEW (cfg, ins, *ip);
12093                         --sp;
12094                         CHECK_OPSIZE (5);
12095                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
12096                         CHECK_TYPELOAD (klass);
12097
12098                         context_used = mini_class_check_context_used (cfg, klass);
12099
12100                         // FIXME:
12101                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12102                         if (!src_var)
12103                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
12104                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
12105                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass));
12106
12107                         if (context_used) {
12108                                 MonoInst *klass_ins;
12109
12110                                 klass_ins = emit_get_rgctx_klass (cfg, context_used,
12111                                                 klass, MONO_RGCTX_INFO_KLASS);
12112
12113                                 // FIXME:
12114                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
12115                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
12116                         } else {
12117                                 mini_emit_class_check (cfg, klass_reg, klass);
12118                         }
12119                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value));
12120                         ins->type = STACK_MP;
12121                         ins->klass = klass;
12122                         *sp++ = ins;
12123                         ip += 5;
12124                         break;
12125                 }
12126                 case CEE_MKREFANY: {
12127                         MonoInst *loc, *addr;
12128
12129                         GSHAREDVT_FAILURE (*ip);
12130
12131                         CHECK_STACK (1);
12132                         MONO_INST_NEW (cfg, ins, *ip);
12133                         --sp;
12134                         CHECK_OPSIZE (5);
12135                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
12136                         CHECK_TYPELOAD (klass);
12137
12138                         context_used = mini_class_check_context_used (cfg, klass);
12139
12140                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
12141                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
12142
12143                         if (context_used) {
12144                                 MonoInst *const_ins;
12145                                 int type_reg = alloc_preg (cfg);
12146
12147                                 const_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
12148                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
12149                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
12150                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
12151                         } else if (cfg->compile_aot) {
12152                                 int const_reg = alloc_preg (cfg);
12153                                 int type_reg = alloc_preg (cfg);
12154
12155                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
12156                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
12157                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
12158                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
12159                         } else {
12160                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), &klass->byval_arg);
12161                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), klass);
12162                         }
12163                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
12164
12165                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
12166                         ins->type = STACK_VTYPE;
12167                         ins->klass = mono_defaults.typed_reference_class;
12168                         *sp++ = ins;
12169                         ip += 5;
12170                         break;
12171                 }
12172                 case CEE_LDTOKEN: {
12173                         gpointer handle;
12174                         MonoClass *handle_class;
12175
12176                         CHECK_STACK_OVF (1);
12177
12178                         CHECK_OPSIZE (5);
12179                         n = read32 (ip + 1);
12180
12181                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
12182                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
12183                                 handle = mono_method_get_wrapper_data (method, n);
12184                                 handle_class = (MonoClass *)mono_method_get_wrapper_data (method, n + 1);
12185                                 if (handle_class == mono_defaults.typehandle_class)
12186                                         handle = &((MonoClass*)handle)->byval_arg;
12187                         }
12188                         else {
12189                                 handle = mono_ldtoken_checked (image, n, &handle_class, generic_context, &cfg->error);
12190                                 CHECK_CFG_ERROR;
12191                         }
12192                         if (!handle)
12193                                 LOAD_ERROR;
12194                         mono_class_init (handle_class);
12195                         if (cfg->gshared) {
12196                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
12197                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
12198                                         /* This case handles ldtoken
12199                                            of an open type, like for
12200                                            typeof(Gen<>). */
12201                                         context_used = 0;
12202                                 } else if (handle_class == mono_defaults.typehandle_class) {
12203                                         context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type ((MonoType *)handle));
12204                                 } else if (handle_class == mono_defaults.fieldhandle_class)
12205                                         context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
12206                                 else if (handle_class == mono_defaults.methodhandle_class)
12207                                         context_used = mini_method_check_context_used (cfg, (MonoMethod *)handle);
12208                                 else
12209                                         g_assert_not_reached ();
12210                         }
12211
12212                         if ((cfg->opt & MONO_OPT_SHARED) &&
12213                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
12214                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
12215                                 MonoInst *addr, *vtvar, *iargs [3];
12216                                 int method_context_used;
12217
12218                                 method_context_used = mini_method_check_context_used (cfg, method);
12219
12220                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
12221
12222                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
12223                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
12224                                 if (method_context_used) {
12225                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
12226                                                 method, MONO_RGCTX_INFO_METHOD);
12227                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
12228                                 } else {
12229                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
12230                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
12231                                 }
12232                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12233
12234                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
12235
12236                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12237                         } else {
12238                                 if ((ip + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 5) && 
12239                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
12240                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
12241                                         (cmethod->klass == mono_defaults.systemtype_class) &&
12242                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
12243                                         MonoClass *tclass = mono_class_from_mono_type ((MonoType *)handle);
12244
12245                                         mono_class_init (tclass);
12246                                         if (context_used) {
12247                                                 ins = emit_get_rgctx_klass (cfg, context_used,
12248                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
12249                                         } else if (cfg->compile_aot) {
12250                                                 if (method->wrapper_type) {
12251                                                         mono_error_init (&error); //got to do it since there are multiple conditionals below
12252                                                         if (mono_class_get_checked (tclass->image, tclass->type_token, &error) == tclass && !generic_context) {
12253                                                                 /* Special case for static synchronized wrappers */
12254                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
12255                                                         } else {
12256                                                                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
12257                                                                 /* FIXME: n is not a normal token */
12258                                                                 DISABLE_AOT (cfg);
12259                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12260                                                         }
12261                                                 } else {
12262                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
12263                                                 }
12264                                         } else {
12265                                                 MonoReflectionType *rt = mono_type_get_object_checked (cfg->domain, (MonoType *)handle, &cfg->error);
12266                                                 CHECK_CFG_ERROR;
12267                                                 EMIT_NEW_PCONST (cfg, ins, rt);
12268                                         }
12269                                         ins->type = STACK_OBJ;
12270                                         ins->klass = cmethod->klass;
12271                                         ip += 5;
12272                                 } else {
12273                                         MonoInst *addr, *vtvar;
12274
12275                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
12276
12277                                         if (context_used) {
12278                                                 if (handle_class == mono_defaults.typehandle_class) {
12279                                                         ins = emit_get_rgctx_klass (cfg, context_used,
12280                                                                         mono_class_from_mono_type ((MonoType *)handle),
12281                                                                         MONO_RGCTX_INFO_TYPE);
12282                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
12283                                                         ins = emit_get_rgctx_method (cfg, context_used,
12284                                                                         (MonoMethod *)handle, MONO_RGCTX_INFO_METHOD);
12285                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
12286                                                         ins = emit_get_rgctx_field (cfg, context_used,
12287                                                                         (MonoClassField *)handle, MONO_RGCTX_INFO_CLASS_FIELD);
12288                                                 } else {
12289                                                         g_assert_not_reached ();
12290                                                 }
12291                                         } else if (cfg->compile_aot) {
12292                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n, generic_context);
12293                                         } else {
12294                                                 EMIT_NEW_PCONST (cfg, ins, handle);
12295                                         }
12296                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12297                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
12298                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12299                                 }
12300                         }
12301
12302                         *sp++ = ins;
12303                         ip += 5;
12304                         break;
12305                 }
12306                 case CEE_THROW:
12307                         CHECK_STACK (1);
12308                         MONO_INST_NEW (cfg, ins, OP_THROW);
12309                         --sp;
12310                         ins->sreg1 = sp [0]->dreg;
12311                         ip++;
12312                         cfg->cbb->out_of_line = TRUE;
12313                         MONO_ADD_INS (cfg->cbb, ins);
12314                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
12315                         MONO_ADD_INS (cfg->cbb, ins);
12316                         sp = stack_start;
12317                         
12318                         link_bblock (cfg, cfg->cbb, end_bblock);
12319                         start_new_bblock = 1;
12320                         /* This can complicate code generation for llvm since the return value might not be defined */
12321                         if (COMPILE_LLVM (cfg))
12322                                 INLINE_FAILURE ("throw");
12323                         break;
12324                 case CEE_ENDFINALLY:
12325                         /* mono_save_seq_point_info () depends on this */
12326                         if (sp != stack_start)
12327                                 emit_seq_point (cfg, method, ip, FALSE, FALSE);
12328                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
12329                         MONO_ADD_INS (cfg->cbb, ins);
12330                         ip++;
12331                         start_new_bblock = 1;
12332
12333                         /*
12334                          * Control will leave the method so empty the stack, otherwise
12335                          * the next basic block will start with a nonempty stack.
12336                          */
12337                         while (sp != stack_start) {
12338                                 sp--;
12339                         }
12340                         break;
12341                 case CEE_LEAVE:
12342                 case CEE_LEAVE_S: {
12343                         GList *handlers;
12344
12345                         if (*ip == CEE_LEAVE) {
12346                                 CHECK_OPSIZE (5);
12347                                 target = ip + 5 + (gint32)read32(ip + 1);
12348                         } else {
12349                                 CHECK_OPSIZE (2);
12350                                 target = ip + 2 + (signed char)(ip [1]);
12351                         }
12352
12353                         /* empty the stack */
12354                         while (sp != stack_start) {
12355                                 sp--;
12356                         }
12357
12358                         /* 
12359                          * If this leave statement is in a catch block, check for a
12360                          * pending exception, and rethrow it if necessary.
12361                          * We avoid doing this in runtime invoke wrappers, since those are called
12362                          * by native code which excepts the wrapper to catch all exceptions.
12363                          */
12364                         for (i = 0; i < header->num_clauses; ++i) {
12365                                 MonoExceptionClause *clause = &header->clauses [i];
12366
12367                                 /* 
12368                                  * Use <= in the final comparison to handle clauses with multiple
12369                                  * leave statements, like in bug #78024.
12370                                  * The ordering of the exception clauses guarantees that we find the
12371                                  * innermost clause.
12372                                  */
12373                                 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) {
12374                                         MonoInst *exc_ins;
12375                                         MonoBasicBlock *dont_throw;
12376
12377                                         /*
12378                                           MonoInst *load;
12379
12380                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
12381                                         */
12382
12383                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
12384
12385                                         NEW_BBLOCK (cfg, dont_throw);
12386
12387                                         /*
12388                                          * Currently, we always rethrow the abort exception, despite the 
12389                                          * fact that this is not correct. See thread6.cs for an example. 
12390                                          * But propagating the abort exception is more important than 
12391                                          * getting the sematics right.
12392                                          */
12393                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
12394                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
12395                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
12396
12397                                         MONO_START_BB (cfg, dont_throw);
12398                                 }
12399                         }
12400
12401 #ifdef ENABLE_LLVM
12402                         cfg->cbb->try_end = (intptr_t)(ip - header->code);
12403 #endif
12404
12405                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
12406                                 GList *tmp;
12407                                 MonoExceptionClause *clause;
12408
12409                                 for (tmp = handlers; tmp; tmp = tmp->next) {
12410                                         clause = (MonoExceptionClause *)tmp->data;
12411                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
12412                                         g_assert (tblock);
12413                                         link_bblock (cfg, cfg->cbb, tblock);
12414                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
12415                                         ins->inst_target_bb = tblock;
12416                                         ins->inst_eh_block = clause;
12417                                         MONO_ADD_INS (cfg->cbb, ins);
12418                                         cfg->cbb->has_call_handler = 1;
12419                                         if (COMPILE_LLVM (cfg)) {
12420                                                 MonoBasicBlock *target_bb;
12421
12422                                                 /* 
12423                                                  * Link the finally bblock with the target, since it will
12424                                                  * conceptually branch there.
12425                                                  */
12426                                                 GET_BBLOCK (cfg, tblock, cfg->cil_start + clause->handler_offset + clause->handler_len - 1);
12427                                                 GET_BBLOCK (cfg, target_bb, target);
12428                                                 link_bblock (cfg, tblock, target_bb);
12429                                         }
12430                                 }
12431                                 g_list_free (handlers);
12432                         } 
12433
12434                         MONO_INST_NEW (cfg, ins, OP_BR);
12435                         MONO_ADD_INS (cfg->cbb, ins);
12436                         GET_BBLOCK (cfg, tblock, target);
12437                         link_bblock (cfg, cfg->cbb, tblock);
12438                         ins->inst_target_bb = tblock;
12439
12440                         start_new_bblock = 1;
12441
12442                         if (*ip == CEE_LEAVE)
12443                                 ip += 5;
12444                         else
12445                                 ip += 2;
12446
12447                         break;
12448                 }
12449
12450                         /*
12451                          * Mono specific opcodes
12452                          */
12453                 case MONO_CUSTOM_PREFIX: {
12454
12455                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
12456
12457                         CHECK_OPSIZE (2);
12458                         switch (ip [1]) {
12459                         case CEE_MONO_ICALL: {
12460                                 gpointer func;
12461                                 MonoJitICallInfo *info;
12462
12463                                 token = read32 (ip + 2);
12464                                 func = mono_method_get_wrapper_data (method, token);
12465                                 info = mono_find_jit_icall_by_addr (func);
12466                                 if (!info)
12467                                         g_error ("Could not find icall address in wrapper %s", mono_method_full_name (method, 1));
12468                                 g_assert (info);
12469
12470                                 CHECK_STACK (info->sig->param_count);
12471                                 sp -= info->sig->param_count;
12472
12473                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
12474                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
12475                                         *sp++ = ins;
12476
12477                                 ip += 6;
12478                                 inline_costs += 10 * num_calls++;
12479
12480                                 break;
12481                         }
12482                         case CEE_MONO_LDPTR_CARD_TABLE:
12483                         case CEE_MONO_LDPTR_NURSERY_START:
12484                         case CEE_MONO_LDPTR_NURSERY_BITS:
12485                         case CEE_MONO_LDPTR_INT_REQ_FLAG: {
12486                                 CHECK_STACK_OVF (1);
12487
12488                                 switch (ip [1]) {
12489                                         case CEE_MONO_LDPTR_CARD_TABLE:
12490                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
12491                                                 break;
12492                                         case CEE_MONO_LDPTR_NURSERY_START:
12493                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_START, NULL);
12494                                                 break;
12495                                         case CEE_MONO_LDPTR_NURSERY_BITS:
12496                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_BITS, NULL);
12497                                                 break;
12498                                         case CEE_MONO_LDPTR_INT_REQ_FLAG:
12499                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
12500                                                 break;
12501                                 }
12502
12503                                 *sp++ = ins;
12504                                 ip += 2;
12505                                 inline_costs += 10 * num_calls++;
12506                                 break;
12507                         }
12508                         case CEE_MONO_LDPTR: {
12509                                 gpointer ptr;
12510
12511                                 CHECK_STACK_OVF (1);
12512                                 CHECK_OPSIZE (6);
12513                                 token = read32 (ip + 2);
12514
12515                                 ptr = mono_method_get_wrapper_data (method, token);
12516                                 EMIT_NEW_PCONST (cfg, ins, ptr);
12517                                 *sp++ = ins;
12518                                 ip += 6;
12519                                 inline_costs += 10 * num_calls++;
12520                                 /* Can't embed random pointers into AOT code */
12521                                 DISABLE_AOT (cfg);
12522                                 break;
12523                         }
12524                         case CEE_MONO_JIT_ICALL_ADDR: {
12525                                 MonoJitICallInfo *callinfo;
12526                                 gpointer ptr;
12527
12528                                 CHECK_STACK_OVF (1);
12529                                 CHECK_OPSIZE (6);
12530                                 token = read32 (ip + 2);
12531
12532                                 ptr = mono_method_get_wrapper_data (method, token);
12533                                 callinfo = mono_find_jit_icall_by_addr (ptr);
12534                                 g_assert (callinfo);
12535                                 EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
12536                                 *sp++ = ins;
12537                                 ip += 6;
12538                                 inline_costs += 10 * num_calls++;
12539                                 break;
12540                         }
12541                         case CEE_MONO_ICALL_ADDR: {
12542                                 MonoMethod *cmethod;
12543                                 gpointer ptr;
12544
12545                                 CHECK_STACK_OVF (1);
12546                                 CHECK_OPSIZE (6);
12547                                 token = read32 (ip + 2);
12548
12549                                 cmethod = (MonoMethod *)mono_method_get_wrapper_data (method, token);
12550
12551                                 if (cfg->compile_aot) {
12552                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
12553                                 } else {
12554                                         ptr = mono_lookup_internal_call (cmethod);
12555                                         g_assert (ptr);
12556                                         EMIT_NEW_PCONST (cfg, ins, ptr);
12557                                 }
12558                                 *sp++ = ins;
12559                                 ip += 6;
12560                                 break;
12561                         }
12562                         case CEE_MONO_VTADDR: {
12563                                 MonoInst *src_var, *src;
12564
12565                                 CHECK_STACK (1);
12566                                 --sp;
12567
12568                                 // FIXME:
12569                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12570                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
12571                                 *sp++ = src;
12572                                 ip += 2;
12573                                 break;
12574                         }
12575                         case CEE_MONO_NEWOBJ: {
12576                                 MonoInst *iargs [2];
12577
12578                                 CHECK_STACK_OVF (1);
12579                                 CHECK_OPSIZE (6);
12580                                 token = read32 (ip + 2);
12581                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12582                                 mono_class_init (klass);
12583                                 NEW_DOMAINCONST (cfg, iargs [0]);
12584                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
12585                                 NEW_CLASSCONST (cfg, iargs [1], klass);
12586                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
12587                                 *sp++ = mono_emit_jit_icall (cfg, ves_icall_object_new, iargs);
12588                                 ip += 6;
12589                                 inline_costs += 10 * num_calls++;
12590                                 break;
12591                         }
12592                         case CEE_MONO_OBJADDR:
12593                                 CHECK_STACK (1);
12594                                 --sp;
12595                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
12596                                 ins->dreg = alloc_ireg_mp (cfg);
12597                                 ins->sreg1 = sp [0]->dreg;
12598                                 ins->type = STACK_MP;
12599                                 MONO_ADD_INS (cfg->cbb, ins);
12600                                 *sp++ = ins;
12601                                 ip += 2;
12602                                 break;
12603                         case CEE_MONO_LDNATIVEOBJ:
12604                                 /*
12605                                  * Similar to LDOBJ, but instead load the unmanaged 
12606                                  * representation of the vtype to the stack.
12607                                  */
12608                                 CHECK_STACK (1);
12609                                 CHECK_OPSIZE (6);
12610                                 --sp;
12611                                 token = read32 (ip + 2);
12612                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12613                                 g_assert (klass->valuetype);
12614                                 mono_class_init (klass);
12615
12616                                 {
12617                                         MonoInst *src, *dest, *temp;
12618
12619                                         src = sp [0];
12620                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
12621                                         temp->backend.is_pinvoke = 1;
12622                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
12623                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
12624
12625                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
12626                                         dest->type = STACK_VTYPE;
12627                                         dest->klass = klass;
12628
12629                                         *sp ++ = dest;
12630                                         ip += 6;
12631                                 }
12632                                 break;
12633                         case CEE_MONO_RETOBJ: {
12634                                 /*
12635                                  * Same as RET, but return the native representation of a vtype
12636                                  * to the caller.
12637                                  */
12638                                 g_assert (cfg->ret);
12639                                 g_assert (mono_method_signature (method)->pinvoke); 
12640                                 CHECK_STACK (1);
12641                                 --sp;
12642                                 
12643                                 CHECK_OPSIZE (6);
12644                                 token = read32 (ip + 2);    
12645                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12646
12647                                 if (!cfg->vret_addr) {
12648                                         g_assert (cfg->ret_var_is_local);
12649
12650                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
12651                                 } else {
12652                                         EMIT_NEW_RETLOADA (cfg, ins);
12653                                 }
12654                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
12655                                 
12656                                 if (sp != stack_start)
12657                                         UNVERIFIED;
12658                                 
12659                                 MONO_INST_NEW (cfg, ins, OP_BR);
12660                                 ins->inst_target_bb = end_bblock;
12661                                 MONO_ADD_INS (cfg->cbb, ins);
12662                                 link_bblock (cfg, cfg->cbb, end_bblock);
12663                                 start_new_bblock = 1;
12664                                 ip += 6;
12665                                 break;
12666                         }
12667                         case CEE_MONO_CISINST:
12668                         case CEE_MONO_CCASTCLASS: {
12669                                 int token;
12670                                 CHECK_STACK (1);
12671                                 --sp;
12672                                 CHECK_OPSIZE (6);
12673                                 token = read32 (ip + 2);
12674                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12675                                 if (ip [1] == CEE_MONO_CISINST)
12676                                         ins = handle_cisinst (cfg, klass, sp [0]);
12677                                 else
12678                                         ins = handle_ccastclass (cfg, klass, sp [0]);
12679                                 *sp++ = ins;
12680                                 ip += 6;
12681                                 break;
12682                         }
12683                         case CEE_MONO_SAVE_LMF:
12684                         case CEE_MONO_RESTORE_LMF:
12685                                 ip += 2;
12686                                 break;
12687                         case CEE_MONO_CLASSCONST:
12688                                 CHECK_STACK_OVF (1);
12689                                 CHECK_OPSIZE (6);
12690                                 token = read32 (ip + 2);
12691                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
12692                                 *sp++ = ins;
12693                                 ip += 6;
12694                                 inline_costs += 10 * num_calls++;
12695                                 break;
12696                         case CEE_MONO_NOT_TAKEN:
12697                                 cfg->cbb->out_of_line = TRUE;
12698                                 ip += 2;
12699                                 break;
12700                         case CEE_MONO_TLS: {
12701                                 MonoTlsKey key;
12702
12703                                 CHECK_STACK_OVF (1);
12704                                 CHECK_OPSIZE (6);
12705                                 key = (MonoTlsKey)read32 (ip + 2);
12706                                 g_assert (key < TLS_KEY_NUM);
12707
12708                                 ins = mono_create_tls_get (cfg, key);
12709                                 if (!ins) {
12710                                         if (cfg->compile_aot) {
12711                                                 DISABLE_AOT (cfg);
12712                                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
12713                                                 ins->dreg = alloc_preg (cfg);
12714                                                 ins->type = STACK_PTR;
12715                                         } else {
12716                                                 g_assert_not_reached ();
12717                                         }
12718                                 }
12719                                 ins->type = STACK_PTR;
12720                                 MONO_ADD_INS (cfg->cbb, ins);
12721                                 *sp++ = ins;
12722                                 ip += 6;
12723                                 break;
12724                         }
12725                         case CEE_MONO_DYN_CALL: {
12726                                 MonoCallInst *call;
12727
12728                                 /* It would be easier to call a trampoline, but that would put an
12729                                  * extra frame on the stack, confusing exception handling. So
12730                                  * implement it inline using an opcode for now.
12731                                  */
12732
12733                                 if (!cfg->dyn_call_var) {
12734                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12735                                         /* prevent it from being register allocated */
12736                                         cfg->dyn_call_var->flags |= MONO_INST_VOLATILE;
12737                                 }
12738
12739                                 /* Has to use a call inst since it local regalloc expects it */
12740                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
12741                                 ins = (MonoInst*)call;
12742                                 sp -= 2;
12743                                 ins->sreg1 = sp [0]->dreg;
12744                                 ins->sreg2 = sp [1]->dreg;
12745                                 MONO_ADD_INS (cfg->cbb, ins);
12746
12747                                 cfg->param_area = MAX (cfg->param_area, cfg->backend->dyn_call_param_area);
12748
12749                                 ip += 2;
12750                                 inline_costs += 10 * num_calls++;
12751
12752                                 break;
12753                         }
12754                         case CEE_MONO_MEMORY_BARRIER: {
12755                                 CHECK_OPSIZE (6);
12756                                 emit_memory_barrier (cfg, (int)read32 (ip + 2));
12757                                 ip += 6;
12758                                 break;
12759                         }
12760                         case CEE_MONO_JIT_ATTACH: {
12761                                 MonoInst *args [16], *domain_ins;
12762                                 MonoInst *ad_ins, *jit_tls_ins;
12763                                 MonoBasicBlock *next_bb = NULL, *call_bb = NULL;
12764
12765                                 cfg->attach_cookie = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12766                                 cfg->attach_dummy = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12767
12768                                 if (mono_threads_is_coop_enabled ()) {
12769                                         /* AOT code is only used in the root domain */
12770                                         EMIT_NEW_PCONST (cfg, args [0], cfg->compile_aot ? NULL : cfg->domain);
12771                                         EMIT_NEW_VARLOADA (cfg, args [1], cfg->attach_dummy, cfg->attach_dummy->inst_vtype);
12772                                         ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
12773                                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->attach_cookie->dreg, ins->dreg);
12774                                 } else {
12775                                         EMIT_NEW_PCONST (cfg, ins, NULL);
12776                                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->attach_cookie->dreg, ins->dreg);
12777
12778                                         ad_ins = mono_get_domain_intrinsic (cfg);
12779                                         jit_tls_ins = mono_get_jit_tls_intrinsic (cfg);
12780
12781                                         if (cfg->backend->have_tls_get && ad_ins && jit_tls_ins) {
12782                                                 NEW_BBLOCK (cfg, next_bb);
12783                                                 NEW_BBLOCK (cfg, call_bb);
12784
12785                                                 if (cfg->compile_aot) {
12786                                                         /* AOT code is only used in the root domain */
12787                                                         EMIT_NEW_PCONST (cfg, domain_ins, NULL);
12788                                                 } else {
12789                                                         EMIT_NEW_PCONST (cfg, domain_ins, cfg->domain);
12790                                                 }
12791                                                 MONO_ADD_INS (cfg->cbb, ad_ins);
12792                                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, ad_ins->dreg, domain_ins->dreg);
12793                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, call_bb);
12794
12795                                                 MONO_ADD_INS (cfg->cbb, jit_tls_ins);
12796                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, jit_tls_ins->dreg, 0);
12797                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, call_bb);
12798
12799                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, next_bb);
12800                                                 MONO_START_BB (cfg, call_bb);
12801                                         }
12802
12803                                         /* AOT code is only used in the root domain */
12804                                         EMIT_NEW_PCONST (cfg, args [0], cfg->compile_aot ? NULL : cfg->domain);
12805                                         EMIT_NEW_PCONST (cfg, args [1], NULL);
12806                                         ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
12807                                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->attach_cookie->dreg, ins->dreg);
12808
12809                                         if (next_bb)
12810                                                 MONO_START_BB (cfg, next_bb);
12811                                 }
12812
12813                                 ip += 2;
12814                                 break;
12815                         }
12816                         case CEE_MONO_JIT_DETACH: {
12817                                 MonoInst *args [16];
12818
12819                                 /* Restore the original domain */
12820                                 dreg = alloc_ireg (cfg);
12821                                 EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->attach_cookie->dreg);
12822                                 EMIT_NEW_VARLOADA (cfg, args [1], cfg->attach_dummy, cfg->attach_dummy->inst_vtype);
12823                                 mono_emit_jit_icall (cfg, mono_jit_thread_detach, args);
12824                                 ip += 2;
12825                                 break;
12826                         }
12827                         case CEE_MONO_CALLI_EXTRA_ARG: {
12828                                 MonoInst *addr;
12829                                 MonoMethodSignature *fsig;
12830                                 MonoInst *arg;
12831
12832                                 /*
12833                                  * This is the same as CEE_CALLI, but passes an additional argument
12834                                  * to the called method in llvmonly mode.
12835                                  * This is only used by delegate invoke wrappers to call the
12836                                  * actual delegate method.
12837                                  */
12838                                 g_assert (method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE);
12839
12840                                 CHECK_OPSIZE (6);
12841                                 token = read32 (ip + 2);
12842
12843                                 ins = NULL;
12844
12845                                 cmethod = NULL;
12846                                 CHECK_STACK (1);
12847                                 --sp;
12848                                 addr = *sp;
12849                                 fsig = mini_get_signature (method, token, generic_context);
12850
12851                                 if (cfg->llvm_only)
12852                                         cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, fsig);
12853
12854                                 n = fsig->param_count + fsig->hasthis + 1;
12855
12856                                 CHECK_STACK (n);
12857
12858                                 sp -= n;
12859                                 arg = sp [n - 1];
12860
12861                                 if (cfg->llvm_only) {
12862                                         /*
12863                                          * The lowest bit of 'arg' determines whenever the callee uses the gsharedvt
12864                                          * cconv. This is set by mono_init_delegate ().
12865                                          */
12866                                         if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig)) {
12867                                                 MonoInst *callee = addr;
12868                                                 MonoInst *call, *localloc_ins;
12869                                                 MonoBasicBlock *is_gsharedvt_bb, *end_bb;
12870                                                 int low_bit_reg = alloc_preg (cfg);
12871
12872                                                 NEW_BBLOCK (cfg, is_gsharedvt_bb);
12873                                                 NEW_BBLOCK (cfg, end_bb);
12874
12875                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, low_bit_reg, arg->dreg, 1);
12876                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_bit_reg, 0);
12877                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_gsharedvt_bb);
12878
12879                                                 /* Normal case: callee uses a normal cconv, have to add an out wrapper */
12880                                                 addr = emit_get_rgctx_sig (cfg, context_used,
12881                                                                                                    fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
12882                                                 /*
12883                                                  * ADDR points to a gsharedvt-out wrapper, have to pass <callee, arg> as an extra arg.
12884                                                  */
12885                                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
12886                                                 ins->dreg = alloc_preg (cfg);
12887                                                 ins->inst_imm = 2 * SIZEOF_VOID_P;
12888                                                 MONO_ADD_INS (cfg->cbb, ins);
12889                                                 localloc_ins = ins;
12890                                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12891                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, 0, callee->dreg);
12892                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, SIZEOF_VOID_P, arg->dreg);
12893
12894                                                 call = emit_extra_arg_calli (cfg, fsig, sp, localloc_ins->dreg, addr);
12895                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12896
12897                                                 /* Gsharedvt case: callee uses a gsharedvt cconv, no conversion is needed */
12898                                                 MONO_START_BB (cfg, is_gsharedvt_bb);
12899                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PXOR_IMM, arg->dreg, arg->dreg, 1);
12900                                                 ins = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
12901                                                 ins->dreg = call->dreg;
12902
12903                                                 MONO_START_BB (cfg, end_bb);
12904                                         } else {
12905                                                 /* Caller uses a normal calling conv */
12906
12907                                                 MonoInst *callee = addr;
12908                                                 MonoInst *call, *localloc_ins;
12909                                                 MonoBasicBlock *is_gsharedvt_bb, *end_bb;
12910                                                 int low_bit_reg = alloc_preg (cfg);
12911
12912                                                 NEW_BBLOCK (cfg, is_gsharedvt_bb);
12913                                                 NEW_BBLOCK (cfg, end_bb);
12914
12915                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, low_bit_reg, arg->dreg, 1);
12916                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_bit_reg, 0);
12917                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_gsharedvt_bb);
12918
12919                                                 /* Normal case: callee uses a normal cconv, no conversion is needed */
12920                                                 call = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
12921                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12922                                                 /* Gsharedvt case: callee uses a gsharedvt cconv, have to add an in wrapper */
12923                                                 MONO_START_BB (cfg, is_gsharedvt_bb);
12924                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PXOR_IMM, arg->dreg, arg->dreg, 1);
12925                                                 NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER, fsig);
12926                                                 MONO_ADD_INS (cfg->cbb, addr);
12927                                                 /*
12928                                                  * ADDR points to a gsharedvt-in wrapper, have to pass <callee, arg> as an extra arg.
12929                                                  */
12930                                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
12931                                                 ins->dreg = alloc_preg (cfg);
12932                                                 ins->inst_imm = 2 * SIZEOF_VOID_P;
12933                                                 MONO_ADD_INS (cfg->cbb, ins);
12934                                                 localloc_ins = ins;
12935                                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12936                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, 0, callee->dreg);
12937                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, SIZEOF_VOID_P, arg->dreg);
12938
12939                                                 ins = emit_extra_arg_calli (cfg, fsig, sp, localloc_ins->dreg, addr);
12940                                                 ins->dreg = call->dreg;
12941                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12942
12943                                                 MONO_START_BB (cfg, end_bb);
12944                                         }
12945                                 } else {
12946                                         /* Same as CEE_CALLI */
12947                                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
12948                                                 /*
12949                                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
12950                                                  */
12951                                                 MonoInst *callee = addr;
12952
12953                                                 addr = emit_get_rgctx_sig (cfg, context_used,
12954                                                                                                    fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
12955                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
12956                                         } else {
12957                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
12958                                         }
12959                                 }
12960
12961                                 if (!MONO_TYPE_IS_VOID (fsig->ret))
12962                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
12963
12964                                 CHECK_CFG_EXCEPTION;
12965
12966                                 ip += 6;
12967                                 ins_flag = 0;
12968                                 constrained_class = NULL;
12969                                 break;
12970                         }
12971                         default:
12972                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
12973                                 break;
12974                         }
12975                         break;
12976                 }
12977
12978                 case CEE_PREFIX1: {
12979                         CHECK_OPSIZE (2);
12980                         switch (ip [1]) {
12981                         case CEE_ARGLIST: {
12982                                 /* somewhat similar to LDTOKEN */
12983                                 MonoInst *addr, *vtvar;
12984                                 CHECK_STACK_OVF (1);
12985                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
12986
12987                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12988                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
12989
12990                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12991                                 ins->type = STACK_VTYPE;
12992                                 ins->klass = mono_defaults.argumenthandle_class;
12993                                 *sp++ = ins;
12994                                 ip += 2;
12995                                 break;
12996                         }
12997                         case CEE_CEQ:
12998                         case CEE_CGT:
12999                         case CEE_CGT_UN:
13000                         case CEE_CLT:
13001                         case CEE_CLT_UN: {
13002                                 MonoInst *cmp, *arg1, *arg2;
13003
13004                                 CHECK_STACK (2);
13005                                 sp -= 2;
13006                                 arg1 = sp [0];
13007                                 arg2 = sp [1];
13008
13009                                 /*
13010                                  * The following transforms:
13011                                  *    CEE_CEQ    into OP_CEQ
13012                                  *    CEE_CGT    into OP_CGT
13013                                  *    CEE_CGT_UN into OP_CGT_UN
13014                                  *    CEE_CLT    into OP_CLT
13015                                  *    CEE_CLT_UN into OP_CLT_UN
13016                                  */
13017                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
13018
13019                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
13020                                 cmp->sreg1 = arg1->dreg;
13021                                 cmp->sreg2 = arg2->dreg;
13022                                 type_from_op (cfg, cmp, arg1, arg2);
13023                                 CHECK_TYPE (cmp);
13024                                 add_widen_op (cfg, cmp, &arg1, &arg2);
13025                                 if ((arg1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((arg1->type == STACK_PTR) || (arg1->type == STACK_OBJ) || (arg1->type == STACK_MP))))
13026                                         cmp->opcode = OP_LCOMPARE;
13027                                 else if (arg1->type == STACK_R4)
13028                                         cmp->opcode = OP_RCOMPARE;
13029                                 else if (arg1->type == STACK_R8)
13030                                         cmp->opcode = OP_FCOMPARE;
13031                                 else
13032                                         cmp->opcode = OP_ICOMPARE;
13033                                 MONO_ADD_INS (cfg->cbb, cmp);
13034                                 ins->type = STACK_I4;
13035                                 ins->dreg = alloc_dreg (cfg, (MonoStackType)ins->type);
13036                                 type_from_op (cfg, ins, arg1, arg2);
13037
13038                                 if (cmp->opcode == OP_FCOMPARE || cmp->opcode == OP_RCOMPARE) {
13039                                         /*
13040                                          * The backends expect the fceq opcodes to do the
13041                                          * comparison too.
13042                                          */
13043                                         ins->sreg1 = cmp->sreg1;
13044                                         ins->sreg2 = cmp->sreg2;
13045                                         NULLIFY_INS (cmp);
13046                                 }
13047                                 MONO_ADD_INS (cfg->cbb, ins);
13048                                 *sp++ = ins;
13049                                 ip += 2;
13050                                 break;
13051                         }
13052                         case CEE_LDFTN: {
13053                                 MonoInst *argconst;
13054                                 MonoMethod *cil_method;
13055
13056                                 CHECK_STACK_OVF (1);
13057                                 CHECK_OPSIZE (6);
13058                                 n = read32 (ip + 2);
13059                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
13060                                 CHECK_CFG_ERROR;
13061
13062                                 mono_class_init (cmethod->klass);
13063
13064                                 mono_save_token_info (cfg, image, n, cmethod);
13065
13066                                 context_used = mini_method_check_context_used (cfg, cmethod);
13067
13068                                 cil_method = cmethod;
13069                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
13070                                         METHOD_ACCESS_FAILURE (method, cil_method);
13071
13072                                 if (mono_security_core_clr_enabled ())
13073                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
13074
13075                                 /* 
13076                                  * Optimize the common case of ldftn+delegate creation
13077                                  */
13078                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
13079                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
13080                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
13081                                                 MonoInst *target_ins, *handle_ins;
13082                                                 MonoMethod *invoke;
13083                                                 int invoke_context_used;
13084
13085                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
13086                                                 if (!invoke || !mono_method_signature (invoke))
13087                                                         LOAD_ERROR;
13088
13089                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
13090
13091                                                 target_ins = sp [-1];
13092
13093                                                 if (mono_security_core_clr_enabled ())
13094                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
13095
13096                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
13097                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
13098                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
13099                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
13100                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
13101                                                         }
13102                                                 }
13103
13104                                                 /* FIXME: SGEN support */
13105                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
13106                                                         ip += 6;
13107                                                         if (cfg->verbose_level > 3)
13108                                                                 g_print ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
13109                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, FALSE))) {
13110                                                                 sp --;
13111                                                                 *sp = handle_ins;
13112                                                                 CHECK_CFG_EXCEPTION;
13113                                                                 ip += 5;
13114                                                                 sp ++;
13115                                                                 break;
13116                                                         }
13117                                                         ip -= 6;
13118                                                 }
13119                                         }
13120                                 }
13121
13122                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
13123                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
13124                                 *sp++ = ins;
13125                                 
13126                                 ip += 6;
13127                                 inline_costs += 10 * num_calls++;
13128                                 break;
13129                         }
13130                         case CEE_LDVIRTFTN: {
13131                                 MonoInst *args [2];
13132
13133                                 CHECK_STACK (1);
13134                                 CHECK_OPSIZE (6);
13135                                 n = read32 (ip + 2);
13136                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
13137                                 CHECK_CFG_ERROR;
13138
13139                                 mono_class_init (cmethod->klass);
13140  
13141                                 context_used = mini_method_check_context_used (cfg, cmethod);
13142
13143                                 if (mono_security_core_clr_enabled ())
13144                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
13145
13146                                 /*
13147                                  * Optimize the common case of ldvirtftn+delegate creation
13148                                  */
13149                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 6) && (ip [6] == CEE_NEWOBJ) && (ip > header->code && ip [-1] == CEE_DUP)) {
13150                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
13151                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
13152                                                 MonoInst *target_ins, *handle_ins;
13153                                                 MonoMethod *invoke;
13154                                                 int invoke_context_used;
13155                                                 gboolean is_virtual = cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL;
13156
13157                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
13158                                                 if (!invoke || !mono_method_signature (invoke))
13159                                                         LOAD_ERROR;
13160
13161                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
13162
13163                                                 target_ins = sp [-1];
13164
13165                                                 if (mono_security_core_clr_enabled ())
13166                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
13167
13168                                                 /* FIXME: SGEN support */
13169                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
13170                                                         ip += 6;
13171                                                         if (cfg->verbose_level > 3)
13172                                                                 g_print ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
13173                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, is_virtual))) {
13174                                                                 sp -= 2;
13175                                                                 *sp = handle_ins;
13176                                                                 CHECK_CFG_EXCEPTION;
13177                                                                 ip += 5;
13178                                                                 sp ++;
13179                                                                 break;
13180                                                         }
13181                                                         ip -= 6;
13182                                                 }
13183                                         }
13184                                 }
13185
13186                                 --sp;
13187                                 args [0] = *sp;
13188
13189                                 args [1] = emit_get_rgctx_method (cfg, context_used,
13190                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
13191
13192                                 if (context_used)
13193                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
13194                                 else
13195                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
13196
13197                                 ip += 6;
13198                                 inline_costs += 10 * num_calls++;
13199                                 break;
13200                         }
13201                         case CEE_LDARG:
13202                                 CHECK_STACK_OVF (1);
13203                                 CHECK_OPSIZE (4);
13204                                 n = read16 (ip + 2);
13205                                 CHECK_ARG (n);
13206                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
13207                                 *sp++ = ins;
13208                                 ip += 4;
13209                                 break;
13210                         case CEE_LDARGA:
13211                                 CHECK_STACK_OVF (1);
13212                                 CHECK_OPSIZE (4);
13213                                 n = read16 (ip + 2);
13214                                 CHECK_ARG (n);
13215                                 NEW_ARGLOADA (cfg, ins, n);
13216                                 MONO_ADD_INS (cfg->cbb, ins);
13217                                 *sp++ = ins;
13218                                 ip += 4;
13219                                 break;
13220                         case CEE_STARG:
13221                                 CHECK_STACK (1);
13222                                 --sp;
13223                                 CHECK_OPSIZE (4);
13224                                 n = read16 (ip + 2);
13225                                 CHECK_ARG (n);
13226                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
13227                                         UNVERIFIED;
13228                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
13229                                 ip += 4;
13230                                 break;
13231                         case CEE_LDLOC:
13232                                 CHECK_STACK_OVF (1);
13233                                 CHECK_OPSIZE (4);
13234                                 n = read16 (ip + 2);
13235                                 CHECK_LOCAL (n);
13236                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
13237                                 *sp++ = ins;
13238                                 ip += 4;
13239                                 break;
13240                         case CEE_LDLOCA: {
13241                                 unsigned char *tmp_ip;
13242                                 CHECK_STACK_OVF (1);
13243                                 CHECK_OPSIZE (4);
13244                                 n = read16 (ip + 2);
13245                                 CHECK_LOCAL (n);
13246
13247                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
13248                                         ip = tmp_ip;
13249                                         inline_costs += 1;
13250                                         break;
13251                                 }                       
13252                                 
13253                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
13254                                 *sp++ = ins;
13255                                 ip += 4;
13256                                 break;
13257                         }
13258                         case CEE_STLOC:
13259                                 CHECK_STACK (1);
13260                                 --sp;
13261                                 CHECK_OPSIZE (4);
13262                                 n = read16 (ip + 2);
13263                                 CHECK_LOCAL (n);
13264                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
13265                                         UNVERIFIED;
13266                                 emit_stloc_ir (cfg, sp, header, n);
13267                                 ip += 4;
13268                                 inline_costs += 1;
13269                                 break;
13270                         case CEE_LOCALLOC:
13271                                 CHECK_STACK (1);
13272                                 --sp;
13273                                 if (sp != stack_start) 
13274                                         UNVERIFIED;
13275                                 if (cfg->method != method) 
13276                                         /* 
13277                                          * Inlining this into a loop in a parent could lead to 
13278                                          * stack overflows which is different behavior than the
13279                                          * non-inlined case, thus disable inlining in this case.
13280                                          */
13281                                         INLINE_FAILURE("localloc");
13282
13283                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
13284                                 ins->dreg = alloc_preg (cfg);
13285                                 ins->sreg1 = sp [0]->dreg;
13286                                 ins->type = STACK_PTR;
13287                                 MONO_ADD_INS (cfg->cbb, ins);
13288
13289                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
13290                                 if (init_locals)
13291                                         ins->flags |= MONO_INST_INIT;
13292
13293                                 *sp++ = ins;
13294                                 ip += 2;
13295                                 break;
13296                         case CEE_ENDFILTER: {
13297                                 MonoExceptionClause *clause, *nearest;
13298                                 int cc;
13299
13300                                 CHECK_STACK (1);
13301                                 --sp;
13302                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
13303                                         UNVERIFIED;
13304                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
13305                                 ins->sreg1 = (*sp)->dreg;
13306                                 MONO_ADD_INS (cfg->cbb, ins);
13307                                 start_new_bblock = 1;
13308                                 ip += 2;
13309
13310                                 nearest = NULL;
13311                                 for (cc = 0; cc < header->num_clauses; ++cc) {
13312                                         clause = &header->clauses [cc];
13313                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
13314                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
13315                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset)))
13316                                                 nearest = clause;
13317                                 }
13318                                 g_assert (nearest);
13319                                 if ((ip - header->code) != nearest->handler_offset)
13320                                         UNVERIFIED;
13321
13322                                 break;
13323                         }
13324                         case CEE_UNALIGNED_:
13325                                 ins_flag |= MONO_INST_UNALIGNED;
13326                                 /* FIXME: record alignment? we can assume 1 for now */
13327                                 CHECK_OPSIZE (3);
13328                                 ip += 3;
13329                                 break;
13330                         case CEE_VOLATILE_:
13331                                 ins_flag |= MONO_INST_VOLATILE;
13332                                 ip += 2;
13333                                 break;
13334                         case CEE_TAIL_:
13335                                 ins_flag   |= MONO_INST_TAILCALL;
13336                                 cfg->flags |= MONO_CFG_HAS_TAIL;
13337                                 /* Can't inline tail calls at this time */
13338                                 inline_costs += 100000;
13339                                 ip += 2;
13340                                 break;
13341                         case CEE_INITOBJ:
13342                                 CHECK_STACK (1);
13343                                 --sp;
13344                                 CHECK_OPSIZE (6);
13345                                 token = read32 (ip + 2);
13346                                 klass = mini_get_class (method, token, generic_context);
13347                                 CHECK_TYPELOAD (klass);
13348                                 if (generic_class_is_reference_type (cfg, klass))
13349                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
13350                                 else
13351                                         mini_emit_initobj (cfg, *sp, NULL, klass);
13352                                 ip += 6;
13353                                 inline_costs += 1;
13354                                 break;
13355                         case CEE_CONSTRAINED_:
13356                                 CHECK_OPSIZE (6);
13357                                 token = read32 (ip + 2);
13358                                 constrained_class = mini_get_class (method, token, generic_context);
13359                                 CHECK_TYPELOAD (constrained_class);
13360                                 ip += 6;
13361                                 break;
13362                         case CEE_CPBLK:
13363                         case CEE_INITBLK: {
13364                                 MonoInst *iargs [3];
13365                                 CHECK_STACK (3);
13366                                 sp -= 3;
13367
13368                                 /* Skip optimized paths for volatile operations. */
13369                                 if ((ip [1] == CEE_CPBLK) && !(ins_flag & MONO_INST_VOLATILE) && (cfg->opt & MONO_OPT_INTRINS) && (sp [2]->opcode == OP_ICONST) && ((n = sp [2]->inst_c0) <= sizeof (gpointer) * 5)) {
13370                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
13371                                 } else if ((ip [1] == CEE_INITBLK) && !(ins_flag & MONO_INST_VOLATILE) && (cfg->opt & MONO_OPT_INTRINS) && (sp [2]->opcode == OP_ICONST) && ((n = sp [2]->inst_c0) <= sizeof (gpointer) * 5) && (sp [1]->opcode == OP_ICONST) && (sp [1]->inst_c0 == 0)) {
13372                                         /* emit_memset only works when val == 0 */
13373                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
13374                                 } else {
13375                                         MonoInst *call;
13376                                         iargs [0] = sp [0];
13377                                         iargs [1] = sp [1];
13378                                         iargs [2] = sp [2];
13379                                         if (ip [1] == CEE_CPBLK) {
13380                                                 /*
13381                                                  * FIXME: It's unclear whether we should be emitting both the acquire
13382                                                  * and release barriers for cpblk. It is technically both a load and
13383                                                  * store operation, so it seems like that's the sensible thing to do.
13384                                                  *
13385                                                  * FIXME: We emit full barriers on both sides of the operation for
13386                                                  * simplicity. We should have a separate atomic memcpy method instead.
13387                                                  */
13388                                                 MonoMethod *memcpy_method = get_memcpy_method ();
13389
13390                                                 if (ins_flag & MONO_INST_VOLATILE)
13391                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
13392
13393                                                 call = mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
13394                                                 call->flags |= ins_flag;
13395
13396                                                 if (ins_flag & MONO_INST_VOLATILE)
13397                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
13398                                         } else {
13399                                                 MonoMethod *memset_method = get_memset_method ();
13400                                                 if (ins_flag & MONO_INST_VOLATILE) {
13401                                                         /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
13402                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
13403                                                 }
13404                                                 call = mono_emit_method_call (cfg, memset_method, iargs, NULL);
13405                                                 call->flags |= ins_flag;
13406                                         }
13407                                 }
13408                                 ip += 2;
13409                                 ins_flag = 0;
13410                                 inline_costs += 1;
13411                                 break;
13412                         }
13413                         case CEE_NO_:
13414                                 CHECK_OPSIZE (3);
13415                                 if (ip [2] & 0x1)
13416                                         ins_flag |= MONO_INST_NOTYPECHECK;
13417                                 if (ip [2] & 0x2)
13418                                         ins_flag |= MONO_INST_NORANGECHECK;
13419                                 /* we ignore the no-nullcheck for now since we
13420                                  * really do it explicitly only when doing callvirt->call
13421                                  */
13422                                 ip += 3;
13423                                 break;
13424                         case CEE_RETHROW: {
13425                                 MonoInst *load;
13426                                 int handler_offset = -1;
13427
13428                                 for (i = 0; i < header->num_clauses; ++i) {
13429                                         MonoExceptionClause *clause = &header->clauses [i];
13430                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
13431                                                 handler_offset = clause->handler_offset;
13432                                                 break;
13433                                         }
13434                                 }
13435
13436                                 cfg->cbb->flags |= BB_EXCEPTION_UNSAFE;
13437
13438                                 if (handler_offset == -1)
13439                                         UNVERIFIED;
13440
13441                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
13442                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
13443                                 ins->sreg1 = load->dreg;
13444                                 MONO_ADD_INS (cfg->cbb, ins);
13445
13446                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
13447                                 MONO_ADD_INS (cfg->cbb, ins);
13448
13449                                 sp = stack_start;
13450                                 link_bblock (cfg, cfg->cbb, end_bblock);
13451                                 start_new_bblock = 1;
13452                                 ip += 2;
13453                                 break;
13454                         }
13455                         case CEE_SIZEOF: {
13456                                 guint32 val;
13457                                 int ialign;
13458
13459                                 CHECK_STACK_OVF (1);
13460                                 CHECK_OPSIZE (6);
13461                                 token = read32 (ip + 2);
13462                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !image_is_dynamic (method->klass->image) && !generic_context) {
13463                                         MonoType *type = mono_type_create_from_typespec_checked (image, token, &cfg->error);
13464                                         CHECK_CFG_ERROR;
13465
13466                                         val = mono_type_size (type, &ialign);
13467                                 } else {
13468                                         MonoClass *klass = mini_get_class (method, token, generic_context);
13469                                         CHECK_TYPELOAD (klass);
13470
13471                                         val = mono_type_size (&klass->byval_arg, &ialign);
13472
13473                                         if (mini_is_gsharedvt_klass (klass))
13474                                                 GSHAREDVT_FAILURE (*ip);
13475                                 }
13476                                 EMIT_NEW_ICONST (cfg, ins, val);
13477                                 *sp++= ins;
13478                                 ip += 6;
13479                                 break;
13480                         }
13481                         case CEE_REFANYTYPE: {
13482                                 MonoInst *src_var, *src;
13483
13484                                 GSHAREDVT_FAILURE (*ip);
13485
13486                                 CHECK_STACK (1);
13487                                 --sp;
13488
13489                                 // FIXME:
13490                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
13491                                 if (!src_var)
13492                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
13493                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
13494                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type));
13495                                 *sp++ = ins;
13496                                 ip += 2;
13497                                 break;
13498                         }
13499                         case CEE_READONLY_:
13500                                 readonly = TRUE;
13501                                 ip += 2;
13502                                 break;
13503
13504                         case CEE_UNUSED56:
13505                         case CEE_UNUSED57:
13506                         case CEE_UNUSED70:
13507                         case CEE_UNUSED:
13508                         case CEE_UNUSED99:
13509                                 UNVERIFIED;
13510                                 
13511                         default:
13512                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
13513                                 UNVERIFIED;
13514                         }
13515                         break;
13516                 }
13517                 case CEE_UNUSED58:
13518                 case CEE_UNUSED1:
13519                         UNVERIFIED;
13520
13521                 default:
13522                         g_warning ("opcode 0x%02x not handled", *ip);
13523                         UNVERIFIED;
13524                 }
13525         }
13526         if (start_new_bblock != 1)
13527                 UNVERIFIED;
13528
13529         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
13530         if (cfg->cbb->next_bb) {
13531                 /* This could already be set because of inlining, #693905 */
13532                 MonoBasicBlock *bb = cfg->cbb;
13533
13534                 while (bb->next_bb)
13535                         bb = bb->next_bb;
13536                 bb->next_bb = end_bblock;
13537         } else {
13538                 cfg->cbb->next_bb = end_bblock;
13539         }
13540
13541         if (cfg->method == method && cfg->domainvar) {
13542                 MonoInst *store;
13543                 MonoInst *get_domain;
13544
13545                 cfg->cbb = init_localsbb;
13546
13547                 if ((get_domain = mono_get_domain_intrinsic (cfg))) {
13548                         MONO_ADD_INS (cfg->cbb, get_domain);
13549                 } else {
13550                         get_domain = mono_emit_jit_icall (cfg, mono_domain_get, NULL);
13551                 }
13552                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
13553                 MONO_ADD_INS (cfg->cbb, store);
13554         }
13555
13556 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
13557         if (cfg->compile_aot)
13558                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
13559                 mono_get_got_var (cfg);
13560 #endif
13561
13562         if (cfg->method == method && cfg->got_var)
13563                 mono_emit_load_got_addr (cfg);
13564
13565         if (init_localsbb) {
13566                 cfg->cbb = init_localsbb;
13567                 cfg->ip = NULL;
13568                 for (i = 0; i < header->num_locals; ++i) {
13569                         emit_init_local (cfg, i, header->locals [i], init_locals);
13570                 }
13571         }
13572
13573         if (cfg->init_ref_vars && cfg->method == method) {
13574                 /* Emit initialization for ref vars */
13575                 // FIXME: Avoid duplication initialization for IL locals.
13576                 for (i = 0; i < cfg->num_varinfo; ++i) {
13577                         MonoInst *ins = cfg->varinfo [i];
13578
13579                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
13580                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
13581                 }
13582         }
13583
13584         if (cfg->lmf_var && cfg->method == method && !cfg->llvm_only) {
13585                 cfg->cbb = init_localsbb;
13586                 emit_push_lmf (cfg);
13587         }
13588
13589         cfg->cbb = init_localsbb;
13590         emit_instrumentation_call (cfg, mono_profiler_method_enter);
13591
13592         if (seq_points) {
13593                 MonoBasicBlock *bb;
13594
13595                 /*
13596                  * Make seq points at backward branch targets interruptable.
13597                  */
13598                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
13599                         if (bb->code && bb->in_count > 1 && bb->code->opcode == OP_SEQ_POINT)
13600                                 bb->code->flags |= MONO_INST_SINGLE_STEP_LOC;
13601         }
13602
13603         /* Add a sequence point for method entry/exit events */
13604         if (seq_points && cfg->gen_sdb_seq_points) {
13605                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
13606                 MONO_ADD_INS (init_localsbb, ins);
13607                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
13608                 MONO_ADD_INS (cfg->bb_exit, ins);
13609         }
13610
13611         /*
13612          * Add seq points for IL offsets which have line number info, but wasn't generated a seq point during JITting because
13613          * the code they refer to was dead (#11880).
13614          */
13615         if (sym_seq_points) {
13616                 for (i = 0; i < header->code_size; ++i) {
13617                         if (mono_bitset_test_fast (seq_point_locs, i) && !mono_bitset_test_fast (seq_point_set_locs, i)) {
13618                                 MonoInst *ins;
13619
13620                                 NEW_SEQ_POINT (cfg, ins, i, FALSE);
13621                                 mono_add_seq_point (cfg, NULL, ins, SEQ_POINT_NATIVE_OFFSET_DEAD_CODE);
13622                         }
13623                 }
13624         }
13625
13626         cfg->ip = NULL;
13627
13628         if (cfg->method == method) {
13629                 MonoBasicBlock *bb;
13630                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13631                         bb->region = mono_find_block_region (cfg, bb->real_offset);
13632                         if (cfg->spvars)
13633                                 mono_create_spvar_for_region (cfg, bb->region);
13634                         if (cfg->verbose_level > 2)
13635                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
13636                 }
13637         }
13638
13639         if (inline_costs < 0) {
13640                 char *mname;
13641
13642                 /* Method is too large */
13643                 mname = mono_method_full_name (method, TRUE);
13644                 mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Method %s is too complex.", mname));
13645                 g_free (mname);
13646         }
13647
13648         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
13649                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
13650
13651         goto cleanup;
13652
13653 mono_error_exit:
13654         g_assert (!mono_error_ok (&cfg->error));
13655         goto cleanup;
13656  
13657  exception_exit:
13658         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
13659         goto cleanup;
13660
13661  unverified:
13662         set_exception_type_from_invalid_il (cfg, method, ip);
13663         goto cleanup;
13664
13665  cleanup:
13666         g_slist_free (class_inits);
13667         mono_basic_block_free (original_bb);
13668         cfg->dont_inline = g_list_remove (cfg->dont_inline, method);
13669         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
13670         if (cfg->exception_type)
13671                 return -1;
13672         else
13673                 return inline_costs;
13674 }
13675
13676 static int
13677 store_membase_reg_to_store_membase_imm (int opcode)
13678 {
13679         switch (opcode) {
13680         case OP_STORE_MEMBASE_REG:
13681                 return OP_STORE_MEMBASE_IMM;
13682         case OP_STOREI1_MEMBASE_REG:
13683                 return OP_STOREI1_MEMBASE_IMM;
13684         case OP_STOREI2_MEMBASE_REG:
13685                 return OP_STOREI2_MEMBASE_IMM;
13686         case OP_STOREI4_MEMBASE_REG:
13687                 return OP_STOREI4_MEMBASE_IMM;
13688         case OP_STOREI8_MEMBASE_REG:
13689                 return OP_STOREI8_MEMBASE_IMM;
13690         default:
13691                 g_assert_not_reached ();
13692         }
13693
13694         return -1;
13695 }               
13696
13697 int
13698 mono_op_to_op_imm (int opcode)
13699 {
13700         switch (opcode) {
13701         case OP_IADD:
13702                 return OP_IADD_IMM;
13703         case OP_ISUB:
13704                 return OP_ISUB_IMM;
13705         case OP_IDIV:
13706                 return OP_IDIV_IMM;
13707         case OP_IDIV_UN:
13708                 return OP_IDIV_UN_IMM;
13709         case OP_IREM:
13710                 return OP_IREM_IMM;
13711         case OP_IREM_UN:
13712                 return OP_IREM_UN_IMM;
13713         case OP_IMUL:
13714                 return OP_IMUL_IMM;
13715         case OP_IAND:
13716                 return OP_IAND_IMM;
13717         case OP_IOR:
13718                 return OP_IOR_IMM;
13719         case OP_IXOR:
13720                 return OP_IXOR_IMM;
13721         case OP_ISHL:
13722                 return OP_ISHL_IMM;
13723         case OP_ISHR:
13724                 return OP_ISHR_IMM;
13725         case OP_ISHR_UN:
13726                 return OP_ISHR_UN_IMM;
13727
13728         case OP_LADD:
13729                 return OP_LADD_IMM;
13730         case OP_LSUB:
13731                 return OP_LSUB_IMM;
13732         case OP_LAND:
13733                 return OP_LAND_IMM;
13734         case OP_LOR:
13735                 return OP_LOR_IMM;
13736         case OP_LXOR:
13737                 return OP_LXOR_IMM;
13738         case OP_LSHL:
13739                 return OP_LSHL_IMM;
13740         case OP_LSHR:
13741                 return OP_LSHR_IMM;
13742         case OP_LSHR_UN:
13743                 return OP_LSHR_UN_IMM;
13744 #if SIZEOF_REGISTER == 8
13745         case OP_LREM:
13746                 return OP_LREM_IMM;
13747 #endif
13748
13749         case OP_COMPARE:
13750                 return OP_COMPARE_IMM;
13751         case OP_ICOMPARE:
13752                 return OP_ICOMPARE_IMM;
13753         case OP_LCOMPARE:
13754                 return OP_LCOMPARE_IMM;
13755
13756         case OP_STORE_MEMBASE_REG:
13757                 return OP_STORE_MEMBASE_IMM;
13758         case OP_STOREI1_MEMBASE_REG:
13759                 return OP_STOREI1_MEMBASE_IMM;
13760         case OP_STOREI2_MEMBASE_REG:
13761                 return OP_STOREI2_MEMBASE_IMM;
13762         case OP_STOREI4_MEMBASE_REG:
13763                 return OP_STOREI4_MEMBASE_IMM;
13764
13765 #if defined(TARGET_X86) || defined (TARGET_AMD64)
13766         case OP_X86_PUSH:
13767                 return OP_X86_PUSH_IMM;
13768         case OP_X86_COMPARE_MEMBASE_REG:
13769                 return OP_X86_COMPARE_MEMBASE_IMM;
13770 #endif
13771 #if defined(TARGET_AMD64)
13772         case OP_AMD64_ICOMPARE_MEMBASE_REG:
13773                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13774 #endif
13775         case OP_VOIDCALL_REG:
13776                 return OP_VOIDCALL;
13777         case OP_CALL_REG:
13778                 return OP_CALL;
13779         case OP_LCALL_REG:
13780                 return OP_LCALL;
13781         case OP_FCALL_REG:
13782                 return OP_FCALL;
13783         case OP_LOCALLOC:
13784                 return OP_LOCALLOC_IMM;
13785         }
13786
13787         return -1;
13788 }
13789
13790 static int
13791 ldind_to_load_membase (int opcode)
13792 {
13793         switch (opcode) {
13794         case CEE_LDIND_I1:
13795                 return OP_LOADI1_MEMBASE;
13796         case CEE_LDIND_U1:
13797                 return OP_LOADU1_MEMBASE;
13798         case CEE_LDIND_I2:
13799                 return OP_LOADI2_MEMBASE;
13800         case CEE_LDIND_U2:
13801                 return OP_LOADU2_MEMBASE;
13802         case CEE_LDIND_I4:
13803                 return OP_LOADI4_MEMBASE;
13804         case CEE_LDIND_U4:
13805                 return OP_LOADU4_MEMBASE;
13806         case CEE_LDIND_I:
13807                 return OP_LOAD_MEMBASE;
13808         case CEE_LDIND_REF:
13809                 return OP_LOAD_MEMBASE;
13810         case CEE_LDIND_I8:
13811                 return OP_LOADI8_MEMBASE;
13812         case CEE_LDIND_R4:
13813                 return OP_LOADR4_MEMBASE;
13814         case CEE_LDIND_R8:
13815                 return OP_LOADR8_MEMBASE;
13816         default:
13817                 g_assert_not_reached ();
13818         }
13819
13820         return -1;
13821 }
13822
13823 static int
13824 stind_to_store_membase (int opcode)
13825 {
13826         switch (opcode) {
13827         case CEE_STIND_I1:
13828                 return OP_STOREI1_MEMBASE_REG;
13829         case CEE_STIND_I2:
13830                 return OP_STOREI2_MEMBASE_REG;
13831         case CEE_STIND_I4:
13832                 return OP_STOREI4_MEMBASE_REG;
13833         case CEE_STIND_I:
13834         case CEE_STIND_REF:
13835                 return OP_STORE_MEMBASE_REG;
13836         case CEE_STIND_I8:
13837                 return OP_STOREI8_MEMBASE_REG;
13838         case CEE_STIND_R4:
13839                 return OP_STORER4_MEMBASE_REG;
13840         case CEE_STIND_R8:
13841                 return OP_STORER8_MEMBASE_REG;
13842         default:
13843                 g_assert_not_reached ();
13844         }
13845
13846         return -1;
13847 }
13848
13849 int
13850 mono_load_membase_to_load_mem (int opcode)
13851 {
13852         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
13853 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13854         switch (opcode) {
13855         case OP_LOAD_MEMBASE:
13856                 return OP_LOAD_MEM;
13857         case OP_LOADU1_MEMBASE:
13858                 return OP_LOADU1_MEM;
13859         case OP_LOADU2_MEMBASE:
13860                 return OP_LOADU2_MEM;
13861         case OP_LOADI4_MEMBASE:
13862                 return OP_LOADI4_MEM;
13863         case OP_LOADU4_MEMBASE:
13864                 return OP_LOADU4_MEM;
13865 #if SIZEOF_REGISTER == 8
13866         case OP_LOADI8_MEMBASE:
13867                 return OP_LOADI8_MEM;
13868 #endif
13869         }
13870 #endif
13871
13872         return -1;
13873 }
13874
13875 static inline int
13876 op_to_op_dest_membase (int store_opcode, int opcode)
13877 {
13878 #if defined(TARGET_X86)
13879         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
13880                 return -1;
13881
13882         switch (opcode) {
13883         case OP_IADD:
13884                 return OP_X86_ADD_MEMBASE_REG;
13885         case OP_ISUB:
13886                 return OP_X86_SUB_MEMBASE_REG;
13887         case OP_IAND:
13888                 return OP_X86_AND_MEMBASE_REG;
13889         case OP_IOR:
13890                 return OP_X86_OR_MEMBASE_REG;
13891         case OP_IXOR:
13892                 return OP_X86_XOR_MEMBASE_REG;
13893         case OP_ADD_IMM:
13894         case OP_IADD_IMM:
13895                 return OP_X86_ADD_MEMBASE_IMM;
13896         case OP_SUB_IMM:
13897         case OP_ISUB_IMM:
13898                 return OP_X86_SUB_MEMBASE_IMM;
13899         case OP_AND_IMM:
13900         case OP_IAND_IMM:
13901                 return OP_X86_AND_MEMBASE_IMM;
13902         case OP_OR_IMM:
13903         case OP_IOR_IMM:
13904                 return OP_X86_OR_MEMBASE_IMM;
13905         case OP_XOR_IMM:
13906         case OP_IXOR_IMM:
13907                 return OP_X86_XOR_MEMBASE_IMM;
13908         case OP_MOVE:
13909                 return OP_NOP;
13910         }
13911 #endif
13912
13913 #if defined(TARGET_AMD64)
13914         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
13915                 return -1;
13916
13917         switch (opcode) {
13918         case OP_IADD:
13919                 return OP_X86_ADD_MEMBASE_REG;
13920         case OP_ISUB:
13921                 return OP_X86_SUB_MEMBASE_REG;
13922         case OP_IAND:
13923                 return OP_X86_AND_MEMBASE_REG;
13924         case OP_IOR:
13925                 return OP_X86_OR_MEMBASE_REG;
13926         case OP_IXOR:
13927                 return OP_X86_XOR_MEMBASE_REG;
13928         case OP_IADD_IMM:
13929                 return OP_X86_ADD_MEMBASE_IMM;
13930         case OP_ISUB_IMM:
13931                 return OP_X86_SUB_MEMBASE_IMM;
13932         case OP_IAND_IMM:
13933                 return OP_X86_AND_MEMBASE_IMM;
13934         case OP_IOR_IMM:
13935                 return OP_X86_OR_MEMBASE_IMM;
13936         case OP_IXOR_IMM:
13937                 return OP_X86_XOR_MEMBASE_IMM;
13938         case OP_LADD:
13939                 return OP_AMD64_ADD_MEMBASE_REG;
13940         case OP_LSUB:
13941                 return OP_AMD64_SUB_MEMBASE_REG;
13942         case OP_LAND:
13943                 return OP_AMD64_AND_MEMBASE_REG;
13944         case OP_LOR:
13945                 return OP_AMD64_OR_MEMBASE_REG;
13946         case OP_LXOR:
13947                 return OP_AMD64_XOR_MEMBASE_REG;
13948         case OP_ADD_IMM:
13949         case OP_LADD_IMM:
13950                 return OP_AMD64_ADD_MEMBASE_IMM;
13951         case OP_SUB_IMM:
13952         case OP_LSUB_IMM:
13953                 return OP_AMD64_SUB_MEMBASE_IMM;
13954         case OP_AND_IMM:
13955         case OP_LAND_IMM:
13956                 return OP_AMD64_AND_MEMBASE_IMM;
13957         case OP_OR_IMM:
13958         case OP_LOR_IMM:
13959                 return OP_AMD64_OR_MEMBASE_IMM;
13960         case OP_XOR_IMM:
13961         case OP_LXOR_IMM:
13962                 return OP_AMD64_XOR_MEMBASE_IMM;
13963         case OP_MOVE:
13964                 return OP_NOP;
13965         }
13966 #endif
13967
13968         return -1;
13969 }
13970
13971 static inline int
13972 op_to_op_store_membase (int store_opcode, int opcode)
13973 {
13974 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13975         switch (opcode) {
13976         case OP_ICEQ:
13977                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13978                         return OP_X86_SETEQ_MEMBASE;
13979         case OP_CNE:
13980                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13981                         return OP_X86_SETNE_MEMBASE;
13982         }
13983 #endif
13984
13985         return -1;
13986 }
13987
13988 static inline int
13989 op_to_op_src1_membase (MonoCompile *cfg, int load_opcode, int opcode)
13990 {
13991 #ifdef TARGET_X86
13992         /* FIXME: This has sign extension issues */
13993         /*
13994         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13995                 return OP_X86_COMPARE_MEMBASE8_IMM;
13996         */
13997
13998         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13999                 return -1;
14000
14001         switch (opcode) {
14002         case OP_X86_PUSH:
14003                 return OP_X86_PUSH_MEMBASE;
14004         case OP_COMPARE_IMM:
14005         case OP_ICOMPARE_IMM:
14006                 return OP_X86_COMPARE_MEMBASE_IMM;
14007         case OP_COMPARE:
14008         case OP_ICOMPARE:
14009                 return OP_X86_COMPARE_MEMBASE_REG;
14010         }
14011 #endif
14012
14013 #ifdef TARGET_AMD64
14014         /* FIXME: This has sign extension issues */
14015         /*
14016         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
14017                 return OP_X86_COMPARE_MEMBASE8_IMM;
14018         */
14019
14020         switch (opcode) {
14021         case OP_X86_PUSH:
14022                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
14023                         return OP_X86_PUSH_MEMBASE;
14024                 break;
14025                 /* FIXME: This only works for 32 bit immediates
14026         case OP_COMPARE_IMM:
14027         case OP_LCOMPARE_IMM:
14028                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
14029                         return OP_AMD64_COMPARE_MEMBASE_IMM;
14030                 */
14031         case OP_ICOMPARE_IMM:
14032                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
14033                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
14034                 break;
14035         case OP_COMPARE:
14036         case OP_LCOMPARE:
14037                 if (cfg->backend->ilp32 && load_opcode == OP_LOAD_MEMBASE)
14038                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
14039                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
14040                         return OP_AMD64_COMPARE_MEMBASE_REG;
14041                 break;
14042         case OP_ICOMPARE:
14043                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
14044                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
14045                 break;
14046         }
14047 #endif
14048
14049         return -1;
14050 }
14051
14052 static inline int
14053 op_to_op_src2_membase (MonoCompile *cfg, int load_opcode, int opcode)
14054 {
14055 #ifdef TARGET_X86
14056         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
14057                 return -1;
14058         
14059         switch (opcode) {
14060         case OP_COMPARE:
14061         case OP_ICOMPARE:
14062                 return OP_X86_COMPARE_REG_MEMBASE;
14063         case OP_IADD:
14064                 return OP_X86_ADD_REG_MEMBASE;
14065         case OP_ISUB:
14066                 return OP_X86_SUB_REG_MEMBASE;
14067         case OP_IAND:
14068                 return OP_X86_AND_REG_MEMBASE;
14069         case OP_IOR:
14070                 return OP_X86_OR_REG_MEMBASE;
14071         case OP_IXOR:
14072                 return OP_X86_XOR_REG_MEMBASE;
14073         }
14074 #endif
14075
14076 #ifdef TARGET_AMD64
14077         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && cfg->backend->ilp32)) {
14078                 switch (opcode) {
14079                 case OP_ICOMPARE:
14080                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
14081                 case OP_IADD:
14082                         return OP_X86_ADD_REG_MEMBASE;
14083                 case OP_ISUB:
14084                         return OP_X86_SUB_REG_MEMBASE;
14085                 case OP_IAND:
14086                         return OP_X86_AND_REG_MEMBASE;
14087                 case OP_IOR:
14088                         return OP_X86_OR_REG_MEMBASE;
14089                 case OP_IXOR:
14090                         return OP_X86_XOR_REG_MEMBASE;
14091                 }
14092         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32)) {
14093                 switch (opcode) {
14094                 case OP_COMPARE:
14095                 case OP_LCOMPARE:
14096                         return OP_AMD64_COMPARE_REG_MEMBASE;
14097                 case OP_LADD:
14098                         return OP_AMD64_ADD_REG_MEMBASE;
14099                 case OP_LSUB:
14100                         return OP_AMD64_SUB_REG_MEMBASE;
14101                 case OP_LAND:
14102                         return OP_AMD64_AND_REG_MEMBASE;
14103                 case OP_LOR:
14104                         return OP_AMD64_OR_REG_MEMBASE;
14105                 case OP_LXOR:
14106                         return OP_AMD64_XOR_REG_MEMBASE;
14107                 }
14108         }
14109 #endif
14110
14111         return -1;
14112 }
14113
14114 int
14115 mono_op_to_op_imm_noemul (int opcode)
14116 {
14117         switch (opcode) {
14118 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
14119         case OP_LSHR:
14120         case OP_LSHL:
14121         case OP_LSHR_UN:
14122                 return -1;
14123 #endif
14124 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
14125         case OP_IDIV:
14126         case OP_IDIV_UN:
14127         case OP_IREM:
14128         case OP_IREM_UN:
14129                 return -1;
14130 #endif
14131 #if defined(MONO_ARCH_EMULATE_MUL_DIV)
14132         case OP_IMUL:
14133                 return -1;
14134 #endif
14135         default:
14136                 return mono_op_to_op_imm (opcode);
14137         }
14138 }
14139
14140 /**
14141  * mono_handle_global_vregs:
14142  *
14143  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
14144  * for them.
14145  */
14146 void
14147 mono_handle_global_vregs (MonoCompile *cfg)
14148 {
14149         gint32 *vreg_to_bb;
14150         MonoBasicBlock *bb;
14151         int i, pos;
14152
14153         vreg_to_bb = (gint32 *)mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
14154
14155 #ifdef MONO_ARCH_SIMD_INTRINSICS
14156         if (cfg->uses_simd_intrinsics)
14157                 mono_simd_simplify_indirection (cfg);
14158 #endif
14159
14160         /* Find local vregs used in more than one bb */
14161         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
14162                 MonoInst *ins = bb->code;       
14163                 int block_num = bb->block_num;
14164
14165                 if (cfg->verbose_level > 2)
14166                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
14167
14168                 cfg->cbb = bb;
14169                 for (; ins; ins = ins->next) {
14170                         const char *spec = INS_INFO (ins->opcode);
14171                         int regtype = 0, regindex;
14172                         gint32 prev_bb;
14173
14174                         if (G_UNLIKELY (cfg->verbose_level > 2))
14175                                 mono_print_ins (ins);
14176
14177                         g_assert (ins->opcode >= MONO_CEE_LAST);
14178
14179                         for (regindex = 0; regindex < 4; regindex ++) {
14180                                 int vreg = 0;
14181
14182                                 if (regindex == 0) {
14183                                         regtype = spec [MONO_INST_DEST];
14184                                         if (regtype == ' ')
14185                                                 continue;
14186                                         vreg = ins->dreg;
14187                                 } else if (regindex == 1) {
14188                                         regtype = spec [MONO_INST_SRC1];
14189                                         if (regtype == ' ')
14190                                                 continue;
14191                                         vreg = ins->sreg1;
14192                                 } else if (regindex == 2) {
14193                                         regtype = spec [MONO_INST_SRC2];
14194                                         if (regtype == ' ')
14195                                                 continue;
14196                                         vreg = ins->sreg2;
14197                                 } else if (regindex == 3) {
14198                                         regtype = spec [MONO_INST_SRC3];
14199                                         if (regtype == ' ')
14200                                                 continue;
14201                                         vreg = ins->sreg3;
14202                                 }
14203
14204 #if SIZEOF_REGISTER == 4
14205                                 /* In the LLVM case, the long opcodes are not decomposed */
14206                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
14207                                         /*
14208                                          * Since some instructions reference the original long vreg,
14209                                          * and some reference the two component vregs, it is quite hard
14210                                          * to determine when it needs to be global. So be conservative.
14211                                          */
14212                                         if (!get_vreg_to_inst (cfg, vreg)) {
14213                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
14214
14215                                                 if (cfg->verbose_level > 2)
14216                                                         printf ("LONG VREG R%d made global.\n", vreg);
14217                                         }
14218
14219                                         /*
14220                                          * Make the component vregs volatile since the optimizations can
14221                                          * get confused otherwise.
14222                                          */
14223                                         get_vreg_to_inst (cfg, MONO_LVREG_LS (vreg))->flags |= MONO_INST_VOLATILE;
14224                                         get_vreg_to_inst (cfg, MONO_LVREG_MS (vreg))->flags |= MONO_INST_VOLATILE;
14225                                 }
14226 #endif
14227
14228                                 g_assert (vreg != -1);
14229
14230                                 prev_bb = vreg_to_bb [vreg];
14231                                 if (prev_bb == 0) {
14232                                         /* 0 is a valid block num */
14233                                         vreg_to_bb [vreg] = block_num + 1;
14234                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
14235                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
14236                                                 continue;
14237
14238                                         if (!get_vreg_to_inst (cfg, vreg)) {
14239                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14240                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
14241
14242                                                 switch (regtype) {
14243                                                 case 'i':
14244                                                         if (vreg_is_ref (cfg, vreg))
14245                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg);
14246                                                         else
14247                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
14248                                                         break;
14249                                                 case 'l':
14250                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
14251                                                         break;
14252                                                 case 'f':
14253                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
14254                                                         break;
14255                                                 case 'v':
14256                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
14257                                                         break;
14258                                                 default:
14259                                                         g_assert_not_reached ();
14260                                                 }
14261                                         }
14262
14263                                         /* Flag as having been used in more than one bb */
14264                                         vreg_to_bb [vreg] = -1;
14265                                 }
14266                         }
14267                 }
14268         }
14269
14270         /* If a variable is used in only one bblock, convert it into a local vreg */
14271         for (i = 0; i < cfg->num_varinfo; i++) {
14272                 MonoInst *var = cfg->varinfo [i];
14273                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
14274
14275                 switch (var->type) {
14276                 case STACK_I4:
14277                 case STACK_OBJ:
14278                 case STACK_PTR:
14279                 case STACK_MP:
14280                 case STACK_VTYPE:
14281 #if SIZEOF_REGISTER == 8
14282                 case STACK_I8:
14283 #endif
14284 #if !defined(TARGET_X86)
14285                 /* Enabling this screws up the fp stack on x86 */
14286                 case STACK_R8:
14287 #endif
14288                         if (mono_arch_is_soft_float ())
14289                                 break;
14290
14291                         /*
14292                         if (var->type == STACK_VTYPE && cfg->gsharedvt && mini_is_gsharedvt_variable_type (var->inst_vtype))
14293                                 break;
14294                         */
14295
14296                         /* Arguments are implicitly global */
14297                         /* Putting R4 vars into registers doesn't work currently */
14298                         /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
14299                         if ((var->opcode != OP_ARG) && (var != cfg->ret) && !(var->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT)) && (vreg_to_bb [var->dreg] != -1) && (var->klass->byval_arg.type != MONO_TYPE_R4) && !cfg->disable_vreg_to_lvreg && var != cfg->gsharedvt_info_var && var != cfg->gsharedvt_locals_var && var != cfg->lmf_addr_var) {
14300                                 /* 
14301                                  * Make that the variable's liveness interval doesn't contain a call, since
14302                                  * that would cause the lvreg to be spilled, making the whole optimization
14303                                  * useless.
14304                                  */
14305                                 /* This is too slow for JIT compilation */
14306 #if 0
14307                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
14308                                         MonoInst *ins;
14309                                         int def_index, call_index, ins_index;
14310                                         gboolean spilled = FALSE;
14311
14312                                         def_index = -1;
14313                                         call_index = -1;
14314                                         ins_index = 0;
14315                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
14316                                                 const char *spec = INS_INFO (ins->opcode);
14317
14318                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
14319                                                         def_index = ins_index;
14320
14321                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
14322                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
14323                                                         if (call_index > def_index) {
14324                                                                 spilled = TRUE;
14325                                                                 break;
14326                                                         }
14327                                                 }
14328
14329                                                 if (MONO_IS_CALL (ins))
14330                                                         call_index = ins_index;
14331
14332                                                 ins_index ++;
14333                                         }
14334
14335                                         if (spilled)
14336                                                 break;
14337                                 }
14338 #endif
14339
14340                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14341                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
14342                                 var->flags |= MONO_INST_IS_DEAD;
14343                                 cfg->vreg_to_inst [var->dreg] = NULL;
14344                         }
14345                         break;
14346                 }
14347         }
14348
14349         /* 
14350          * Compress the varinfo and vars tables so the liveness computation is faster and
14351          * takes up less space.
14352          */
14353         pos = 0;
14354         for (i = 0; i < cfg->num_varinfo; ++i) {
14355                 MonoInst *var = cfg->varinfo [i];
14356                 if (pos < i && cfg->locals_start == i)
14357                         cfg->locals_start = pos;
14358                 if (!(var->flags & MONO_INST_IS_DEAD)) {
14359                         if (pos < i) {
14360                                 cfg->varinfo [pos] = cfg->varinfo [i];
14361                                 cfg->varinfo [pos]->inst_c0 = pos;
14362                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
14363                                 cfg->vars [pos].idx = pos;
14364 #if SIZEOF_REGISTER == 4
14365                                 if (cfg->varinfo [pos]->type == STACK_I8) {
14366                                         /* Modify the two component vars too */
14367                                         MonoInst *var1;
14368
14369                                         var1 = get_vreg_to_inst (cfg, MONO_LVREG_LS (cfg->varinfo [pos]->dreg));
14370                                         var1->inst_c0 = pos;
14371                                         var1 = get_vreg_to_inst (cfg, MONO_LVREG_MS (cfg->varinfo [pos]->dreg));
14372                                         var1->inst_c0 = pos;
14373                                 }
14374 #endif
14375                         }
14376                         pos ++;
14377                 }
14378         }
14379         cfg->num_varinfo = pos;
14380         if (cfg->locals_start > cfg->num_varinfo)
14381                 cfg->locals_start = cfg->num_varinfo;
14382 }
14383
14384 /*
14385  * mono_allocate_gsharedvt_vars:
14386  *
14387  *   Allocate variables with gsharedvt types to entries in the MonoGSharedVtMethodRuntimeInfo.entries array.
14388  * Initialize cfg->gsharedvt_vreg_to_idx with the mapping between vregs and indexes.
14389  */
14390 void
14391 mono_allocate_gsharedvt_vars (MonoCompile *cfg)
14392 {
14393         int i;
14394
14395         cfg->gsharedvt_vreg_to_idx = (int *)mono_mempool_alloc0 (cfg->mempool, sizeof (int) * cfg->next_vreg);
14396
14397         for (i = 0; i < cfg->num_varinfo; ++i) {
14398                 MonoInst *ins = cfg->varinfo [i];
14399                 int idx;
14400
14401                 if (mini_is_gsharedvt_variable_type (ins->inst_vtype)) {
14402                         if (i >= cfg->locals_start) {
14403                                 /* Local */
14404                                 idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
14405                                 cfg->gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
14406                                 ins->opcode = OP_GSHAREDVT_LOCAL;
14407                                 ins->inst_imm = idx;
14408                         } else {
14409                                 /* Arg */
14410                                 cfg->gsharedvt_vreg_to_idx [ins->dreg] = -1;
14411                                 ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
14412                         }
14413                 }
14414         }
14415 }
14416
14417 /**
14418  * mono_spill_global_vars:
14419  *
14420  *   Generate spill code for variables which are not allocated to registers, 
14421  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
14422  * code is generated which could be optimized by the local optimization passes.
14423  */
14424 void
14425 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
14426 {
14427         MonoBasicBlock *bb;
14428         char spec2 [16];
14429         int orig_next_vreg;
14430         guint32 *vreg_to_lvreg;
14431         guint32 *lvregs;
14432         guint32 i, lvregs_len;
14433         gboolean dest_has_lvreg = FALSE;
14434         MonoStackType stacktypes [128];
14435         MonoInst **live_range_start, **live_range_end;
14436         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
14437
14438         *need_local_opts = FALSE;
14439
14440         memset (spec2, 0, sizeof (spec2));
14441
14442         /* FIXME: Move this function to mini.c */
14443         stacktypes ['i'] = STACK_PTR;
14444         stacktypes ['l'] = STACK_I8;
14445         stacktypes ['f'] = STACK_R8;
14446 #ifdef MONO_ARCH_SIMD_INTRINSICS
14447         stacktypes ['x'] = STACK_VTYPE;
14448 #endif
14449
14450 #if SIZEOF_REGISTER == 4
14451         /* Create MonoInsts for longs */
14452         for (i = 0; i < cfg->num_varinfo; i++) {
14453                 MonoInst *ins = cfg->varinfo [i];
14454
14455                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
14456                         switch (ins->type) {
14457                         case STACK_R8:
14458                         case STACK_I8: {
14459                                 MonoInst *tree;
14460
14461                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
14462                                         break;
14463
14464                                 g_assert (ins->opcode == OP_REGOFFSET);
14465
14466                                 tree = get_vreg_to_inst (cfg, MONO_LVREG_LS (ins->dreg));
14467                                 g_assert (tree);
14468                                 tree->opcode = OP_REGOFFSET;
14469                                 tree->inst_basereg = ins->inst_basereg;
14470                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
14471
14472                                 tree = get_vreg_to_inst (cfg, MONO_LVREG_MS (ins->dreg));
14473                                 g_assert (tree);
14474                                 tree->opcode = OP_REGOFFSET;
14475                                 tree->inst_basereg = ins->inst_basereg;
14476                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
14477                                 break;
14478                         }
14479                         default:
14480                                 break;
14481                         }
14482                 }
14483         }
14484 #endif
14485
14486         if (cfg->compute_gc_maps) {
14487                 /* registers need liveness info even for !non refs */
14488                 for (i = 0; i < cfg->num_varinfo; i++) {
14489                         MonoInst *ins = cfg->varinfo [i];
14490
14491                         if (ins->opcode == OP_REGVAR)
14492                                 ins->flags |= MONO_INST_GC_TRACK;
14493                 }
14494         }
14495                 
14496         /* FIXME: widening and truncation */
14497
14498         /*
14499          * As an optimization, when a variable allocated to the stack is first loaded into 
14500          * an lvreg, we will remember the lvreg and use it the next time instead of loading
14501          * the variable again.
14502          */
14503         orig_next_vreg = cfg->next_vreg;
14504         vreg_to_lvreg = (guint32 *)mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
14505         lvregs = (guint32 *)mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
14506         lvregs_len = 0;
14507
14508         /* 
14509          * These arrays contain the first and last instructions accessing a given
14510          * variable.
14511          * Since we emit bblocks in the same order we process them here, and we
14512          * don't split live ranges, these will precisely describe the live range of
14513          * the variable, i.e. the instruction range where a valid value can be found
14514          * in the variables location.
14515          * The live range is computed using the liveness info computed by the liveness pass.
14516          * We can't use vmv->range, since that is an abstract live range, and we need
14517          * one which is instruction precise.
14518          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
14519          */
14520         /* FIXME: Only do this if debugging info is requested */
14521         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
14522         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
14523         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
14524         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
14525         
14526         /* Add spill loads/stores */
14527         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
14528                 MonoInst *ins;
14529
14530                 if (cfg->verbose_level > 2)
14531                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
14532
14533                 /* Clear vreg_to_lvreg array */
14534                 for (i = 0; i < lvregs_len; i++)
14535                         vreg_to_lvreg [lvregs [i]] = 0;
14536                 lvregs_len = 0;
14537
14538                 cfg->cbb = bb;
14539                 MONO_BB_FOR_EACH_INS (bb, ins) {
14540                         const char *spec = INS_INFO (ins->opcode);
14541                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
14542                         gboolean store, no_lvreg;
14543                         int sregs [MONO_MAX_SRC_REGS];
14544
14545                         if (G_UNLIKELY (cfg->verbose_level > 2))
14546                                 mono_print_ins (ins);
14547
14548                         if (ins->opcode == OP_NOP)
14549                                 continue;
14550
14551                         /* 
14552                          * We handle LDADDR here as well, since it can only be decomposed
14553                          * when variable addresses are known.
14554                          */
14555                         if (ins->opcode == OP_LDADDR) {
14556                                 MonoInst *var = (MonoInst *)ins->inst_p0;
14557
14558                                 if (var->opcode == OP_VTARG_ADDR) {
14559                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
14560                                         MonoInst *vtaddr = var->inst_left;
14561                                         if (vtaddr->opcode == OP_REGVAR) {
14562                                                 ins->opcode = OP_MOVE;
14563                                                 ins->sreg1 = vtaddr->dreg;
14564                                         }
14565                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
14566                                                 ins->opcode = OP_LOAD_MEMBASE;
14567                                                 ins->inst_basereg = vtaddr->inst_basereg;
14568                                                 ins->inst_offset = vtaddr->inst_offset;
14569                                         } else
14570                                                 NOT_IMPLEMENTED;
14571                                 } else if (cfg->gsharedvt && cfg->gsharedvt_vreg_to_idx [var->dreg] < 0) {
14572                                         /* gsharedvt arg passed by ref */
14573                                         g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
14574
14575                                         ins->opcode = OP_LOAD_MEMBASE;
14576                                         ins->inst_basereg = var->inst_basereg;
14577                                         ins->inst_offset = var->inst_offset;
14578                                 } else if (cfg->gsharedvt && cfg->gsharedvt_vreg_to_idx [var->dreg]) {
14579                                         MonoInst *load, *load2, *load3;
14580                                         int idx = cfg->gsharedvt_vreg_to_idx [var->dreg] - 1;
14581                                         int reg1, reg2, reg3;
14582                                         MonoInst *info_var = cfg->gsharedvt_info_var;
14583                                         MonoInst *locals_var = cfg->gsharedvt_locals_var;
14584
14585                                         /*
14586                                          * gsharedvt local.
14587                                          * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
14588                                          */
14589
14590                                         g_assert (var->opcode == OP_GSHAREDVT_LOCAL);
14591
14592                                         g_assert (info_var);
14593                                         g_assert (locals_var);
14594
14595                                         /* Mark the instruction used to compute the locals var as used */
14596                                         cfg->gsharedvt_locals_var_ins = NULL;
14597
14598                                         /* Load the offset */
14599                                         if (info_var->opcode == OP_REGOFFSET) {
14600                                                 reg1 = alloc_ireg (cfg);
14601                                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, reg1, info_var->inst_basereg, info_var->inst_offset);
14602                                         } else if (info_var->opcode == OP_REGVAR) {
14603                                                 load = NULL;
14604                                                 reg1 = info_var->dreg;
14605                                         } else {
14606                                                 g_assert_not_reached ();
14607                                         }
14608                                         reg2 = alloc_ireg (cfg);
14609                                         NEW_LOAD_MEMBASE (cfg, load2, OP_LOADI4_MEMBASE, reg2, reg1, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
14610                                         /* Load the locals area address */
14611                                         reg3 = alloc_ireg (cfg);
14612                                         if (locals_var->opcode == OP_REGOFFSET) {
14613                                                 NEW_LOAD_MEMBASE (cfg, load3, OP_LOAD_MEMBASE, reg3, locals_var->inst_basereg, locals_var->inst_offset);
14614                                         } else if (locals_var->opcode == OP_REGVAR) {
14615                                                 NEW_UNALU (cfg, load3, OP_MOVE, reg3, locals_var->dreg);
14616                                         } else {
14617                                                 g_assert_not_reached ();
14618                                         }
14619                                         /* Compute the address */
14620                                         ins->opcode = OP_PADD;
14621                                         ins->sreg1 = reg3;
14622                                         ins->sreg2 = reg2;
14623
14624                                         mono_bblock_insert_before_ins (bb, ins, load3);
14625                                         mono_bblock_insert_before_ins (bb, load3, load2);
14626                                         if (load)
14627                                                 mono_bblock_insert_before_ins (bb, load2, load);
14628                                 } else {
14629                                         g_assert (var->opcode == OP_REGOFFSET);
14630
14631                                         ins->opcode = OP_ADD_IMM;
14632                                         ins->sreg1 = var->inst_basereg;
14633                                         ins->inst_imm = var->inst_offset;
14634                                 }
14635
14636                                 *need_local_opts = TRUE;
14637                                 spec = INS_INFO (ins->opcode);
14638                         }
14639
14640                         if (ins->opcode < MONO_CEE_LAST) {
14641                                 mono_print_ins (ins);
14642                                 g_assert_not_reached ();
14643                         }
14644
14645                         /*
14646                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
14647                          * src register.
14648                          * FIXME:
14649                          */
14650                         if (MONO_IS_STORE_MEMBASE (ins)) {
14651                                 tmp_reg = ins->dreg;
14652                                 ins->dreg = ins->sreg2;
14653                                 ins->sreg2 = tmp_reg;
14654                                 store = TRUE;
14655
14656                                 spec2 [MONO_INST_DEST] = ' ';
14657                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14658                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14659                                 spec2 [MONO_INST_SRC3] = ' ';
14660                                 spec = spec2;
14661                         } else if (MONO_IS_STORE_MEMINDEX (ins))
14662                                 g_assert_not_reached ();
14663                         else
14664                                 store = FALSE;
14665                         no_lvreg = FALSE;
14666
14667                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
14668                                 printf ("\t %.3s %d", spec, ins->dreg);
14669                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
14670                                 for (srcindex = 0; srcindex < num_sregs; ++srcindex)
14671                                         printf (" %d", sregs [srcindex]);
14672                                 printf ("\n");
14673                         }
14674
14675                         /***************/
14676                         /*    DREG     */
14677                         /***************/
14678                         regtype = spec [MONO_INST_DEST];
14679                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
14680                         prev_dreg = -1;
14681
14682                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
14683                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
14684                                 MonoInst *store_ins;
14685                                 int store_opcode;
14686                                 MonoInst *def_ins = ins;
14687                                 int dreg = ins->dreg; /* The original vreg */
14688
14689                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
14690
14691                                 if (var->opcode == OP_REGVAR) {
14692                                         ins->dreg = var->dreg;
14693                                 } else if ((ins->dreg == ins->sreg1) && (spec [MONO_INST_DEST] == 'i') && (spec [MONO_INST_SRC1] == 'i') && !vreg_to_lvreg [ins->dreg] && (op_to_op_dest_membase (store_opcode, ins->opcode) != -1)) {
14694                                         /* 
14695                                          * Instead of emitting a load+store, use a _membase opcode.
14696                                          */
14697                                         g_assert (var->opcode == OP_REGOFFSET);
14698                                         if (ins->opcode == OP_MOVE) {
14699                                                 NULLIFY_INS (ins);
14700                                                 def_ins = NULL;
14701                                         } else {
14702                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
14703                                                 ins->inst_basereg = var->inst_basereg;
14704                                                 ins->inst_offset = var->inst_offset;
14705                                                 ins->dreg = -1;
14706                                         }
14707                                         spec = INS_INFO (ins->opcode);
14708                                 } else {
14709                                         guint32 lvreg;
14710
14711                                         g_assert (var->opcode == OP_REGOFFSET);
14712
14713                                         prev_dreg = ins->dreg;
14714
14715                                         /* Invalidate any previous lvreg for this vreg */
14716                                         vreg_to_lvreg [ins->dreg] = 0;
14717
14718                                         lvreg = 0;
14719
14720                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
14721                                                 regtype = 'l';
14722                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
14723                                         }
14724
14725                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
14726
14727 #if SIZEOF_REGISTER != 8
14728                                         if (regtype == 'l') {
14729                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET, MONO_LVREG_LS (ins->dreg));
14730                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14731                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET, MONO_LVREG_MS (ins->dreg));
14732                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14733                                                 def_ins = store_ins;
14734                                         }
14735                                         else
14736 #endif
14737                                         {
14738                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
14739
14740                                                 /* Try to fuse the store into the instruction itself */
14741                                                 /* FIXME: Add more instructions */
14742                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
14743                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
14744                                                         ins->inst_imm = ins->inst_c0;
14745                                                         ins->inst_destbasereg = var->inst_basereg;
14746                                                         ins->inst_offset = var->inst_offset;
14747                                                         spec = INS_INFO (ins->opcode);
14748                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE) || (ins->opcode == OP_RMOVE))) {
14749                                                         ins->opcode = store_opcode;
14750                                                         ins->inst_destbasereg = var->inst_basereg;
14751                                                         ins->inst_offset = var->inst_offset;
14752
14753                                                         no_lvreg = TRUE;
14754
14755                                                         tmp_reg = ins->dreg;
14756                                                         ins->dreg = ins->sreg2;
14757                                                         ins->sreg2 = tmp_reg;
14758                                                         store = TRUE;
14759
14760                                                         spec2 [MONO_INST_DEST] = ' ';
14761                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14762                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14763                                                         spec2 [MONO_INST_SRC3] = ' ';
14764                                                         spec = spec2;
14765                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
14766                                                         // FIXME: The backends expect the base reg to be in inst_basereg
14767                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
14768                                                         ins->dreg = -1;
14769                                                         ins->inst_basereg = var->inst_basereg;
14770                                                         ins->inst_offset = var->inst_offset;
14771                                                         spec = INS_INFO (ins->opcode);
14772                                                 } else {
14773                                                         /* printf ("INS: "); mono_print_ins (ins); */
14774                                                         /* Create a store instruction */
14775                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
14776
14777                                                         /* Insert it after the instruction */
14778                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
14779
14780                                                         def_ins = store_ins;
14781
14782                                                         /* 
14783                                                          * We can't assign ins->dreg to var->dreg here, since the
14784                                                          * sregs could use it. So set a flag, and do it after
14785                                                          * the sregs.
14786                                                          */
14787                                                         if ((!cfg->backend->use_fpstack || ((store_opcode != OP_STORER8_MEMBASE_REG) && (store_opcode != OP_STORER4_MEMBASE_REG))) && !((var)->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT)))
14788                                                                 dest_has_lvreg = TRUE;
14789                                                 }
14790                                         }
14791                                 }
14792
14793                                 if (def_ins && !live_range_start [dreg]) {
14794                                         live_range_start [dreg] = def_ins;
14795                                         live_range_start_bb [dreg] = bb;
14796                                 }
14797
14798                                 if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) {
14799                                         MonoInst *tmp;
14800
14801                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
14802                                         tmp->inst_c1 = dreg;
14803                                         mono_bblock_insert_after_ins (bb, def_ins, tmp);
14804                                 }
14805                         }
14806
14807                         /************/
14808                         /*  SREGS   */
14809                         /************/
14810                         num_sregs = mono_inst_get_src_registers (ins, sregs);
14811                         for (srcindex = 0; srcindex < 3; ++srcindex) {
14812                                 regtype = spec [MONO_INST_SRC1 + srcindex];
14813                                 sreg = sregs [srcindex];
14814
14815                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
14816                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
14817                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
14818                                         MonoInst *use_ins = ins;
14819                                         MonoInst *load_ins;
14820                                         guint32 load_opcode;
14821
14822                                         if (var->opcode == OP_REGVAR) {
14823                                                 sregs [srcindex] = var->dreg;
14824                                                 //mono_inst_set_src_registers (ins, sregs);
14825                                                 live_range_end [sreg] = use_ins;
14826                                                 live_range_end_bb [sreg] = bb;
14827
14828                                                 if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14829                                                         MonoInst *tmp;
14830
14831                                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14832                                                         /* var->dreg is a hreg */
14833                                                         tmp->inst_c1 = sreg;
14834                                                         mono_bblock_insert_after_ins (bb, ins, tmp);
14835                                                 }
14836
14837                                                 continue;
14838                                         }
14839
14840                                         g_assert (var->opcode == OP_REGOFFSET);
14841                                                 
14842                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
14843
14844                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
14845
14846                                         if (vreg_to_lvreg [sreg]) {
14847                                                 g_assert (vreg_to_lvreg [sreg] != -1);
14848
14849                                                 /* The variable is already loaded to an lvreg */
14850                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14851                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
14852                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
14853                                                 //mono_inst_set_src_registers (ins, sregs);
14854                                                 continue;
14855                                         }
14856
14857                                         /* Try to fuse the load into the instruction */
14858                                         if ((srcindex == 0) && (op_to_op_src1_membase (cfg, load_opcode, ins->opcode) != -1)) {
14859                                                 ins->opcode = op_to_op_src1_membase (cfg, load_opcode, ins->opcode);
14860                                                 sregs [0] = var->inst_basereg;
14861                                                 //mono_inst_set_src_registers (ins, sregs);
14862                                                 ins->inst_offset = var->inst_offset;
14863                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (cfg, load_opcode, ins->opcode) != -1)) {
14864                                                 ins->opcode = op_to_op_src2_membase (cfg, load_opcode, ins->opcode);
14865                                                 sregs [1] = var->inst_basereg;
14866                                                 //mono_inst_set_src_registers (ins, sregs);
14867                                                 ins->inst_offset = var->inst_offset;
14868                                         } else {
14869                                                 if (MONO_IS_REAL_MOVE (ins)) {
14870                                                         ins->opcode = OP_NOP;
14871                                                         sreg = ins->dreg;
14872                                                 } else {
14873                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
14874
14875                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
14876
14877                                                         if ((!cfg->backend->use_fpstack || ((load_opcode != OP_LOADR8_MEMBASE) && (load_opcode != OP_LOADR4_MEMBASE))) && !((var)->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT)) && !no_lvreg) {
14878                                                                 if (var->dreg == prev_dreg) {
14879                                                                         /*
14880                                                                          * sreg refers to the value loaded by the load
14881                                                                          * emitted below, but we need to use ins->dreg
14882                                                                          * since it refers to the store emitted earlier.
14883                                                                          */
14884                                                                         sreg = ins->dreg;
14885                                                                 }
14886                                                                 g_assert (sreg != -1);
14887                                                                 vreg_to_lvreg [var->dreg] = sreg;
14888                                                                 g_assert (lvregs_len < 1024);
14889                                                                 lvregs [lvregs_len ++] = var->dreg;
14890                                                         }
14891                                                 }
14892
14893                                                 sregs [srcindex] = sreg;
14894                                                 //mono_inst_set_src_registers (ins, sregs);
14895
14896 #if SIZEOF_REGISTER != 8
14897                                                 if (regtype == 'l') {
14898                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, MONO_LVREG_MS (sreg), var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
14899                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14900                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, MONO_LVREG_LS (sreg), var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
14901                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14902                                                         use_ins = load_ins;
14903                                                 }
14904                                                 else
14905 #endif
14906                                                 {
14907 #if SIZEOF_REGISTER == 4
14908                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
14909 #endif
14910                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
14911                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14912                                                         use_ins = load_ins;
14913                                                 }
14914                                         }
14915
14916                                         if (var->dreg < orig_next_vreg) {
14917                                                 live_range_end [var->dreg] = use_ins;
14918                                                 live_range_end_bb [var->dreg] = bb;
14919                                         }
14920
14921                                         if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14922                                                 MonoInst *tmp;
14923
14924                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14925                                                 tmp->inst_c1 = var->dreg;
14926                                                 mono_bblock_insert_after_ins (bb, ins, tmp);
14927                                         }
14928                                 }
14929                         }
14930                         mono_inst_set_src_registers (ins, sregs);
14931
14932                         if (dest_has_lvreg) {
14933                                 g_assert (ins->dreg != -1);
14934                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
14935                                 g_assert (lvregs_len < 1024);
14936                                 lvregs [lvregs_len ++] = prev_dreg;
14937                                 dest_has_lvreg = FALSE;
14938                         }
14939
14940                         if (store) {
14941                                 tmp_reg = ins->dreg;
14942                                 ins->dreg = ins->sreg2;
14943                                 ins->sreg2 = tmp_reg;
14944                         }
14945
14946                         if (MONO_IS_CALL (ins)) {
14947                                 /* Clear vreg_to_lvreg array */
14948                                 for (i = 0; i < lvregs_len; i++)
14949                                         vreg_to_lvreg [lvregs [i]] = 0;
14950                                 lvregs_len = 0;
14951                         } else if (ins->opcode == OP_NOP) {
14952                                 ins->dreg = -1;
14953                                 MONO_INST_NULLIFY_SREGS (ins);
14954                         }
14955
14956                         if (cfg->verbose_level > 2)
14957                                 mono_print_ins_index (1, ins);
14958                 }
14959
14960                 /* Extend the live range based on the liveness info */
14961                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
14962                         for (i = 0; i < cfg->num_varinfo; i ++) {
14963                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
14964
14965                                 if (vreg_is_volatile (cfg, vi->vreg))
14966                                         /* The liveness info is incomplete */
14967                                         continue;
14968
14969                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
14970                                         /* Live from at least the first ins of this bb */
14971                                         live_range_start [vi->vreg] = bb->code;
14972                                         live_range_start_bb [vi->vreg] = bb;
14973                                 }
14974
14975                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
14976                                         /* Live at least until the last ins of this bb */
14977                                         live_range_end [vi->vreg] = bb->last_ins;
14978                                         live_range_end_bb [vi->vreg] = bb;
14979                                 }
14980                         }
14981                 }
14982         }
14983         
14984         /*
14985          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
14986          * by storing the current native offset into MonoMethodVar->live_range_start/end.
14987          */
14988         if (cfg->backend->have_liverange_ops && cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
14989                 for (i = 0; i < cfg->num_varinfo; ++i) {
14990                         int vreg = MONO_VARINFO (cfg, i)->vreg;
14991                         MonoInst *ins;
14992
14993                         if (live_range_start [vreg]) {
14994                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
14995                                 ins->inst_c0 = i;
14996                                 ins->inst_c1 = vreg;
14997                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
14998                         }
14999                         if (live_range_end [vreg]) {
15000                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
15001                                 ins->inst_c0 = i;
15002                                 ins->inst_c1 = vreg;
15003                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
15004                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
15005                                 else
15006                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
15007                         }
15008                 }
15009         }
15010
15011         if (cfg->gsharedvt_locals_var_ins) {
15012                 /* Nullify if unused */
15013                 cfg->gsharedvt_locals_var_ins->opcode = OP_PCONST;
15014                 cfg->gsharedvt_locals_var_ins->inst_imm = 0;
15015         }
15016
15017         g_free (live_range_start);
15018         g_free (live_range_end);
15019         g_free (live_range_start_bb);
15020         g_free (live_range_end_bb);
15021 }
15022
15023 /**
15024  * FIXME:
15025  * - use 'iadd' instead of 'int_add'
15026  * - handling ovf opcodes: decompose in method_to_ir.
15027  * - unify iregs/fregs
15028  *   -> partly done, the missing parts are:
15029  *   - a more complete unification would involve unifying the hregs as well, so
15030  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
15031  *     would no longer map to the machine hregs, so the code generators would need to
15032  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
15033  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
15034  *     fp/non-fp branches speeds it up by about 15%.
15035  * - use sext/zext opcodes instead of shifts
15036  * - add OP_ICALL
15037  * - get rid of TEMPLOADs if possible and use vregs instead
15038  * - clean up usage of OP_P/OP_ opcodes
15039  * - cleanup usage of DUMMY_USE
15040  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
15041  *   stack
15042  * - set the stack type and allocate a dreg in the EMIT_NEW macros
15043  * - get rid of all the <foo>2 stuff when the new JIT is ready.
15044  * - make sure handle_stack_args () is called before the branch is emitted
15045  * - when the new IR is done, get rid of all unused stuff
15046  * - COMPARE/BEQ as separate instructions or unify them ?
15047  *   - keeping them separate allows specialized compare instructions like
15048  *     compare_imm, compare_membase
15049  *   - most back ends unify fp compare+branch, fp compare+ceq
15050  * - integrate mono_save_args into inline_method
15051  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
15052  * - handle long shift opts on 32 bit platforms somehow: they require 
15053  *   3 sregs (2 for arg1 and 1 for arg2)
15054  * - make byref a 'normal' type.
15055  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
15056  *   variable if needed.
15057  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
15058  *   like inline_method.
15059  * - remove inlining restrictions
15060  * - fix LNEG and enable cfold of INEG
15061  * - generalize x86 optimizations like ldelema as a peephole optimization
15062  * - add store_mem_imm for amd64
15063  * - optimize the loading of the interruption flag in the managed->native wrappers
15064  * - avoid special handling of OP_NOP in passes
15065  * - move code inserting instructions into one function/macro.
15066  * - try a coalescing phase after liveness analysis
15067  * - add float -> vreg conversion + local optimizations on !x86
15068  * - figure out how to handle decomposed branches during optimizations, ie.
15069  *   compare+branch, op_jump_table+op_br etc.
15070  * - promote RuntimeXHandles to vregs
15071  * - vtype cleanups:
15072  *   - add a NEW_VARLOADA_VREG macro
15073  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
15074  *   accessing vtype fields.
15075  * - get rid of I8CONST on 64 bit platforms
15076  * - dealing with the increase in code size due to branches created during opcode
15077  *   decomposition:
15078  *   - use extended basic blocks
15079  *     - all parts of the JIT
15080  *     - handle_global_vregs () && local regalloc
15081  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
15082  * - sources of increase in code size:
15083  *   - vtypes
15084  *   - long compares
15085  *   - isinst and castclass
15086  *   - lvregs not allocated to global registers even if used multiple times
15087  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
15088  *   meaningful.
15089  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
15090  * - add all micro optimizations from the old JIT
15091  * - put tree optimizations into the deadce pass
15092  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
15093  *   specific function.
15094  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
15095  *   fcompare + branchCC.
15096  * - create a helper function for allocating a stack slot, taking into account 
15097  *   MONO_CFG_HAS_SPILLUP.
15098  * - merge r68207.
15099  * - merge the ia64 switch changes.
15100  * - optimize mono_regstate2_alloc_int/float.
15101  * - fix the pessimistic handling of variables accessed in exception handler blocks.
15102  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
15103  *   parts of the tree could be separated by other instructions, killing the tree
15104  *   arguments, or stores killing loads etc. Also, should we fold loads into other
15105  *   instructions if the result of the load is used multiple times ?
15106  * - make the REM_IMM optimization in mini-x86.c arch-independent.
15107  * - LAST MERGE: 108395.
15108  * - when returning vtypes in registers, generate IR and append it to the end of the
15109  *   last bb instead of doing it in the epilog.
15110  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
15111  */
15112
15113 /*
15114
15115 NOTES
15116 -----
15117
15118 - When to decompose opcodes:
15119   - earlier: this makes some optimizations hard to implement, since the low level IR
15120   no longer contains the neccessary information. But it is easier to do.
15121   - later: harder to implement, enables more optimizations.
15122 - Branches inside bblocks:
15123   - created when decomposing complex opcodes. 
15124     - branches to another bblock: harmless, but not tracked by the branch 
15125       optimizations, so need to branch to a label at the start of the bblock.
15126     - branches to inside the same bblock: very problematic, trips up the local
15127       reg allocator. Can be fixed by spitting the current bblock, but that is a
15128       complex operation, since some local vregs can become global vregs etc.
15129 - Local/global vregs:
15130   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
15131     local register allocator.
15132   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
15133     structure, created by mono_create_var (). Assigned to hregs or the stack by
15134     the global register allocator.
15135 - When to do optimizations like alu->alu_imm:
15136   - earlier -> saves work later on since the IR will be smaller/simpler
15137   - later -> can work on more instructions
15138 - Handling of valuetypes:
15139   - When a vtype is pushed on the stack, a new temporary is created, an 
15140     instruction computing its address (LDADDR) is emitted and pushed on
15141     the stack. Need to optimize cases when the vtype is used immediately as in
15142     argument passing, stloc etc.
15143 - Instead of the to_end stuff in the old JIT, simply call the function handling
15144   the values on the stack before emitting the last instruction of the bb.
15145 */
15146
15147 #endif /* DISABLE_JIT */