[sgen] Clear the card table in the finishing pause
[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 || info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
9160                                         ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
9161                                         NULLIFY_INS (addr);
9162                                         goto calli_end;
9163                                 }
9164                         }
9165                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9166
9167                         calli_end:
9168
9169                         /* End of call, INS should contain the result of the call, if any */
9170
9171                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9172                                 g_assert (ins);
9173                                 *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
9174                         }
9175
9176                         CHECK_CFG_EXCEPTION;
9177
9178                         ip += 5;
9179                         ins_flag = 0;
9180                         constrained_class = NULL;
9181                         break;
9182                 }
9183                 case CEE_CALL:
9184                 case CEE_CALLVIRT: {
9185                         MonoInst *addr = NULL;
9186                         MonoMethodSignature *fsig = NULL;
9187                         int array_rank = 0;
9188                         int virtual_ = *ip == CEE_CALLVIRT;
9189                         gboolean pass_imt_from_rgctx = FALSE;
9190                         MonoInst *imt_arg = NULL;
9191                         MonoInst *keep_this_alive = NULL;
9192                         gboolean pass_vtable = FALSE;
9193                         gboolean pass_mrgctx = FALSE;
9194                         MonoInst *vtable_arg = NULL;
9195                         gboolean check_this = FALSE;
9196                         gboolean supported_tail_call = FALSE;
9197                         gboolean tail_call = FALSE;
9198                         gboolean need_seq_point = FALSE;
9199                         guint32 call_opcode = *ip;
9200                         gboolean emit_widen = TRUE;
9201                         gboolean push_res = TRUE;
9202                         gboolean skip_ret = FALSE;
9203                         gboolean delegate_invoke = FALSE;
9204                         gboolean direct_icall = FALSE;
9205                         gboolean constrained_partial_call = FALSE;
9206                         MonoMethod *cil_method;
9207
9208                         CHECK_OPSIZE (5);
9209                         token = read32 (ip + 1);
9210
9211                         ins = NULL;
9212
9213                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
9214                         CHECK_CFG_ERROR;
9215
9216                         cil_method = cmethod;
9217                                 
9218                         if (constrained_class) {
9219                                 if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
9220                                         if (!mini_is_gsharedvt_klass (constrained_class)) {
9221                                                 g_assert (!cmethod->klass->valuetype);
9222                                                 if (!mini_type_is_reference (&constrained_class->byval_arg))
9223                                                         constrained_partial_call = TRUE;
9224                                         }
9225                                 }
9226
9227                                 if (method->wrapper_type != MONO_WRAPPER_NONE) {
9228                                         if (cfg->verbose_level > 2)
9229                                                 printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_class));
9230                                         if (!((constrained_class->byval_arg.type == MONO_TYPE_VAR ||
9231                                                    constrained_class->byval_arg.type == MONO_TYPE_MVAR) &&
9232                                                   cfg->gshared)) {
9233                                                 cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_class, generic_context, &cfg->error);
9234                                                 CHECK_CFG_ERROR;
9235                                         }
9236                                 } else {
9237                                         if (cfg->verbose_level > 2)
9238                                                 printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_class));
9239
9240                                         if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
9241                                                 /* 
9242                                                  * This is needed since get_method_constrained can't find 
9243                                                  * the method in klass representing a type var.
9244                                                  * The type var is guaranteed to be a reference type in this
9245                                                  * case.
9246                                                  */
9247                                                 if (!mini_is_gsharedvt_klass (constrained_class))
9248                                                         g_assert (!cmethod->klass->valuetype);
9249                                         } else {
9250                                                 cmethod = mono_get_method_constrained_checked (image, token, constrained_class, generic_context, &cil_method, &cfg->error);
9251                                                 CHECK_CFG_ERROR;
9252                                         }
9253                                 }
9254                         }
9255                                         
9256                         if (!cmethod || mono_loader_get_last_error ()) {
9257                                 if (mono_loader_get_last_error ()) {
9258                                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
9259                                         mono_error_set_from_loader_error (&cfg->error);
9260                                         CHECK_CFG_ERROR;
9261                                 } else {
9262                                         LOAD_ERROR;
9263                                 }
9264                         }
9265                         if (!dont_verify && !cfg->skip_visibility) {
9266                                 MonoMethod *target_method = cil_method;
9267                                 if (method->is_inflated) {
9268                                         target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context), &cfg->error);
9269                                         CHECK_CFG_ERROR;
9270                                 }
9271                                 if (!mono_method_can_access_method (method_definition, target_method) &&
9272                                         !mono_method_can_access_method (method, cil_method))
9273                                         METHOD_ACCESS_FAILURE (method, cil_method);
9274                         }
9275
9276                         if (mono_security_core_clr_enabled ())
9277                                 ensure_method_is_allowed_to_call_method (cfg, method, cil_method);
9278
9279                         if (!virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
9280                                 /* MS.NET seems to silently convert this to a callvirt */
9281                                 virtual_ = 1;
9282
9283                         {
9284                                 /*
9285                                  * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
9286                                  * converts to a callvirt.
9287                                  *
9288                                  * tests/bug-515884.il is an example of this behavior
9289                                  */
9290                                 const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
9291                                 const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
9292                                 if (!virtual_ && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
9293                                         virtual_ = 1;
9294                         }
9295
9296                         if (!cmethod->klass->inited)
9297                                 if (!mono_class_init (cmethod->klass))
9298                                         TYPE_LOAD_ERROR (cmethod->klass);
9299
9300                         fsig = mono_method_signature (cmethod);
9301                         if (!fsig)
9302                                 LOAD_ERROR;
9303                         if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
9304                                 mini_class_is_system_array (cmethod->klass)) {
9305                                 array_rank = cmethod->klass->rank;
9306                         } else if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && icall_is_direct_callable (cfg, cmethod)) {
9307                                 direct_icall = TRUE;
9308                         } else if (fsig->pinvoke) {
9309                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
9310                                 fsig = mono_method_signature (wrapper);
9311                         } else if (constrained_class) {
9312                         } else {
9313                                 fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
9314                                 CHECK_CFG_ERROR;
9315                         }
9316
9317                         if (cfg->llvm_only && !cfg->method->wrapper_type)
9318                                 cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, fsig);
9319
9320                         /* See code below */
9321                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
9322                                 MonoBasicBlock *tbb;
9323
9324                                 GET_BBLOCK (cfg, tbb, ip + 5);
9325                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
9326                                         /*
9327                                          * We want to extend the try block to cover the call, but we can't do it if the
9328                                          * call is made directly since its followed by an exception check.
9329                                          */
9330                                         direct_icall = FALSE;
9331                                 }
9332                         }
9333
9334                         mono_save_token_info (cfg, image, token, cil_method);
9335
9336                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip + 5 - header->code)))
9337                                 need_seq_point = TRUE;
9338
9339                         /* Don't support calls made using type arguments for now */
9340                         /*
9341                           if (cfg->gsharedvt) {
9342                           if (mini_is_gsharedvt_signature (fsig))
9343                           GSHAREDVT_FAILURE (*ip);
9344                           }
9345                         */
9346
9347                         if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
9348                                 g_assert_not_reached ();
9349
9350                         n = fsig->param_count + fsig->hasthis;
9351
9352                         if (!cfg->gshared && cmethod->klass->generic_container)
9353                                 UNVERIFIED;
9354
9355                         if (!cfg->gshared)
9356                                 g_assert (!mono_method_check_context_used (cmethod));
9357
9358                         CHECK_STACK (n);
9359
9360                         //g_assert (!virtual_ || fsig->hasthis);
9361
9362                         sp -= n;
9363
9364                         /*
9365                          * We have the `constrained.' prefix opcode.
9366                          */
9367                         if (constrained_class) {
9368                                 if (mini_is_gsharedvt_klass (constrained_class)) {
9369                                         if ((cmethod->klass != mono_defaults.object_class) && constrained_class->valuetype && cmethod->klass->valuetype) {
9370                                                 /* The 'Own method' case below */
9371                                         } else if (cmethod->klass->image != mono_defaults.corlib && !(cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !cmethod->klass->valuetype) {
9372                                                 /* 'The type parameter is instantiated as a reference type' case below. */
9373                                         } else {
9374                                                 ins = handle_constrained_gsharedvt_call (cfg, cmethod, fsig, sp, constrained_class, &emit_widen);
9375                                                 CHECK_CFG_EXCEPTION;
9376                                                 g_assert (ins);
9377                                                 goto call_end;
9378                                         }
9379                                 }
9380
9381                                 if (constrained_partial_call) {
9382                                         gboolean need_box = TRUE;
9383
9384                                         /*
9385                                          * The receiver is a valuetype, but the exact type is not known at compile time. This means the
9386                                          * called method is not known at compile time either. The called method could end up being
9387                                          * one of the methods on the parent classes (object/valuetype/enum), in which case we need
9388                                          * to box the receiver.
9389                                          * A simple solution would be to box always and make a normal virtual call, but that would
9390                                          * be bad performance wise.
9391                                          */
9392                                         if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE && cmethod->klass->generic_class) {
9393                                                 /*
9394                                                  * The parent classes implement no generic interfaces, so the called method will be a vtype method, so no boxing neccessary.
9395                                                  */
9396                                                 need_box = FALSE;
9397                                         }
9398
9399                                         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)) {
9400                                                 /* The called method is not virtual, i.e. Object:GetType (), the receiver is a vtype, has to box */
9401                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9402                                                 ins->klass = constrained_class;
9403                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9404                                                 CHECK_CFG_EXCEPTION;
9405                                         } else if (need_box) {
9406                                                 MonoInst *box_type;
9407                                                 MonoBasicBlock *is_ref_bb, *end_bb;
9408                                                 MonoInst *nonbox_call;
9409
9410                                                 /*
9411                                                  * Determine at runtime whenever the called method is defined on object/valuetype/enum, and emit a boxing call
9412                                                  * if needed.
9413                                                  * FIXME: It is possible to inline the called method in a lot of cases, i.e. for T_INT,
9414                                                  * the no-box case goes to a method in Int32, while the box case goes to a method in Enum.
9415                                                  */
9416                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
9417
9418                                                 NEW_BBLOCK (cfg, is_ref_bb);
9419                                                 NEW_BBLOCK (cfg, end_bb);
9420
9421                                                 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);
9422                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, box_type->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
9423                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
9424
9425                                                 /* Non-ref case */
9426                                                 nonbox_call = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9427
9428                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9429
9430                                                 /* Ref case */
9431                                                 MONO_START_BB (cfg, is_ref_bb);
9432                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9433                                                 ins->klass = constrained_class;
9434                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9435                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9436
9437                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9438
9439                                                 MONO_START_BB (cfg, end_bb);
9440                                                 cfg->cbb = end_bb;
9441
9442                                                 nonbox_call->dreg = ins->dreg;
9443                                                 goto call_end;
9444                                         } else {
9445                                                 g_assert (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
9446                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
9447                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9448                                                 goto call_end;
9449                                         }
9450                                 } else if (constrained_class->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
9451                                         /*
9452                                          * The type parameter is instantiated as a valuetype,
9453                                          * but that type doesn't override the method we're
9454                                          * calling, so we need to box `this'.
9455                                          */
9456                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9457                                         ins->klass = constrained_class;
9458                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9459                                         CHECK_CFG_EXCEPTION;
9460                                 } else if (!constrained_class->valuetype) {
9461                                         int dreg = alloc_ireg_ref (cfg);
9462
9463                                         /*
9464                                          * The type parameter is instantiated as a reference
9465                                          * type.  We have a managed pointer on the stack, so
9466                                          * we need to dereference it here.
9467                                          */
9468                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
9469                                         ins->type = STACK_OBJ;
9470                                         sp [0] = ins;
9471                                 } else {
9472                                         if (cmethod->klass->valuetype) {
9473                                                 /* Own method */
9474                                         } else {
9475                                                 /* Interface method */
9476                                                 int ioffset, slot;
9477
9478                                                 mono_class_setup_vtable (constrained_class);
9479                                                 CHECK_TYPELOAD (constrained_class);
9480                                                 ioffset = mono_class_interface_offset (constrained_class, cmethod->klass);
9481                                                 if (ioffset == -1)
9482                                                         TYPE_LOAD_ERROR (constrained_class);
9483                                                 slot = mono_method_get_vtable_slot (cmethod);
9484                                                 if (slot == -1)
9485                                                         TYPE_LOAD_ERROR (cmethod->klass);
9486                                                 cmethod = constrained_class->vtable [ioffset + slot];
9487
9488                                                 if (cmethod->klass == mono_defaults.enum_class) {
9489                                                         /* Enum implements some interfaces, so treat this as the first case */
9490                                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9491                                                         ins->klass = constrained_class;
9492                                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9493                                                         CHECK_CFG_EXCEPTION;
9494                                                 }
9495                                         }
9496                                         virtual_ = 0;
9497                                 }
9498                                 constrained_class = NULL;
9499                         }
9500
9501                         if (check_call_signature (cfg, fsig, sp))
9502                                 UNVERIFIED;
9503
9504                         if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
9505                                 delegate_invoke = TRUE;
9506
9507                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
9508                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9509                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9510                                         emit_widen = FALSE;
9511                                 }
9512
9513                                 goto call_end;
9514                         }
9515
9516                         /* 
9517                          * If the callee is a shared method, then its static cctor
9518                          * might not get called after the call was patched.
9519                          */
9520                         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)) {
9521                                 emit_class_init (cfg, cmethod->klass);
9522                                 CHECK_TYPELOAD (cmethod->klass);
9523                         }
9524
9525                         check_method_sharing (cfg, cmethod, &pass_vtable, &pass_mrgctx);
9526
9527                         if (cfg->gshared) {
9528                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
9529
9530                                 context_used = mini_method_check_context_used (cfg, cmethod);
9531
9532                                 if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9533                                         /* Generic method interface
9534                                            calls are resolved via a
9535                                            helper function and don't
9536                                            need an imt. */
9537                                         if (!cmethod_context || !cmethod_context->method_inst)
9538                                                 pass_imt_from_rgctx = TRUE;
9539                                 }
9540
9541                                 /*
9542                                  * If a shared method calls another
9543                                  * shared method then the caller must
9544                                  * have a generic sharing context
9545                                  * because the magic trampoline
9546                                  * requires it.  FIXME: We shouldn't
9547                                  * have to force the vtable/mrgctx
9548                                  * variable here.  Instead there
9549                                  * should be a flag in the cfg to
9550                                  * request a generic sharing context.
9551                                  */
9552                                 if (context_used &&
9553                                                 ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
9554                                         mono_get_vtable_var (cfg);
9555                         }
9556
9557                         if (pass_vtable) {
9558                                 if (context_used) {
9559                                         vtable_arg = emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
9560                                 } else {
9561                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
9562
9563                                         CHECK_TYPELOAD (cmethod->klass);
9564                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
9565                                 }
9566                         }
9567
9568                         if (pass_mrgctx) {
9569                                 g_assert (!vtable_arg);
9570
9571                                 if (!cfg->compile_aot) {
9572                                         /* 
9573                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
9574                                          * for type load errors before.
9575                                          */
9576                                         mono_class_setup_vtable (cmethod->klass);
9577                                         CHECK_TYPELOAD (cmethod->klass);
9578                                 }
9579
9580                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
9581
9582                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
9583                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
9584                                          MONO_METHOD_IS_FINAL (cmethod)) &&
9585                                         !mono_class_is_marshalbyref (cmethod->klass)) {
9586                                         if (virtual_)
9587                                                 check_this = TRUE;
9588                                         virtual_ = 0;
9589                                 }
9590                         }
9591
9592                         if (pass_imt_from_rgctx) {
9593                                 g_assert (!pass_vtable);
9594
9595                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9596                                         cmethod, MONO_RGCTX_INFO_METHOD);
9597                         }
9598
9599                         if (check_this)
9600                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9601
9602                         /* Calling virtual generic methods */
9603                         if (virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) &&
9604                             !(MONO_METHOD_IS_FINAL (cmethod) && 
9605                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
9606                             fsig->generic_param_count && 
9607                                 !(cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) &&
9608                                 !cfg->llvm_only) {
9609                                 MonoInst *this_temp, *this_arg_temp, *store;
9610                                 MonoInst *iargs [4];
9611
9612                                 g_assert (fsig->is_inflated);
9613
9614                                 /* Prevent inlining of methods that contain indirect calls */
9615                                 INLINE_FAILURE ("virtual generic call");
9616
9617                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
9618                                         GSHAREDVT_FAILURE (*ip);
9619
9620                                 if (cfg->backend->have_generalized_imt_thunk && cfg->backend->gshared_supported && cmethod->wrapper_type == MONO_WRAPPER_NONE) {
9621                                         g_assert (!imt_arg);
9622                                         if (!context_used)
9623                                                 g_assert (cmethod->is_inflated);
9624                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
9625                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
9626                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, sp [0], imt_arg, NULL);
9627                                 } else {
9628                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
9629                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
9630                                         MONO_ADD_INS (cfg->cbb, store);
9631
9632                                         /* FIXME: This should be a managed pointer */
9633                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
9634
9635                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
9636                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
9637                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
9638                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
9639                                         addr = mono_emit_jit_icall (cfg,
9640                                                                                                 mono_helper_compile_generic_method, iargs);
9641
9642                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
9643
9644                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9645                                 }
9646
9647                                 goto call_end;
9648                         }
9649
9650                         /*
9651                          * Implement a workaround for the inherent races involved in locking:
9652                          * Monitor.Enter ()
9653                          * try {
9654                          * } finally {
9655                          *    Monitor.Exit ()
9656                          * }
9657                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
9658                          * try block, the Exit () won't be executed, see:
9659                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
9660                          * To work around this, we extend such try blocks to include the last x bytes
9661                          * of the Monitor.Enter () call.
9662                          */
9663                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
9664                                 MonoBasicBlock *tbb;
9665
9666                                 GET_BBLOCK (cfg, tbb, ip + 5);
9667                                 /* 
9668                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
9669                                  * from Monitor.Enter like ArgumentNullException.
9670                                  */
9671                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
9672                                         /* Mark this bblock as needing to be extended */
9673                                         tbb->extend_try_block = TRUE;
9674                                 }
9675                         }
9676
9677                         /* Conversion to a JIT intrinsic */
9678                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
9679                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9680                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9681                                         emit_widen = FALSE;
9682                                 }
9683                                 goto call_end;
9684                         }
9685
9686                         /* Inlining */
9687                         if ((cfg->opt & MONO_OPT_INLINE) &&
9688                                 (!virtual_ || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
9689                             mono_method_check_inlining (cfg, cmethod)) {
9690                                 int costs;
9691                                 gboolean always = FALSE;
9692
9693                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
9694                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
9695                                         /* Prevent inlining of methods that call wrappers */
9696                                         INLINE_FAILURE ("wrapper call");
9697                                         cmethod = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
9698                                         always = TRUE;
9699                                 }
9700
9701                                 costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, always);
9702                                 if (costs) {
9703                                         cfg->real_offset += 5;
9704
9705                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9706                                                 /* *sp is already set by inline_method */
9707                                                 sp++;
9708                                                 push_res = FALSE;
9709                                         }
9710
9711                                         inline_costs += costs;
9712
9713                                         goto call_end;
9714                                 }
9715                         }
9716
9717                         /* Tail recursion elimination */
9718                         if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
9719                                 gboolean has_vtargs = FALSE;
9720                                 int i;
9721
9722                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9723                                 INLINE_FAILURE ("tail call");
9724
9725                                 /* keep it simple */
9726                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
9727                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
9728                                                 has_vtargs = TRUE;
9729                                 }
9730
9731                                 if (!has_vtargs) {
9732                                         for (i = 0; i < n; ++i)
9733                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9734                                         MONO_INST_NEW (cfg, ins, OP_BR);
9735                                         MONO_ADD_INS (cfg->cbb, ins);
9736                                         tblock = start_bblock->out_bb [0];
9737                                         link_bblock (cfg, cfg->cbb, tblock);
9738                                         ins->inst_target_bb = tblock;
9739                                         start_new_bblock = 1;
9740
9741                                         /* skip the CEE_RET, too */
9742                                         if (ip_in_bb (cfg, cfg->cbb, ip + 5))
9743                                                 skip_ret = TRUE;
9744                                         push_res = FALSE;
9745                                         goto call_end;
9746                                 }
9747                         }
9748
9749                         inline_costs += 10 * num_calls++;
9750
9751                         /*
9752                          * Making generic calls out of gsharedvt methods.
9753                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9754                          * patching gshared method addresses into a gsharedvt method.
9755                          */
9756                         if (cfg->gsharedvt && (mini_is_gsharedvt_signature (fsig) || cmethod->is_inflated || cmethod->klass->generic_class) &&
9757                                 !(cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY) &&
9758                                 (!(cfg->llvm_only && virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)))) {
9759                                 MonoRgctxInfoType info_type;
9760
9761                                 if (virtual_) {
9762                                         //if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
9763                                                 //GSHAREDVT_FAILURE (*ip);
9764                                         // disable for possible remoting calls
9765                                         if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
9766                                                 GSHAREDVT_FAILURE (*ip);
9767                                         if (fsig->generic_param_count) {
9768                                                 /* virtual generic call */
9769                                                 g_assert (!imt_arg);
9770                                                 /* Same as the virtual generic case above */
9771                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9772                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9773                                                 /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
9774                                                 vtable_arg = NULL;
9775                                         } else if ((cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !imt_arg) {
9776                                                 /* This can happen when we call a fully instantiated iface method */
9777                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9778                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9779                                                 vtable_arg = NULL;
9780                                         }
9781                                 }
9782
9783                                 if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
9784                                         keep_this_alive = sp [0];
9785
9786                                 if (virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
9787                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
9788                                 else
9789                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
9790                                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
9791
9792                                 if (cfg->llvm_only) {
9793                                         // FIXME: Avoid initializing vtable_arg
9794                                         ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
9795                                 } else {
9796                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9797                                 }
9798                                 goto call_end;
9799                         }
9800
9801                         /* Generic sharing */
9802
9803                         /*
9804                          * Use this if the callee is gsharedvt sharable too, since
9805                          * at runtime we might find an instantiation so the call cannot
9806                          * be patched (the 'no_patch' code path in mini-trampolines.c).
9807                          */
9808                         if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
9809                                 (!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
9810                                  !mono_class_generic_sharing_enabled (cmethod->klass)) &&
9811                                 (!virtual_ || MONO_METHOD_IS_FINAL (cmethod) ||
9812                                  !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
9813                                 INLINE_FAILURE ("gshared");
9814
9815                                 g_assert (cfg->gshared && cmethod);
9816                                 g_assert (!addr);
9817
9818                                 /*
9819                                  * We are compiling a call to a
9820                                  * generic method from shared code,
9821                                  * which means that we have to look up
9822                                  * the method in the rgctx and do an
9823                                  * indirect call.
9824                                  */
9825                                 if (fsig->hasthis)
9826                                         MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9827
9828                                 if (cfg->llvm_only) {
9829                                         if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig))
9830                                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER);
9831                                         else
9832                                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9833                                         // FIXME: Avoid initializing imt_arg/vtable_arg
9834                                         ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
9835                                 } else {
9836                                         addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9837                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9838                                 }
9839                                 goto call_end;
9840                         }
9841
9842                         /* Direct calls to icalls */
9843                         if (direct_icall) {
9844                                 MonoMethod *wrapper;
9845                                 int costs;
9846
9847                                 /* Inline the wrapper */
9848                                 wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
9849
9850                                 costs = inline_method (cfg, wrapper, fsig, sp, ip, cfg->real_offset, TRUE);
9851                                 g_assert (costs > 0);
9852                                 cfg->real_offset += 5;
9853
9854                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9855                                         /* *sp is already set by inline_method */
9856                                         sp++;
9857                                         push_res = FALSE;
9858                                 }
9859
9860                                 inline_costs += costs;
9861
9862                                 goto call_end;
9863                         }
9864                                         
9865                         /* Array methods */
9866                         if (array_rank) {
9867                                 MonoInst *addr;
9868
9869                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
9870                                         MonoInst *val = sp [fsig->param_count];
9871
9872                                         if (val->type == STACK_OBJ) {
9873                                                 MonoInst *iargs [2];
9874
9875                                                 iargs [0] = sp [0];
9876                                                 iargs [1] = val;
9877                                                 
9878                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
9879                                         }
9880                                         
9881                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
9882                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
9883                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !(val->opcode == OP_PCONST && val->inst_c0 == 0))
9884                                                 emit_write_barrier (cfg, addr, val);
9885                                         if (cfg->gen_write_barriers && mini_is_gsharedvt_klass (cmethod->klass))
9886                                                 GSHAREDVT_FAILURE (*ip);
9887                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
9888                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9889
9890                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
9891                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
9892                                         if (!cmethod->klass->element_class->valuetype && !readonly)
9893                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
9894                                         CHECK_TYPELOAD (cmethod->klass);
9895                                         
9896                                         readonly = FALSE;
9897                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9898                                         ins = addr;
9899                                 } else {
9900                                         g_assert_not_reached ();
9901                                 }
9902
9903                                 emit_widen = FALSE;
9904                                 goto call_end;
9905                         }
9906
9907                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual_ ? sp [0] : NULL);
9908                         if (ins)
9909                                 goto call_end;
9910
9911                         /* Tail prefix / tail call optimization */
9912
9913                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
9914                         /* FIXME: runtime generic context pointer for jumps? */
9915                         /* FIXME: handle this for generic sharing eventually */
9916                         if ((ins_flag & MONO_INST_TAILCALL) &&
9917                                 !vtable_arg && !cfg->gshared && is_supported_tail_call (cfg, method, cmethod, fsig, call_opcode))
9918                                 supported_tail_call = TRUE;
9919
9920                         if (supported_tail_call) {
9921                                 MonoCallInst *call;
9922
9923                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9924                                 INLINE_FAILURE ("tail call");
9925
9926                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
9927
9928                                 if (cfg->backend->have_op_tail_call) {
9929                                         /* Handle tail calls similarly to normal calls */
9930                                         tail_call = TRUE;
9931                                 } else {
9932                                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
9933
9934                                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9935                                         call->tail_call = TRUE;
9936                                         call->method = cmethod;
9937                                         call->signature = mono_method_signature (cmethod);
9938
9939                                         /*
9940                                          * We implement tail calls by storing the actual arguments into the 
9941                                          * argument variables, then emitting a CEE_JMP.
9942                                          */
9943                                         for (i = 0; i < n; ++i) {
9944                                                 /* Prevent argument from being register allocated */
9945                                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
9946                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9947                                         }
9948                                         ins = (MonoInst*)call;
9949                                         ins->inst_p0 = cmethod;
9950                                         ins->inst_p1 = arg_array [0];
9951                                         MONO_ADD_INS (cfg->cbb, ins);
9952                                         link_bblock (cfg, cfg->cbb, end_bblock);
9953                                         start_new_bblock = 1;
9954
9955                                         // FIXME: Eliminate unreachable epilogs
9956
9957                                         /*
9958                                          * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9959                                          * only reachable from this call.
9960                                          */
9961                                         GET_BBLOCK (cfg, tblock, ip + 5);
9962                                         if (tblock == cfg->cbb || tblock->in_count == 0)
9963                                                 skip_ret = TRUE;
9964                                         push_res = FALSE;
9965
9966                                         goto call_end;
9967                                 }
9968                         }
9969
9970                         /* 
9971                          * Synchronized wrappers.
9972                          * Its hard to determine where to replace a method with its synchronized
9973                          * wrapper without causing an infinite recursion. The current solution is
9974                          * to add the synchronized wrapper in the trampolines, and to
9975                          * change the called method to a dummy wrapper, and resolve that wrapper
9976                          * to the real method in mono_jit_compile_method ().
9977                          */
9978                         if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
9979                                 MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
9980                                 if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
9981                                         cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
9982                         }
9983
9984                         /*
9985                          * Virtual calls in llvm-only mode.
9986                          */
9987                         if (cfg->llvm_only && virtual_ && cmethod && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
9988                                 ins = emit_llvmonly_virtual_call (cfg, cmethod, fsig, context_used, sp);
9989                                 goto call_end;
9990                         }
9991
9992                         /* Common call */
9993                         INLINE_FAILURE ("call");
9994                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual_ ? sp [0] : NULL,
9995                                                                                           imt_arg, vtable_arg);
9996
9997                         if (tail_call && !cfg->llvm_only) {
9998                                 link_bblock (cfg, cfg->cbb, end_bblock);
9999                                 start_new_bblock = 1;
10000
10001                                 // FIXME: Eliminate unreachable epilogs
10002
10003                                 /*
10004                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
10005                                  * only reachable from this call.
10006                                  */
10007                                 GET_BBLOCK (cfg, tblock, ip + 5);
10008                                 if (tblock == cfg->cbb || tblock->in_count == 0)
10009                                         skip_ret = TRUE;
10010                                 push_res = FALSE;
10011                         }
10012
10013                         call_end:
10014
10015                         /* End of call, INS should contain the result of the call, if any */
10016
10017                         if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
10018                                 g_assert (ins);
10019                                 if (emit_widen)
10020                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
10021                                 else
10022                                         *sp++ = ins;
10023                         }
10024
10025                         if (keep_this_alive) {
10026                                 MonoInst *dummy_use;
10027
10028                                 /* See mono_emit_method_call_full () */
10029                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
10030                         }
10031
10032                         CHECK_CFG_EXCEPTION;
10033
10034                         ip += 5;
10035                         if (skip_ret) {
10036                                 g_assert (*ip == CEE_RET);
10037                                 ip += 1;
10038                         }
10039                         ins_flag = 0;
10040                         constrained_class = NULL;
10041                         if (need_seq_point)
10042                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10043                         break;
10044                 }
10045                 case CEE_RET:
10046                         if (cfg->method != method) {
10047                                 /* return from inlined method */
10048                                 /* 
10049                                  * If in_count == 0, that means the ret is unreachable due to
10050                                  * being preceeded by a throw. In that case, inline_method () will
10051                                  * handle setting the return value 
10052                                  * (test case: test_0_inline_throw ()).
10053                                  */
10054                                 if (return_var && cfg->cbb->in_count) {
10055                                         MonoType *ret_type = mono_method_signature (method)->ret;
10056
10057                                         MonoInst *store;
10058                                         CHECK_STACK (1);
10059                                         --sp;
10060
10061                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
10062                                                 UNVERIFIED;
10063
10064                                         //g_assert (returnvar != -1);
10065                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
10066                                         cfg->ret_var_set = TRUE;
10067                                 } 
10068                         } else {
10069                                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
10070
10071                                 if (cfg->lmf_var && cfg->cbb->in_count && !cfg->llvm_only)
10072                                         emit_pop_lmf (cfg);
10073
10074                                 if (cfg->ret) {
10075                                         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (method)->ret);
10076
10077                                         if (seq_points && !sym_seq_points) {
10078                                                 /* 
10079                                                  * Place a seq point here too even through the IL stack is not
10080                                                  * empty, so a step over on
10081                                                  * call <FOO>
10082                                                  * ret
10083                                                  * will work correctly.
10084                                                  */
10085                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
10086                                                 MONO_ADD_INS (cfg->cbb, ins);
10087                                         }
10088
10089                                         g_assert (!return_var);
10090                                         CHECK_STACK (1);
10091                                         --sp;
10092
10093                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
10094                                                 UNVERIFIED;
10095
10096                                         emit_setret (cfg, *sp);
10097                                 }
10098                         }
10099                         if (sp != stack_start)
10100                                 UNVERIFIED;
10101                         MONO_INST_NEW (cfg, ins, OP_BR);
10102                         ip++;
10103                         ins->inst_target_bb = end_bblock;
10104                         MONO_ADD_INS (cfg->cbb, ins);
10105                         link_bblock (cfg, cfg->cbb, end_bblock);
10106                         start_new_bblock = 1;
10107                         break;
10108                 case CEE_BR_S:
10109                         CHECK_OPSIZE (2);
10110                         MONO_INST_NEW (cfg, ins, OP_BR);
10111                         ip++;
10112                         target = ip + 1 + (signed char)(*ip);
10113                         ++ip;
10114                         GET_BBLOCK (cfg, tblock, target);
10115                         link_bblock (cfg, cfg->cbb, tblock);
10116                         ins->inst_target_bb = tblock;
10117                         if (sp != stack_start) {
10118                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10119                                 sp = stack_start;
10120                                 CHECK_UNVERIFIABLE (cfg);
10121                         }
10122                         MONO_ADD_INS (cfg->cbb, ins);
10123                         start_new_bblock = 1;
10124                         inline_costs += BRANCH_COST;
10125                         break;
10126                 case CEE_BEQ_S:
10127                 case CEE_BGE_S:
10128                 case CEE_BGT_S:
10129                 case CEE_BLE_S:
10130                 case CEE_BLT_S:
10131                 case CEE_BNE_UN_S:
10132                 case CEE_BGE_UN_S:
10133                 case CEE_BGT_UN_S:
10134                 case CEE_BLE_UN_S:
10135                 case CEE_BLT_UN_S:
10136                         CHECK_OPSIZE (2);
10137                         CHECK_STACK (2);
10138                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
10139                         ip++;
10140                         target = ip + 1 + *(signed char*)ip;
10141                         ip++;
10142
10143                         ADD_BINCOND (NULL);
10144
10145                         sp = stack_start;
10146                         inline_costs += BRANCH_COST;
10147                         break;
10148                 case CEE_BR:
10149                         CHECK_OPSIZE (5);
10150                         MONO_INST_NEW (cfg, ins, OP_BR);
10151                         ip++;
10152
10153                         target = ip + 4 + (gint32)read32(ip);
10154                         ip += 4;
10155                         GET_BBLOCK (cfg, tblock, target);
10156                         link_bblock (cfg, cfg->cbb, tblock);
10157                         ins->inst_target_bb = tblock;
10158                         if (sp != stack_start) {
10159                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10160                                 sp = stack_start;
10161                                 CHECK_UNVERIFIABLE (cfg);
10162                         }
10163
10164                         MONO_ADD_INS (cfg->cbb, ins);
10165
10166                         start_new_bblock = 1;
10167                         inline_costs += BRANCH_COST;
10168                         break;
10169                 case CEE_BRFALSE_S:
10170                 case CEE_BRTRUE_S:
10171                 case CEE_BRFALSE:
10172                 case CEE_BRTRUE: {
10173                         MonoInst *cmp;
10174                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
10175                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
10176                         guint32 opsize = is_short ? 1 : 4;
10177
10178                         CHECK_OPSIZE (opsize);
10179                         CHECK_STACK (1);
10180                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
10181                                 UNVERIFIED;
10182                         ip ++;
10183                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
10184                         ip += opsize;
10185
10186                         sp--;
10187
10188                         GET_BBLOCK (cfg, tblock, target);
10189                         link_bblock (cfg, cfg->cbb, tblock);
10190                         GET_BBLOCK (cfg, tblock, ip);
10191                         link_bblock (cfg, cfg->cbb, tblock);
10192
10193                         if (sp != stack_start) {
10194                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10195                                 CHECK_UNVERIFIABLE (cfg);
10196                         }
10197
10198                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
10199                         cmp->sreg1 = sp [0]->dreg;
10200                         type_from_op (cfg, cmp, sp [0], NULL);
10201                         CHECK_TYPE (cmp);
10202
10203 #if SIZEOF_REGISTER == 4
10204                         if (cmp->opcode == OP_LCOMPARE_IMM) {
10205                                 /* Convert it to OP_LCOMPARE */
10206                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
10207                                 ins->type = STACK_I8;
10208                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
10209                                 ins->inst_l = 0;
10210                                 MONO_ADD_INS (cfg->cbb, ins);
10211                                 cmp->opcode = OP_LCOMPARE;
10212                                 cmp->sreg2 = ins->dreg;
10213                         }
10214 #endif
10215                         MONO_ADD_INS (cfg->cbb, cmp);
10216
10217                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
10218                         type_from_op (cfg, ins, sp [0], NULL);
10219                         MONO_ADD_INS (cfg->cbb, ins);
10220                         ins->inst_many_bb = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
10221                         GET_BBLOCK (cfg, tblock, target);
10222                         ins->inst_true_bb = tblock;
10223                         GET_BBLOCK (cfg, tblock, ip);
10224                         ins->inst_false_bb = tblock;
10225                         start_new_bblock = 2;
10226
10227                         sp = stack_start;
10228                         inline_costs += BRANCH_COST;
10229                         break;
10230                 }
10231                 case CEE_BEQ:
10232                 case CEE_BGE:
10233                 case CEE_BGT:
10234                 case CEE_BLE:
10235                 case CEE_BLT:
10236                 case CEE_BNE_UN:
10237                 case CEE_BGE_UN:
10238                 case CEE_BGT_UN:
10239                 case CEE_BLE_UN:
10240                 case CEE_BLT_UN:
10241                         CHECK_OPSIZE (5);
10242                         CHECK_STACK (2);
10243                         MONO_INST_NEW (cfg, ins, *ip);
10244                         ip++;
10245                         target = ip + 4 + (gint32)read32(ip);
10246                         ip += 4;
10247
10248                         ADD_BINCOND (NULL);
10249
10250                         sp = stack_start;
10251                         inline_costs += BRANCH_COST;
10252                         break;
10253                 case CEE_SWITCH: {
10254                         MonoInst *src1;
10255                         MonoBasicBlock **targets;
10256                         MonoBasicBlock *default_bblock;
10257                         MonoJumpInfoBBTable *table;
10258                         int offset_reg = alloc_preg (cfg);
10259                         int target_reg = alloc_preg (cfg);
10260                         int table_reg = alloc_preg (cfg);
10261                         int sum_reg = alloc_preg (cfg);
10262                         gboolean use_op_switch;
10263
10264                         CHECK_OPSIZE (5);
10265                         CHECK_STACK (1);
10266                         n = read32 (ip + 1);
10267                         --sp;
10268                         src1 = sp [0];
10269                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
10270                                 UNVERIFIED;
10271
10272                         ip += 5;
10273                         CHECK_OPSIZE (n * sizeof (guint32));
10274                         target = ip + n * sizeof (guint32);
10275
10276                         GET_BBLOCK (cfg, default_bblock, target);
10277                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
10278
10279                         targets = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
10280                         for (i = 0; i < n; ++i) {
10281                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
10282                                 targets [i] = tblock;
10283                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
10284                                 ip += 4;
10285                         }
10286
10287                         if (sp != stack_start) {
10288                                 /* 
10289                                  * Link the current bb with the targets as well, so handle_stack_args
10290                                  * will set their in_stack correctly.
10291                                  */
10292                                 link_bblock (cfg, cfg->cbb, default_bblock);
10293                                 for (i = 0; i < n; ++i)
10294                                         link_bblock (cfg, cfg->cbb, targets [i]);
10295
10296                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10297                                 sp = stack_start;
10298                                 CHECK_UNVERIFIABLE (cfg);
10299
10300                                 /* Undo the links */
10301                                 mono_unlink_bblock (cfg, cfg->cbb, default_bblock);
10302                                 for (i = 0; i < n; ++i)
10303                                         mono_unlink_bblock (cfg, cfg->cbb, targets [i]);
10304                         }
10305
10306                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
10307                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
10308
10309                         for (i = 0; i < n; ++i)
10310                                 link_bblock (cfg, cfg->cbb, targets [i]);
10311
10312                         table = (MonoJumpInfoBBTable *)mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
10313                         table->table = targets;
10314                         table->table_size = n;
10315
10316                         use_op_switch = FALSE;
10317 #ifdef TARGET_ARM
10318                         /* ARM implements SWITCH statements differently */
10319                         /* FIXME: Make it use the generic implementation */
10320                         if (!cfg->compile_aot)
10321                                 use_op_switch = TRUE;
10322 #endif
10323
10324                         if (COMPILE_LLVM (cfg))
10325                                 use_op_switch = TRUE;
10326
10327                         cfg->cbb->has_jump_table = 1;
10328
10329                         if (use_op_switch) {
10330                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
10331                                 ins->sreg1 = src1->dreg;
10332                                 ins->inst_p0 = table;
10333                                 ins->inst_many_bb = targets;
10334                                 ins->klass = (MonoClass *)GUINT_TO_POINTER (n);
10335                                 MONO_ADD_INS (cfg->cbb, ins);
10336                         } else {
10337                                 if (sizeof (gpointer) == 8)
10338                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
10339                                 else
10340                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
10341
10342 #if SIZEOF_REGISTER == 8
10343                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
10344                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
10345 #endif
10346
10347                                 if (cfg->compile_aot) {
10348                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
10349                                 } else {
10350                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
10351                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
10352                                         ins->inst_p0 = table;
10353                                         ins->dreg = table_reg;
10354                                         MONO_ADD_INS (cfg->cbb, ins);
10355                                 }
10356
10357                                 /* FIXME: Use load_memindex */
10358                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
10359                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
10360                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
10361                         }
10362                         start_new_bblock = 1;
10363                         inline_costs += (BRANCH_COST * 2);
10364                         break;
10365                 }
10366                 case CEE_LDIND_I1:
10367                 case CEE_LDIND_U1:
10368                 case CEE_LDIND_I2:
10369                 case CEE_LDIND_U2:
10370                 case CEE_LDIND_I4:
10371                 case CEE_LDIND_U4:
10372                 case CEE_LDIND_I8:
10373                 case CEE_LDIND_I:
10374                 case CEE_LDIND_R4:
10375                 case CEE_LDIND_R8:
10376                 case CEE_LDIND_REF:
10377                         CHECK_STACK (1);
10378                         --sp;
10379
10380                         switch (*ip) {
10381                         case CEE_LDIND_R4:
10382                         case CEE_LDIND_R8:
10383                                 dreg = alloc_freg (cfg);
10384                                 break;
10385                         case CEE_LDIND_I8:
10386                                 dreg = alloc_lreg (cfg);
10387                                 break;
10388                         case CEE_LDIND_REF:
10389                                 dreg = alloc_ireg_ref (cfg);
10390                                 break;
10391                         default:
10392                                 dreg = alloc_preg (cfg);
10393                         }
10394
10395                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
10396                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
10397                         if (*ip == CEE_LDIND_R4)
10398                                 ins->type = cfg->r4_stack_type;
10399                         ins->flags |= ins_flag;
10400                         MONO_ADD_INS (cfg->cbb, ins);
10401                         *sp++ = ins;
10402                         if (ins_flag & MONO_INST_VOLATILE) {
10403                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10404                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10405                         }
10406                         ins_flag = 0;
10407                         ++ip;
10408                         break;
10409                 case CEE_STIND_REF:
10410                 case CEE_STIND_I1:
10411                 case CEE_STIND_I2:
10412                 case CEE_STIND_I4:
10413                 case CEE_STIND_I8:
10414                 case CEE_STIND_R4:
10415                 case CEE_STIND_R8:
10416                 case CEE_STIND_I:
10417                         CHECK_STACK (2);
10418                         sp -= 2;
10419
10420                         if (ins_flag & MONO_INST_VOLATILE) {
10421                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
10422                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
10423                         }
10424
10425                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
10426                         ins->flags |= ins_flag;
10427                         ins_flag = 0;
10428
10429                         MONO_ADD_INS (cfg->cbb, ins);
10430
10431                         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)))
10432                                 emit_write_barrier (cfg, sp [0], sp [1]);
10433
10434                         inline_costs += 1;
10435                         ++ip;
10436                         break;
10437
10438                 case CEE_MUL:
10439                         CHECK_STACK (2);
10440
10441                         MONO_INST_NEW (cfg, ins, (*ip));
10442                         sp -= 2;
10443                         ins->sreg1 = sp [0]->dreg;
10444                         ins->sreg2 = sp [1]->dreg;
10445                         type_from_op (cfg, ins, sp [0], sp [1]);
10446                         CHECK_TYPE (ins);
10447                         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type);
10448
10449                         /* Use the immediate opcodes if possible */
10450                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
10451                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
10452                                 if (imm_opcode != -1) {
10453                                         ins->opcode = imm_opcode;
10454                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
10455                                         ins->sreg2 = -1;
10456
10457                                         NULLIFY_INS (sp [1]);
10458                                 }
10459                         }
10460
10461                         MONO_ADD_INS ((cfg)->cbb, (ins));
10462
10463                         *sp++ = mono_decompose_opcode (cfg, ins);
10464                         ip++;
10465                         break;
10466                 case CEE_ADD:
10467                 case CEE_SUB:
10468                 case CEE_DIV:
10469                 case CEE_DIV_UN:
10470                 case CEE_REM:
10471                 case CEE_REM_UN:
10472                 case CEE_AND:
10473                 case CEE_OR:
10474                 case CEE_XOR:
10475                 case CEE_SHL:
10476                 case CEE_SHR:
10477                 case CEE_SHR_UN:
10478                         CHECK_STACK (2);
10479
10480                         MONO_INST_NEW (cfg, ins, (*ip));
10481                         sp -= 2;
10482                         ins->sreg1 = sp [0]->dreg;
10483                         ins->sreg2 = sp [1]->dreg;
10484                         type_from_op (cfg, ins, sp [0], sp [1]);
10485                         CHECK_TYPE (ins);
10486                         add_widen_op (cfg, ins, &sp [0], &sp [1]);
10487                         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type);
10488
10489                         /* FIXME: Pass opcode to is_inst_imm */
10490
10491                         /* Use the immediate opcodes if possible */
10492                         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)) {
10493                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
10494                                 if (imm_opcode != -1) {
10495                                         ins->opcode = imm_opcode;
10496                                         if (sp [1]->opcode == OP_I8CONST) {
10497 #if SIZEOF_REGISTER == 8
10498                                                 ins->inst_imm = sp [1]->inst_l;
10499 #else
10500                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
10501                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
10502 #endif
10503                                         }
10504                                         else
10505                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
10506                                         ins->sreg2 = -1;
10507
10508                                         /* Might be followed by an instruction added by add_widen_op */
10509                                         if (sp [1]->next == NULL)
10510                                                 NULLIFY_INS (sp [1]);
10511                                 }
10512                         }
10513                         MONO_ADD_INS ((cfg)->cbb, (ins));
10514
10515                         *sp++ = mono_decompose_opcode (cfg, ins);
10516                         ip++;
10517                         break;
10518                 case CEE_NEG:
10519                 case CEE_NOT:
10520                 case CEE_CONV_I1:
10521                 case CEE_CONV_I2:
10522                 case CEE_CONV_I4:
10523                 case CEE_CONV_R4:
10524                 case CEE_CONV_R8:
10525                 case CEE_CONV_U4:
10526                 case CEE_CONV_I8:
10527                 case CEE_CONV_U8:
10528                 case CEE_CONV_OVF_I8:
10529                 case CEE_CONV_OVF_U8:
10530                 case CEE_CONV_R_UN:
10531                         CHECK_STACK (1);
10532
10533                         /* Special case this earlier so we have long constants in the IR */
10534                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
10535                                 int data = sp [-1]->inst_c0;
10536                                 sp [-1]->opcode = OP_I8CONST;
10537                                 sp [-1]->type = STACK_I8;
10538 #if SIZEOF_REGISTER == 8
10539                                 if ((*ip) == CEE_CONV_U8)
10540                                         sp [-1]->inst_c0 = (guint32)data;
10541                                 else
10542                                         sp [-1]->inst_c0 = data;
10543 #else
10544                                 sp [-1]->inst_ls_word = data;
10545                                 if ((*ip) == CEE_CONV_U8)
10546                                         sp [-1]->inst_ms_word = 0;
10547                                 else
10548                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
10549 #endif
10550                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
10551                         }
10552                         else {
10553                                 ADD_UNOP (*ip);
10554                         }
10555                         ip++;
10556                         break;
10557                 case CEE_CONV_OVF_I4:
10558                 case CEE_CONV_OVF_I1:
10559                 case CEE_CONV_OVF_I2:
10560                 case CEE_CONV_OVF_I:
10561                 case CEE_CONV_OVF_U:
10562                         CHECK_STACK (1);
10563
10564                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10565                                 ADD_UNOP (CEE_CONV_OVF_I8);
10566                                 ADD_UNOP (*ip);
10567                         } else {
10568                                 ADD_UNOP (*ip);
10569                         }
10570                         ip++;
10571                         break;
10572                 case CEE_CONV_OVF_U1:
10573                 case CEE_CONV_OVF_U2:
10574                 case CEE_CONV_OVF_U4:
10575                         CHECK_STACK (1);
10576
10577                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10578                                 ADD_UNOP (CEE_CONV_OVF_U8);
10579                                 ADD_UNOP (*ip);
10580                         } else {
10581                                 ADD_UNOP (*ip);
10582                         }
10583                         ip++;
10584                         break;
10585                 case CEE_CONV_OVF_I1_UN:
10586                 case CEE_CONV_OVF_I2_UN:
10587                 case CEE_CONV_OVF_I4_UN:
10588                 case CEE_CONV_OVF_I8_UN:
10589                 case CEE_CONV_OVF_U1_UN:
10590                 case CEE_CONV_OVF_U2_UN:
10591                 case CEE_CONV_OVF_U4_UN:
10592                 case CEE_CONV_OVF_U8_UN:
10593                 case CEE_CONV_OVF_I_UN:
10594                 case CEE_CONV_OVF_U_UN:
10595                 case CEE_CONV_U2:
10596                 case CEE_CONV_U1:
10597                 case CEE_CONV_I:
10598                 case CEE_CONV_U:
10599                         CHECK_STACK (1);
10600                         ADD_UNOP (*ip);
10601                         CHECK_CFG_EXCEPTION;
10602                         ip++;
10603                         break;
10604                 case CEE_ADD_OVF:
10605                 case CEE_ADD_OVF_UN:
10606                 case CEE_MUL_OVF:
10607                 case CEE_MUL_OVF_UN:
10608                 case CEE_SUB_OVF:
10609                 case CEE_SUB_OVF_UN:
10610                         CHECK_STACK (2);
10611                         ADD_BINOP (*ip);
10612                         ip++;
10613                         break;
10614                 case CEE_CPOBJ:
10615                         GSHAREDVT_FAILURE (*ip);
10616                         CHECK_OPSIZE (5);
10617                         CHECK_STACK (2);
10618                         token = read32 (ip + 1);
10619                         klass = mini_get_class (method, token, generic_context);
10620                         CHECK_TYPELOAD (klass);
10621                         sp -= 2;
10622                         if (generic_class_is_reference_type (cfg, klass)) {
10623                                 MonoInst *store, *load;
10624                                 int dreg = alloc_ireg_ref (cfg);
10625
10626                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
10627                                 load->flags |= ins_flag;
10628                                 MONO_ADD_INS (cfg->cbb, load);
10629
10630                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
10631                                 store->flags |= ins_flag;
10632                                 MONO_ADD_INS (cfg->cbb, store);
10633
10634                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
10635                                         emit_write_barrier (cfg, sp [0], sp [1]);
10636                         } else {
10637                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10638                         }
10639                         ins_flag = 0;
10640                         ip += 5;
10641                         break;
10642                 case CEE_LDOBJ: {
10643                         int loc_index = -1;
10644                         int stloc_len = 0;
10645
10646                         CHECK_OPSIZE (5);
10647                         CHECK_STACK (1);
10648                         --sp;
10649                         token = read32 (ip + 1);
10650                         klass = mini_get_class (method, token, generic_context);
10651                         CHECK_TYPELOAD (klass);
10652
10653                         /* Optimize the common ldobj+stloc combination */
10654                         switch (ip [5]) {
10655                         case CEE_STLOC_S:
10656                                 loc_index = ip [6];
10657                                 stloc_len = 2;
10658                                 break;
10659                         case CEE_STLOC_0:
10660                         case CEE_STLOC_1:
10661                         case CEE_STLOC_2:
10662                         case CEE_STLOC_3:
10663                                 loc_index = ip [5] - CEE_STLOC_0;
10664                                 stloc_len = 1;
10665                                 break;
10666                         default:
10667                                 break;
10668                         }
10669
10670                         if ((loc_index != -1) && ip_in_bb (cfg, cfg->cbb, ip + 5)) {
10671                                 CHECK_LOCAL (loc_index);
10672
10673                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10674                                 ins->dreg = cfg->locals [loc_index]->dreg;
10675                                 ins->flags |= ins_flag;
10676                                 ip += 5;
10677                                 ip += stloc_len;
10678                                 if (ins_flag & MONO_INST_VOLATILE) {
10679                                         /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10680                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10681                                 }
10682                                 ins_flag = 0;
10683                                 break;
10684                         }
10685
10686                         /* Optimize the ldobj+stobj combination */
10687                         /* The reference case ends up being a load+store anyway */
10688                         /* Skip this if the operation is volatile. */
10689                         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)) {
10690                                 CHECK_STACK (1);
10691
10692                                 sp --;
10693
10694                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10695
10696                                 ip += 5 + 5;
10697                                 ins_flag = 0;
10698                                 break;
10699                         }
10700
10701                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10702                         ins->flags |= ins_flag;
10703                         *sp++ = ins;
10704
10705                         if (ins_flag & MONO_INST_VOLATILE) {
10706                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10707                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10708                         }
10709
10710                         ip += 5;
10711                         ins_flag = 0;
10712                         inline_costs += 1;
10713                         break;
10714                 }
10715                 case CEE_LDSTR:
10716                         CHECK_STACK_OVF (1);
10717                         CHECK_OPSIZE (5);
10718                         n = read32 (ip + 1);
10719
10720                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
10721                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
10722                                 ins->type = STACK_OBJ;
10723                                 *sp = ins;
10724                         }
10725                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
10726                                 MonoInst *iargs [1];
10727                                 char *str = (char *)mono_method_get_wrapper_data (method, n);
10728
10729                                 if (cfg->compile_aot)
10730                                         EMIT_NEW_LDSTRLITCONST (cfg, iargs [0], str);
10731                                 else
10732                                         EMIT_NEW_PCONST (cfg, iargs [0], str);
10733                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
10734                         } else {
10735                                 if (cfg->opt & MONO_OPT_SHARED) {
10736                                         MonoInst *iargs [3];
10737
10738                                         if (cfg->compile_aot) {
10739                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
10740                                         }
10741                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10742                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
10743                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
10744                                         *sp = mono_emit_jit_icall (cfg, mono_ldstr, iargs);
10745                                         mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
10746                                 } else {
10747                                         if (cfg->cbb->out_of_line) {
10748                                                 MonoInst *iargs [2];
10749
10750                                                 if (image == mono_defaults.corlib) {
10751                                                         /* 
10752                                                          * Avoid relocations in AOT and save some space by using a 
10753                                                          * version of helper_ldstr specialized to mscorlib.
10754                                                          */
10755                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
10756                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
10757                                                 } else {
10758                                                         /* Avoid creating the string object */
10759                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
10760                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
10761                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
10762                                                 }
10763                                         } 
10764                                         else
10765                                         if (cfg->compile_aot) {
10766                                                 NEW_LDSTRCONST (cfg, ins, image, n);
10767                                                 *sp = ins;
10768                                                 MONO_ADD_INS (cfg->cbb, ins);
10769                                         } 
10770                                         else {
10771                                                 NEW_PCONST (cfg, ins, NULL);
10772                                                 ins->type = STACK_OBJ;
10773                                                 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
10774                                                 if (!ins->inst_p0)
10775                                                         OUT_OF_MEMORY_FAILURE;
10776
10777                                                 *sp = ins;
10778                                                 MONO_ADD_INS (cfg->cbb, ins);
10779                                         }
10780                                 }
10781                         }
10782
10783                         sp++;
10784                         ip += 5;
10785                         break;
10786                 case CEE_NEWOBJ: {
10787                         MonoInst *iargs [2];
10788                         MonoMethodSignature *fsig;
10789                         MonoInst this_ins;
10790                         MonoInst *alloc;
10791                         MonoInst *vtable_arg = NULL;
10792
10793                         CHECK_OPSIZE (5);
10794                         token = read32 (ip + 1);
10795                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
10796                         CHECK_CFG_ERROR;
10797
10798                         fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
10799                         CHECK_CFG_ERROR;
10800
10801                         mono_save_token_info (cfg, image, token, cmethod);
10802
10803                         if (!mono_class_init (cmethod->klass))
10804                                 TYPE_LOAD_ERROR (cmethod->klass);
10805
10806                         context_used = mini_method_check_context_used (cfg, cmethod);
10807
10808                         if (mono_security_core_clr_enabled ())
10809                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
10810
10811                         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)) {
10812                                 emit_class_init (cfg, cmethod->klass);
10813                                 CHECK_TYPELOAD (cmethod->klass);
10814                         }
10815
10816                         /*
10817                         if (cfg->gsharedvt) {
10818                                 if (mini_is_gsharedvt_variable_signature (sig))
10819                                         GSHAREDVT_FAILURE (*ip);
10820                         }
10821                         */
10822
10823                         n = fsig->param_count;
10824                         CHECK_STACK (n);
10825
10826                         /* 
10827                          * Generate smaller code for the common newobj <exception> instruction in
10828                          * argument checking code.
10829                          */
10830                         if (cfg->cbb->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
10831                                 is_exception_class (cmethod->klass) && n <= 2 &&
10832                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
10833                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
10834                                 MonoInst *iargs [3];
10835
10836                                 sp -= n;
10837
10838                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
10839                                 switch (n) {
10840                                 case 0:
10841                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
10842                                         break;
10843                                 case 1:
10844                                         iargs [1] = sp [0];
10845                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
10846                                         break;
10847                                 case 2:
10848                                         iargs [1] = sp [0];
10849                                         iargs [2] = sp [1];
10850                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
10851                                         break;
10852                                 default:
10853                                         g_assert_not_reached ();
10854                                 }
10855
10856                                 ip += 5;
10857                                 inline_costs += 5;
10858                                 break;
10859                         }
10860
10861                         /* move the args to allow room for 'this' in the first position */
10862                         while (n--) {
10863                                 --sp;
10864                                 sp [1] = sp [0];
10865                         }
10866
10867                         /* check_call_signature () requires sp[0] to be set */
10868                         this_ins.type = STACK_OBJ;
10869                         sp [0] = &this_ins;
10870                         if (check_call_signature (cfg, fsig, sp))
10871                                 UNVERIFIED;
10872
10873                         iargs [0] = NULL;
10874
10875                         if (mini_class_is_system_array (cmethod->klass)) {
10876                                 *sp = emit_get_rgctx_method (cfg, context_used,
10877                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
10878
10879                                 /* Avoid varargs in the common case */
10880                                 if (fsig->param_count == 1)
10881                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
10882                                 else if (fsig->param_count == 2)
10883                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
10884                                 else if (fsig->param_count == 3)
10885                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
10886                                 else if (fsig->param_count == 4)
10887                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
10888                                 else
10889                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
10890                         } else if (cmethod->string_ctor) {
10891                                 g_assert (!context_used);
10892                                 g_assert (!vtable_arg);
10893                                 /* we simply pass a null pointer */
10894                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
10895                                 /* now call the string ctor */
10896                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
10897                         } else {
10898                                 if (cmethod->klass->valuetype) {
10899                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
10900                                         emit_init_rvar (cfg, iargs [0]->dreg, &cmethod->klass->byval_arg);
10901                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
10902
10903                                         alloc = NULL;
10904
10905                                         /* 
10906                                          * The code generated by mini_emit_virtual_call () expects
10907                                          * iargs [0] to be a boxed instance, but luckily the vcall
10908                                          * will be transformed into a normal call there.
10909                                          */
10910                                 } else if (context_used) {
10911                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
10912                                         *sp = alloc;
10913                                 } else {
10914                                         MonoVTable *vtable = NULL;
10915
10916                                         if (!cfg->compile_aot)
10917                                                 vtable = mono_class_vtable (cfg->domain, cmethod->klass);
10918                                         CHECK_TYPELOAD (cmethod->klass);
10919
10920                                         /*
10921                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
10922                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
10923                                          * As a workaround, we call class cctors before allocating objects.
10924                                          */
10925                                         if (mini_field_access_needs_cctor_run (cfg, method, cmethod->klass, vtable) && !(g_slist_find (class_inits, cmethod->klass))) {
10926                                                 emit_class_init (cfg, cmethod->klass);
10927                                                 if (cfg->verbose_level > 2)
10928                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
10929                                                 class_inits = g_slist_prepend (class_inits, cmethod->klass);
10930                                         }
10931
10932                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
10933                                         *sp = alloc;
10934                                 }
10935                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
10936
10937                                 if (alloc)
10938                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
10939
10940                                 /* Now call the actual ctor */
10941                                 handle_ctor_call (cfg, cmethod, fsig, context_used, sp, ip, &inline_costs);
10942                                 CHECK_CFG_EXCEPTION;
10943                         }
10944
10945                         if (alloc == NULL) {
10946                                 /* Valuetype */
10947                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
10948                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
10949                                 *sp++= ins;
10950                         } else {
10951                                 *sp++ = alloc;
10952                         }
10953                         
10954                         ip += 5;
10955                         inline_costs += 5;
10956                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip - header->code)))
10957                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10958                         break;
10959                 }
10960                 case CEE_CASTCLASS:
10961                         CHECK_STACK (1);
10962                         --sp;
10963                         CHECK_OPSIZE (5);
10964                         token = read32 (ip + 1);
10965                         klass = mini_get_class (method, token, generic_context);
10966                         CHECK_TYPELOAD (klass);
10967                         if (sp [0]->type != STACK_OBJ)
10968                                 UNVERIFIED;
10969
10970                         ins = handle_castclass (cfg, klass, *sp, ip, &inline_costs);
10971                         CHECK_CFG_EXCEPTION;
10972
10973                         *sp ++ = ins;
10974                         ip += 5;
10975                         break;
10976                 case CEE_ISINST: {
10977                         CHECK_STACK (1);
10978                         --sp;
10979                         CHECK_OPSIZE (5);
10980                         token = read32 (ip + 1);
10981                         klass = mini_get_class (method, token, generic_context);
10982                         CHECK_TYPELOAD (klass);
10983                         if (sp [0]->type != STACK_OBJ)
10984                                 UNVERIFIED;
10985  
10986                         context_used = mini_class_check_context_used (cfg, klass);
10987
10988                         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
10989                                 MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
10990                                 MonoInst *args [3];
10991                                 int idx;
10992
10993                                 /* obj */
10994                                 args [0] = *sp;
10995
10996                                 /* klass */
10997                                 EMIT_NEW_CLASSCONST (cfg, args [1], klass);
10998
10999                                 /* inline cache*/
11000                                 idx = get_castclass_cache_idx (cfg);
11001                                 args [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
11002
11003                                 *sp++ = mono_emit_method_call (cfg, mono_isinst, args, NULL);
11004                                 ip += 5;
11005                                 inline_costs += 2;
11006                         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
11007                                 MonoMethod *mono_isinst;
11008                                 MonoInst *iargs [1];
11009                                 int costs;
11010
11011                                 mono_isinst = mono_marshal_get_isinst (klass); 
11012                                 iargs [0] = sp [0];
11013
11014                                 costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), 
11015                                                                            iargs, ip, cfg->real_offset, TRUE);
11016                                 CHECK_CFG_EXCEPTION;
11017                                 g_assert (costs > 0);
11018                                 
11019                                 ip += 5;
11020                                 cfg->real_offset += 5;
11021
11022                                 *sp++= iargs [0];
11023
11024                                 inline_costs += costs;
11025                         }
11026                         else {
11027                                 ins = handle_isinst (cfg, klass, *sp, context_used);
11028                                 CHECK_CFG_EXCEPTION;
11029                                 *sp ++ = ins;
11030                                 ip += 5;
11031                         }
11032                         break;
11033                 }
11034                 case CEE_UNBOX_ANY: {
11035                         MonoInst *res, *addr;
11036
11037                         CHECK_STACK (1);
11038                         --sp;
11039                         CHECK_OPSIZE (5);
11040                         token = read32 (ip + 1);
11041                         klass = mini_get_class (method, token, generic_context);
11042                         CHECK_TYPELOAD (klass);
11043
11044                         mono_save_token_info (cfg, image, token, klass);
11045
11046                         context_used = mini_class_check_context_used (cfg, klass);
11047
11048                         if (mini_is_gsharedvt_klass (klass)) {
11049                                 res = handle_unbox_gsharedvt (cfg, klass, *sp);
11050                                 inline_costs += 2;
11051                         } else if (generic_class_is_reference_type (cfg, klass)) {
11052                                 res = handle_castclass (cfg, klass, *sp, ip, &inline_costs);
11053                                 CHECK_CFG_EXCEPTION;
11054                         } else if (mono_class_is_nullable (klass)) {
11055                                 res = handle_unbox_nullable (cfg, *sp, klass, context_used);
11056                         } else {
11057                                 addr = handle_unbox (cfg, klass, sp, context_used);
11058                                 /* LDOBJ */
11059                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11060                                 res = ins;
11061                                 inline_costs += 2;
11062                         }
11063
11064                         *sp ++ = res;
11065                         ip += 5;
11066                         break;
11067                 }
11068                 case CEE_BOX: {
11069                         MonoInst *val;
11070                         MonoClass *enum_class;
11071                         MonoMethod *has_flag;
11072
11073                         CHECK_STACK (1);
11074                         --sp;
11075                         val = *sp;
11076                         CHECK_OPSIZE (5);
11077                         token = read32 (ip + 1);
11078                         klass = mini_get_class (method, token, generic_context);
11079                         CHECK_TYPELOAD (klass);
11080
11081                         mono_save_token_info (cfg, image, token, klass);
11082
11083                         context_used = mini_class_check_context_used (cfg, klass);
11084
11085                         if (generic_class_is_reference_type (cfg, klass)) {
11086                                 *sp++ = val;
11087                                 ip += 5;
11088                                 break;
11089                         }
11090
11091                         if (klass == mono_defaults.void_class)
11092                                 UNVERIFIED;
11093                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
11094                                 UNVERIFIED;
11095                         /* frequent check in generic code: box (struct), brtrue */
11096
11097                         /*
11098                          * Look for:
11099                          *
11100                          *   <push int/long ptr>
11101                          *   <push int/long>
11102                          *   box MyFlags
11103                          *   constrained. MyFlags
11104                          *   callvirt instace bool class [mscorlib] System.Enum::HasFlag (class [mscorlib] System.Enum)
11105                          *
11106                          * If we find this sequence and the operand types on box and constrained
11107                          * are equal, we can emit a specialized instruction sequence instead of
11108                          * the very slow HasFlag () call.
11109                          */
11110                         if ((cfg->opt & MONO_OPT_INTRINS) &&
11111                             /* Cheap checks first. */
11112                             ip + 5 + 6 + 5 < end &&
11113                             ip [5] == CEE_PREFIX1 &&
11114                             ip [6] == CEE_CONSTRAINED_ &&
11115                             ip [11] == CEE_CALLVIRT &&
11116                             ip_in_bb (cfg, cfg->cbb, ip + 5 + 6 + 5) &&
11117                             mono_class_is_enum (klass) &&
11118                             (enum_class = mini_get_class (method, read32 (ip + 7), generic_context)) &&
11119                             (has_flag = mini_get_method (cfg, method, read32 (ip + 12), NULL, generic_context)) &&
11120                             has_flag->klass == mono_defaults.enum_class &&
11121                             !strcmp (has_flag->name, "HasFlag") &&
11122                             has_flag->signature->hasthis &&
11123                             has_flag->signature->param_count == 1) {
11124                                 CHECK_TYPELOAD (enum_class);
11125
11126                                 if (enum_class == klass) {
11127                                         MonoInst *enum_this, *enum_flag;
11128
11129                                         ip += 5 + 6 + 5;
11130                                         --sp;
11131
11132                                         enum_this = sp [0];
11133                                         enum_flag = sp [1];
11134
11135                                         *sp++ = handle_enum_has_flag (cfg, klass, enum_this, enum_flag);
11136                                         break;
11137                                 }
11138                         }
11139
11140                         // FIXME: LLVM can't handle the inconsistent bb linking
11141                         if (!mono_class_is_nullable (klass) &&
11142                                 !mini_is_gsharedvt_klass (klass) &&
11143                                 ip + 5 < end && ip_in_bb (cfg, cfg->cbb, ip + 5) &&
11144                                 (ip [5] == CEE_BRTRUE || 
11145                                  ip [5] == CEE_BRTRUE_S ||
11146                                  ip [5] == CEE_BRFALSE ||
11147                                  ip [5] == CEE_BRFALSE_S)) {
11148                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
11149                                 int dreg;
11150                                 MonoBasicBlock *true_bb, *false_bb;
11151
11152                                 ip += 5;
11153
11154                                 if (cfg->verbose_level > 3) {
11155                                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
11156                                         printf ("<box+brtrue opt>\n");
11157                                 }
11158
11159                                 switch (*ip) {
11160                                 case CEE_BRTRUE_S:
11161                                 case CEE_BRFALSE_S:
11162                                         CHECK_OPSIZE (2);
11163                                         ip++;
11164                                         target = ip + 1 + (signed char)(*ip);
11165                                         ip++;
11166                                         break;
11167                                 case CEE_BRTRUE:
11168                                 case CEE_BRFALSE:
11169                                         CHECK_OPSIZE (5);
11170                                         ip++;
11171                                         target = ip + 4 + (gint)(read32 (ip));
11172                                         ip += 4;
11173                                         break;
11174                                 default:
11175                                         g_assert_not_reached ();
11176                                 }
11177
11178                                 /* 
11179                                  * We need to link both bblocks, since it is needed for handling stack
11180                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
11181                                  * Branching to only one of them would lead to inconsistencies, so
11182                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
11183                                  */
11184                                 GET_BBLOCK (cfg, true_bb, target);
11185                                 GET_BBLOCK (cfg, false_bb, ip);
11186
11187                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
11188                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
11189
11190                                 if (sp != stack_start) {
11191                                         handle_stack_args (cfg, stack_start, sp - stack_start);
11192                                         sp = stack_start;
11193                                         CHECK_UNVERIFIABLE (cfg);
11194                                 }
11195
11196                                 if (COMPILE_LLVM (cfg)) {
11197                                         dreg = alloc_ireg (cfg);
11198                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
11199                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
11200
11201                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
11202                                 } else {
11203                                         /* The JIT can't eliminate the iconst+compare */
11204                                         MONO_INST_NEW (cfg, ins, OP_BR);
11205                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
11206                                         MONO_ADD_INS (cfg->cbb, ins);
11207                                 }
11208
11209                                 start_new_bblock = 1;
11210                                 break;
11211                         }
11212
11213                         *sp++ = handle_box (cfg, val, klass, context_used);
11214
11215                         CHECK_CFG_EXCEPTION;
11216                         ip += 5;
11217                         inline_costs += 1;
11218                         break;
11219                 }
11220                 case CEE_UNBOX: {
11221                         CHECK_STACK (1);
11222                         --sp;
11223                         CHECK_OPSIZE (5);
11224                         token = read32 (ip + 1);
11225                         klass = mini_get_class (method, token, generic_context);
11226                         CHECK_TYPELOAD (klass);
11227
11228                         mono_save_token_info (cfg, image, token, klass);
11229
11230                         context_used = mini_class_check_context_used (cfg, klass);
11231
11232                         if (mono_class_is_nullable (klass)) {
11233                                 MonoInst *val;
11234
11235                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
11236                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
11237
11238                                 *sp++= ins;
11239                         } else {
11240                                 ins = handle_unbox (cfg, klass, sp, context_used);
11241                                 *sp++ = ins;
11242                         }
11243                         ip += 5;
11244                         inline_costs += 2;
11245                         break;
11246                 }
11247                 case CEE_LDFLD:
11248                 case CEE_LDFLDA:
11249                 case CEE_STFLD:
11250                 case CEE_LDSFLD:
11251                 case CEE_LDSFLDA:
11252                 case CEE_STSFLD: {
11253                         MonoClassField *field;
11254 #ifndef DISABLE_REMOTING
11255                         int costs;
11256 #endif
11257                         guint foffset;
11258                         gboolean is_instance;
11259                         int op;
11260                         gpointer addr = NULL;
11261                         gboolean is_special_static;
11262                         MonoType *ftype;
11263                         MonoInst *store_val = NULL;
11264                         MonoInst *thread_ins;
11265
11266                         op = *ip;
11267                         is_instance = (op == CEE_LDFLD || op == CEE_LDFLDA || op == CEE_STFLD);
11268                         if (is_instance) {
11269                                 if (op == CEE_STFLD) {
11270                                         CHECK_STACK (2);
11271                                         sp -= 2;
11272                                         store_val = sp [1];
11273                                 } else {
11274                                         CHECK_STACK (1);
11275                                         --sp;
11276                                 }
11277                                 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
11278                                         UNVERIFIED;
11279                                 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
11280                                         UNVERIFIED;
11281                         } else {
11282                                 if (op == CEE_STSFLD) {
11283                                         CHECK_STACK (1);
11284                                         sp--;
11285                                         store_val = sp [0];
11286                                 }
11287                         }
11288
11289                         CHECK_OPSIZE (5);
11290                         token = read32 (ip + 1);
11291                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
11292                                 field = (MonoClassField *)mono_method_get_wrapper_data (method, token);
11293                                 klass = field->parent;
11294                         }
11295                         else {
11296                                 field = mono_field_from_token_checked (image, token, &klass, generic_context, &cfg->error);
11297                                 CHECK_CFG_ERROR;
11298                         }
11299                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
11300                                 FIELD_ACCESS_FAILURE (method, field);
11301                         mono_class_init (klass);
11302
11303                         /* if the class is Critical then transparent code cannot access it's fields */
11304                         if (!is_instance && mono_security_core_clr_enabled ())
11305                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
11306
11307                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
11308                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
11309                         if (mono_security_core_clr_enabled ())
11310                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
11311                         */
11312
11313                         ftype = mono_field_get_type (field);
11314
11315                         /*
11316                          * LDFLD etc. is usable on static fields as well, so convert those cases to
11317                          * the static case.
11318                          */
11319                         if (is_instance && ftype->attrs & FIELD_ATTRIBUTE_STATIC) {
11320                                 switch (op) {
11321                                 case CEE_LDFLD:
11322                                         op = CEE_LDSFLD;
11323                                         break;
11324                                 case CEE_STFLD:
11325                                         op = CEE_STSFLD;
11326                                         break;
11327                                 case CEE_LDFLDA:
11328                                         op = CEE_LDSFLDA;
11329                                         break;
11330                                 default:
11331                                         g_assert_not_reached ();
11332                                 }
11333                                 is_instance = FALSE;
11334                         }
11335
11336                         context_used = mini_class_check_context_used (cfg, klass);
11337
11338                         /* INSTANCE CASE */
11339
11340                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
11341                         if (op == CEE_STFLD) {
11342                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
11343                                         UNVERIFIED;
11344 #ifndef DISABLE_REMOTING
11345                                 if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
11346                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
11347                                         MonoInst *iargs [5];
11348
11349                                         GSHAREDVT_FAILURE (op);
11350
11351                                         iargs [0] = sp [0];
11352                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11353                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
11354                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
11355                                                     field->offset);
11356                                         iargs [4] = sp [1];
11357
11358                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
11359                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
11360                                                                                            iargs, ip, cfg->real_offset, TRUE);
11361                                                 CHECK_CFG_EXCEPTION;
11362                                                 g_assert (costs > 0);
11363                                                       
11364                                                 cfg->real_offset += 5;
11365
11366                                                 inline_costs += costs;
11367                                         } else {
11368                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
11369                                         }
11370                                 } else
11371 #endif
11372                                 {
11373                                         MonoInst *store;
11374
11375                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
11376
11377                                         if (mini_is_gsharedvt_klass (klass)) {
11378                                                 MonoInst *offset_ins;
11379
11380                                                 context_used = mini_class_check_context_used (cfg, klass);
11381
11382                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11383                                                 /* The value is offset by 1 */
11384                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11385                                                 dreg = alloc_ireg_mp (cfg);
11386                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11387                                                 /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
11388                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
11389                                         } else {
11390                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
11391                                         }
11392                                         if (sp [0]->opcode != OP_LDADDR)
11393                                                 store->flags |= MONO_INST_FAULT;
11394
11395                                 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)) {
11396                                         /* insert call to write barrier */
11397                                         MonoInst *ptr;
11398                                         int dreg;
11399
11400                                         dreg = alloc_ireg_mp (cfg);
11401                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
11402                                         emit_write_barrier (cfg, ptr, sp [1]);
11403                                 }
11404
11405                                         store->flags |= ins_flag;
11406                                 }
11407                                 ins_flag = 0;
11408                                 ip += 5;
11409                                 break;
11410                         }
11411
11412 #ifndef DISABLE_REMOTING
11413                         if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
11414                                 MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
11415                                 MonoInst *iargs [4];
11416
11417                                 GSHAREDVT_FAILURE (op);
11418
11419                                 iargs [0] = sp [0];
11420                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11421                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
11422                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
11423                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
11424                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
11425                                                                                    iargs, ip, cfg->real_offset, TRUE);
11426                                         CHECK_CFG_EXCEPTION;
11427                                         g_assert (costs > 0);
11428                                                       
11429                                         cfg->real_offset += 5;
11430
11431                                         *sp++ = iargs [0];
11432
11433                                         inline_costs += costs;
11434                                 } else {
11435                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
11436                                         *sp++ = ins;
11437                                 }
11438                         } else 
11439 #endif
11440                         if (is_instance) {
11441                                 if (sp [0]->type == STACK_VTYPE) {
11442                                         MonoInst *var;
11443
11444                                         /* Have to compute the address of the variable */
11445
11446                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
11447                                         if (!var)
11448                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
11449                                         else
11450                                                 g_assert (var->klass == klass);
11451                                         
11452                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
11453                                         sp [0] = ins;
11454                                 }
11455
11456                                 if (op == CEE_LDFLDA) {
11457                                         if (sp [0]->type == STACK_OBJ) {
11458                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
11459                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
11460                                         }
11461
11462                                         dreg = alloc_ireg_mp (cfg);
11463
11464                                         if (mini_is_gsharedvt_klass (klass)) {
11465                                                 MonoInst *offset_ins;
11466
11467                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11468                                                 /* The value is offset by 1 */
11469                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11470                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11471                                         } else {
11472                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
11473                                         }
11474                                         ins->klass = mono_class_from_mono_type (field->type);
11475                                         ins->type = STACK_MP;
11476                                         *sp++ = ins;
11477                                 } else {
11478                                         MonoInst *load;
11479
11480                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
11481
11482                                         if (mini_is_gsharedvt_klass (klass)) {
11483                                                 MonoInst *offset_ins;
11484
11485                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11486                                                 /* The value is offset by 1 */
11487                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11488                                                 dreg = alloc_ireg_mp (cfg);
11489                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11490                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
11491                                         } else {
11492                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
11493                                         }
11494                                         load->flags |= ins_flag;
11495                                         if (sp [0]->opcode != OP_LDADDR)
11496                                                 load->flags |= MONO_INST_FAULT;
11497                                         *sp++ = load;
11498                                 }
11499                         }
11500
11501                         if (is_instance) {
11502                                 ins_flag = 0;
11503                                 ip += 5;
11504                                 break;
11505                         }
11506
11507                         /* STATIC CASE */
11508                         context_used = mini_class_check_context_used (cfg, klass);
11509
11510                         if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL) {
11511                                 mono_error_set_field_load (&cfg->error, field->parent, field->name, "Using static instructions with literal field");
11512                                 CHECK_CFG_ERROR;
11513                         }
11514
11515                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
11516                          * to be called here.
11517                          */
11518                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
11519                                 mono_class_vtable (cfg->domain, klass);
11520                                 CHECK_TYPELOAD (klass);
11521                         }
11522                         mono_domain_lock (cfg->domain);
11523                         if (cfg->domain->special_static_fields)
11524                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
11525                         mono_domain_unlock (cfg->domain);
11526
11527                         is_special_static = mono_class_field_is_special_static (field);
11528
11529                         if (is_special_static && ((gsize)addr & 0x80000000) == 0)
11530                                 thread_ins = mono_get_thread_intrinsic (cfg);
11531                         else
11532                                 thread_ins = NULL;
11533
11534                         /* Generate IR to compute the field address */
11535                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && thread_ins && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
11536                                 /*
11537                                  * Fast access to TLS data
11538                                  * Inline version of get_thread_static_data () in
11539                                  * threads.c.
11540                                  */
11541                                 guint32 offset;
11542                                 int idx, static_data_reg, array_reg, dreg;
11543
11544                                 GSHAREDVT_FAILURE (op);
11545
11546                                 MONO_ADD_INS (cfg->cbb, thread_ins);
11547                                 static_data_reg = alloc_ireg (cfg);
11548                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
11549
11550                                 if (cfg->compile_aot) {
11551                                         int offset_reg, offset2_reg, idx_reg;
11552
11553                                         /* For TLS variables, this will return the TLS offset */
11554                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
11555                                         offset_reg = ins->dreg;
11556                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
11557                                         idx_reg = alloc_ireg (cfg);
11558                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, idx_reg, offset_reg, 0x3f);
11559                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
11560                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
11561                                         array_reg = alloc_ireg (cfg);
11562                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
11563                                         offset2_reg = alloc_ireg (cfg);
11564                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, offset2_reg, offset_reg, 6);
11565                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset2_reg, 0x1ffffff);
11566                                         dreg = alloc_ireg (cfg);
11567                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
11568                                 } else {
11569                                         offset = (gsize)addr & 0x7fffffff;
11570                                         idx = offset & 0x3f;
11571
11572                                         array_reg = alloc_ireg (cfg);
11573                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
11574                                         dreg = alloc_ireg (cfg);
11575                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, ((offset >> 6) & 0x1ffffff));
11576                                 }
11577                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
11578                                         (cfg->compile_aot && is_special_static) ||
11579                                         (context_used && is_special_static)) {
11580                                 MonoInst *iargs [2];
11581
11582                                 g_assert (field->parent);
11583                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11584                                 if (context_used) {
11585                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
11586                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
11587                                 } else {
11588                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11589                                 }
11590                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11591                         } else if (context_used) {
11592                                 MonoInst *static_data;
11593
11594                                 /*
11595                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
11596                                         method->klass->name_space, method->klass->name, method->name,
11597                                         depth, field->offset);
11598                                 */
11599
11600                                 if (mono_class_needs_cctor_run (klass, method))
11601                                         emit_class_init (cfg, klass);
11602
11603                                 /*
11604                                  * The pointer we're computing here is
11605                                  *
11606                                  *   super_info.static_data + field->offset
11607                                  */
11608                                 static_data = emit_get_rgctx_klass (cfg, context_used,
11609                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
11610
11611                                 if (mini_is_gsharedvt_klass (klass)) {
11612                                         MonoInst *offset_ins;
11613
11614                                         offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11615                                         /* The value is offset by 1 */
11616                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11617                                         dreg = alloc_ireg_mp (cfg);
11618                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
11619                                 } else if (field->offset == 0) {
11620                                         ins = static_data;
11621                                 } else {
11622                                         int addr_reg = mono_alloc_preg (cfg);
11623                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
11624                                 }
11625                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
11626                                 MonoInst *iargs [2];
11627
11628                                 g_assert (field->parent);
11629                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11630                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11631                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11632                         } else {
11633                                 MonoVTable *vtable = NULL;
11634
11635                                 if (!cfg->compile_aot)
11636                                         vtable = mono_class_vtable (cfg->domain, klass);
11637                                 CHECK_TYPELOAD (klass);
11638
11639                                 if (!addr) {
11640                                         if (mini_field_access_needs_cctor_run (cfg, method, klass, vtable)) {
11641                                                 if (!(g_slist_find (class_inits, klass))) {
11642                                                         emit_class_init (cfg, klass);
11643                                                         if (cfg->verbose_level > 2)
11644                                                                 printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
11645                                                         class_inits = g_slist_prepend (class_inits, klass);
11646                                                 }
11647                                         } else {
11648                                                 if (cfg->run_cctors) {
11649                                                         /* This makes so that inline cannot trigger */
11650                                                         /* .cctors: too many apps depend on them */
11651                                                         /* running with a specific order... */
11652                                                         g_assert (vtable);
11653                                                         if (! vtable->initialized)
11654                                                                 INLINE_FAILURE ("class init");
11655                                                         if (!mono_runtime_class_init_full (vtable, &cfg->error)) {
11656                                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
11657                                                                 g_assert_not_reached ();
11658                                                                 goto exception_exit;
11659                                                         }
11660                                                 }
11661                                         }
11662                                         if (cfg->compile_aot)
11663                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
11664                                         else {
11665                                                 g_assert (vtable);
11666                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11667                                                 g_assert (addr);
11668                                                 EMIT_NEW_PCONST (cfg, ins, addr);
11669                                         }
11670                                 } else {
11671                                         MonoInst *iargs [1];
11672                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
11673                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
11674                                 }
11675                         }
11676
11677                         /* Generate IR to do the actual load/store operation */
11678
11679                         if ((op == CEE_STFLD || op == CEE_STSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11680                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11681                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11682                         }
11683
11684                         if (op == CEE_LDSFLDA) {
11685                                 ins->klass = mono_class_from_mono_type (ftype);
11686                                 ins->type = STACK_PTR;
11687                                 *sp++ = ins;
11688                         } else if (op == CEE_STSFLD) {
11689                                 MonoInst *store;
11690
11691                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
11692                                 store->flags |= ins_flag;
11693                         } else {
11694                                 gboolean is_const = FALSE;
11695                                 MonoVTable *vtable = NULL;
11696                                 gpointer addr = NULL;
11697
11698                                 if (!context_used) {
11699                                         vtable = mono_class_vtable (cfg->domain, klass);
11700                                         CHECK_TYPELOAD (klass);
11701                                 }
11702                                 if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) ||
11703                                                 (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) {
11704                                         int ro_type = ftype->type;
11705                                         if (!addr)
11706                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11707                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
11708                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
11709                                         }
11710
11711                                         GSHAREDVT_FAILURE (op);
11712
11713                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
11714                                         is_const = TRUE;
11715                                         switch (ro_type) {
11716                                         case MONO_TYPE_BOOLEAN:
11717                                         case MONO_TYPE_U1:
11718                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
11719                                                 sp++;
11720                                                 break;
11721                                         case MONO_TYPE_I1:
11722                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
11723                                                 sp++;
11724                                                 break;                                          
11725                                         case MONO_TYPE_CHAR:
11726                                         case MONO_TYPE_U2:
11727                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
11728                                                 sp++;
11729                                                 break;
11730                                         case MONO_TYPE_I2:
11731                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
11732                                                 sp++;
11733                                                 break;
11734                                                 break;
11735                                         case MONO_TYPE_I4:
11736                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
11737                                                 sp++;
11738                                                 break;                                          
11739                                         case MONO_TYPE_U4:
11740                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
11741                                                 sp++;
11742                                                 break;
11743                                         case MONO_TYPE_I:
11744                                         case MONO_TYPE_U:
11745                                         case MONO_TYPE_PTR:
11746                                         case MONO_TYPE_FNPTR:
11747                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11748                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
11749                                                 sp++;
11750                                                 break;
11751                                         case MONO_TYPE_STRING:
11752                                         case MONO_TYPE_OBJECT:
11753                                         case MONO_TYPE_CLASS:
11754                                         case MONO_TYPE_SZARRAY:
11755                                         case MONO_TYPE_ARRAY:
11756                                                 if (!mono_gc_is_moving ()) {
11757                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11758                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
11759                                                         sp++;
11760                                                 } else {
11761                                                         is_const = FALSE;
11762                                                 }
11763                                                 break;
11764                                         case MONO_TYPE_I8:
11765                                         case MONO_TYPE_U8:
11766                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
11767                                                 sp++;
11768                                                 break;
11769                                         case MONO_TYPE_R4:
11770                                         case MONO_TYPE_R8:
11771                                         case MONO_TYPE_VALUETYPE:
11772                                         default:
11773                                                 is_const = FALSE;
11774                                                 break;
11775                                         }
11776                                 }
11777
11778                                 if (!is_const) {
11779                                         MonoInst *load;
11780
11781                                         CHECK_STACK_OVF (1);
11782
11783                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
11784                                         load->flags |= ins_flag;
11785                                         ins_flag = 0;
11786                                         *sp++ = load;
11787                                 }
11788                         }
11789
11790                         if ((op == CEE_LDFLD || op == CEE_LDSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11791                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
11792                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
11793                         }
11794
11795                         ins_flag = 0;
11796                         ip += 5;
11797                         break;
11798                 }
11799                 case CEE_STOBJ:
11800                         CHECK_STACK (2);
11801                         sp -= 2;
11802                         CHECK_OPSIZE (5);
11803                         token = read32 (ip + 1);
11804                         klass = mini_get_class (method, token, generic_context);
11805                         CHECK_TYPELOAD (klass);
11806                         if (ins_flag & MONO_INST_VOLATILE) {
11807                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11808                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11809                         }
11810                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
11811                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
11812                         ins->flags |= ins_flag;
11813                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
11814                                         generic_class_is_reference_type (cfg, klass)) {
11815                                 /* insert call to write barrier */
11816                                 emit_write_barrier (cfg, sp [0], sp [1]);
11817                         }
11818                         ins_flag = 0;
11819                         ip += 5;
11820                         inline_costs += 1;
11821                         break;
11822
11823                         /*
11824                          * Array opcodes
11825                          */
11826                 case CEE_NEWARR: {
11827                         MonoInst *len_ins;
11828                         const char *data_ptr;
11829                         int data_size = 0;
11830                         guint32 field_token;
11831
11832                         CHECK_STACK (1);
11833                         --sp;
11834
11835                         CHECK_OPSIZE (5);
11836                         token = read32 (ip + 1);
11837
11838                         klass = mini_get_class (method, token, generic_context);
11839                         CHECK_TYPELOAD (klass);
11840
11841                         context_used = mini_class_check_context_used (cfg, klass);
11842
11843                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
11844                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_OVF_U4);
11845                                 ins->sreg1 = sp [0]->dreg;
11846                                 ins->type = STACK_I4;
11847                                 ins->dreg = alloc_ireg (cfg);
11848                                 MONO_ADD_INS (cfg->cbb, ins);
11849                                 *sp = mono_decompose_opcode (cfg, ins);
11850                         }
11851
11852                         if (context_used) {
11853                                 MonoInst *args [3];
11854                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11855                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
11856
11857                                 /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
11858
11859                                 /* vtable */
11860                                 args [0] = emit_get_rgctx_klass (cfg, context_used,
11861                                         array_class, MONO_RGCTX_INFO_VTABLE);
11862                                 /* array len */
11863                                 args [1] = sp [0];
11864
11865                                 if (managed_alloc)
11866                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
11867                                 else
11868                                         ins = mono_emit_jit_icall (cfg, ves_icall_array_new_specific, args);
11869                         } else {
11870                                 if (cfg->opt & MONO_OPT_SHARED) {
11871                                         /* Decompose now to avoid problems with references to the domainvar */
11872                                         MonoInst *iargs [3];
11873
11874                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11875                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11876                                         iargs [2] = sp [0];
11877
11878                                         ins = mono_emit_jit_icall (cfg, mono_array_new, iargs);
11879                                 } else {
11880                                         /* Decompose later since it is needed by abcrem */
11881                                         MonoClass *array_type = mono_array_class_get (klass, 1);
11882                                         mono_class_vtable (cfg->domain, array_type);
11883                                         CHECK_TYPELOAD (array_type);
11884
11885                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
11886                                         ins->dreg = alloc_ireg_ref (cfg);
11887                                         ins->sreg1 = sp [0]->dreg;
11888                                         ins->inst_newa_class = klass;
11889                                         ins->type = STACK_OBJ;
11890                                         ins->klass = array_type;
11891                                         MONO_ADD_INS (cfg->cbb, ins);
11892                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11893                                         cfg->cbb->has_array_access = TRUE;
11894
11895                                         /* Needed so mono_emit_load_get_addr () gets called */
11896                                         mono_get_got_var (cfg);
11897                                 }
11898                         }
11899
11900                         len_ins = sp [0];
11901                         ip += 5;
11902                         *sp++ = ins;
11903                         inline_costs += 1;
11904
11905                         /* 
11906                          * we inline/optimize the initialization sequence if possible.
11907                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
11908                          * for small sizes open code the memcpy
11909                          * ensure the rva field is big enough
11910                          */
11911                         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))) {
11912                                 MonoMethod *memcpy_method = get_memcpy_method ();
11913                                 MonoInst *iargs [3];
11914                                 int add_reg = alloc_ireg_mp (cfg);
11915
11916                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, MONO_STRUCT_OFFSET (MonoArray, vector));
11917                                 if (cfg->compile_aot) {
11918                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
11919                                 } else {
11920                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
11921                                 }
11922                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
11923                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
11924                                 ip += 11;
11925                         }
11926
11927                         break;
11928                 }
11929                 case CEE_LDLEN:
11930                         CHECK_STACK (1);
11931                         --sp;
11932                         if (sp [0]->type != STACK_OBJ)
11933                                 UNVERIFIED;
11934
11935                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
11936                         ins->dreg = alloc_preg (cfg);
11937                         ins->sreg1 = sp [0]->dreg;
11938                         ins->type = STACK_I4;
11939                         /* This flag will be inherited by the decomposition */
11940                         ins->flags |= MONO_INST_FAULT;
11941                         MONO_ADD_INS (cfg->cbb, ins);
11942                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11943                         cfg->cbb->has_array_access = TRUE;
11944                         ip ++;
11945                         *sp++ = ins;
11946                         break;
11947                 case CEE_LDELEMA:
11948                         CHECK_STACK (2);
11949                         sp -= 2;
11950                         CHECK_OPSIZE (5);
11951                         if (sp [0]->type != STACK_OBJ)
11952                                 UNVERIFIED;
11953
11954                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11955
11956                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11957                         CHECK_TYPELOAD (klass);
11958                         /* we need to make sure that this array is exactly the type it needs
11959                          * to be for correctness. the wrappers are lax with their usage
11960                          * so we need to ignore them here
11961                          */
11962                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
11963                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11964                                 mini_emit_check_array_type (cfg, sp [0], array_class);
11965                                 CHECK_TYPELOAD (array_class);
11966                         }
11967
11968                         readonly = FALSE;
11969                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11970                         *sp++ = ins;
11971                         ip += 5;
11972                         break;
11973                 case CEE_LDELEM:
11974                 case CEE_LDELEM_I1:
11975                 case CEE_LDELEM_U1:
11976                 case CEE_LDELEM_I2:
11977                 case CEE_LDELEM_U2:
11978                 case CEE_LDELEM_I4:
11979                 case CEE_LDELEM_U4:
11980                 case CEE_LDELEM_I8:
11981                 case CEE_LDELEM_I:
11982                 case CEE_LDELEM_R4:
11983                 case CEE_LDELEM_R8:
11984                 case CEE_LDELEM_REF: {
11985                         MonoInst *addr;
11986
11987                         CHECK_STACK (2);
11988                         sp -= 2;
11989
11990                         if (*ip == CEE_LDELEM) {
11991                                 CHECK_OPSIZE (5);
11992                                 token = read32 (ip + 1);
11993                                 klass = mini_get_class (method, token, generic_context);
11994                                 CHECK_TYPELOAD (klass);
11995                                 mono_class_init (klass);
11996                         }
11997                         else
11998                                 klass = array_access_to_klass (*ip);
11999
12000                         if (sp [0]->type != STACK_OBJ)
12001                                 UNVERIFIED;
12002
12003                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
12004
12005                         if (mini_is_gsharedvt_variable_klass (klass)) {
12006                                 // FIXME-VT: OP_ICONST optimization
12007                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
12008                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
12009                                 ins->opcode = OP_LOADV_MEMBASE;
12010                         } else if (sp [1]->opcode == OP_ICONST) {
12011                                 int array_reg = sp [0]->dreg;
12012                                 int index_reg = sp [1]->dreg;
12013                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
12014
12015                                 if (SIZEOF_REGISTER == 8 && COMPILE_LLVM (cfg))
12016                                         MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, index_reg);
12017
12018                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
12019                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
12020                         } else {
12021                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
12022                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
12023                         }
12024                         *sp++ = ins;
12025                         if (*ip == CEE_LDELEM)
12026                                 ip += 5;
12027                         else
12028                                 ++ip;
12029                         break;
12030                 }
12031                 case CEE_STELEM_I:
12032                 case CEE_STELEM_I1:
12033                 case CEE_STELEM_I2:
12034                 case CEE_STELEM_I4:
12035                 case CEE_STELEM_I8:
12036                 case CEE_STELEM_R4:
12037                 case CEE_STELEM_R8:
12038                 case CEE_STELEM_REF:
12039                 case CEE_STELEM: {
12040                         CHECK_STACK (3);
12041                         sp -= 3;
12042
12043                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
12044
12045                         if (*ip == CEE_STELEM) {
12046                                 CHECK_OPSIZE (5);
12047                                 token = read32 (ip + 1);
12048                                 klass = mini_get_class (method, token, generic_context);
12049                                 CHECK_TYPELOAD (klass);
12050                                 mono_class_init (klass);
12051                         }
12052                         else
12053                                 klass = array_access_to_klass (*ip);
12054
12055                         if (sp [0]->type != STACK_OBJ)
12056                                 UNVERIFIED;
12057
12058                         emit_array_store (cfg, klass, sp, TRUE);
12059
12060                         if (*ip == CEE_STELEM)
12061                                 ip += 5;
12062                         else
12063                                 ++ip;
12064                         inline_costs += 1;
12065                         break;
12066                 }
12067                 case CEE_CKFINITE: {
12068                         CHECK_STACK (1);
12069                         --sp;
12070
12071                         if (cfg->llvm_only) {
12072                                 MonoInst *iargs [1];
12073
12074                                 iargs [0] = sp [0];
12075                                 *sp++ = mono_emit_jit_icall (cfg, mono_ckfinite, iargs);
12076                         } else  {
12077                                 MONO_INST_NEW (cfg, ins, OP_CKFINITE);
12078                                 ins->sreg1 = sp [0]->dreg;
12079                                 ins->dreg = alloc_freg (cfg);
12080                                 ins->type = STACK_R8;
12081                                 MONO_ADD_INS (cfg->cbb, ins);
12082
12083                                 *sp++ = mono_decompose_opcode (cfg, ins);
12084                         }
12085
12086                         ++ip;
12087                         break;
12088                 }
12089                 case CEE_REFANYVAL: {
12090                         MonoInst *src_var, *src;
12091
12092                         int klass_reg = alloc_preg (cfg);
12093                         int dreg = alloc_preg (cfg);
12094
12095                         GSHAREDVT_FAILURE (*ip);
12096
12097                         CHECK_STACK (1);
12098                         MONO_INST_NEW (cfg, ins, *ip);
12099                         --sp;
12100                         CHECK_OPSIZE (5);
12101                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
12102                         CHECK_TYPELOAD (klass);
12103
12104                         context_used = mini_class_check_context_used (cfg, klass);
12105
12106                         // FIXME:
12107                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12108                         if (!src_var)
12109                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
12110                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
12111                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass));
12112
12113                         if (context_used) {
12114                                 MonoInst *klass_ins;
12115
12116                                 klass_ins = emit_get_rgctx_klass (cfg, context_used,
12117                                                 klass, MONO_RGCTX_INFO_KLASS);
12118
12119                                 // FIXME:
12120                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
12121                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
12122                         } else {
12123                                 mini_emit_class_check (cfg, klass_reg, klass);
12124                         }
12125                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value));
12126                         ins->type = STACK_MP;
12127                         ins->klass = klass;
12128                         *sp++ = ins;
12129                         ip += 5;
12130                         break;
12131                 }
12132                 case CEE_MKREFANY: {
12133                         MonoInst *loc, *addr;
12134
12135                         GSHAREDVT_FAILURE (*ip);
12136
12137                         CHECK_STACK (1);
12138                         MONO_INST_NEW (cfg, ins, *ip);
12139                         --sp;
12140                         CHECK_OPSIZE (5);
12141                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
12142                         CHECK_TYPELOAD (klass);
12143
12144                         context_used = mini_class_check_context_used (cfg, klass);
12145
12146                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
12147                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
12148
12149                         if (context_used) {
12150                                 MonoInst *const_ins;
12151                                 int type_reg = alloc_preg (cfg);
12152
12153                                 const_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
12154                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
12155                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
12156                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
12157                         } else if (cfg->compile_aot) {
12158                                 int const_reg = alloc_preg (cfg);
12159                                 int type_reg = alloc_preg (cfg);
12160
12161                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
12162                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
12163                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
12164                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
12165                         } else {
12166                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), &klass->byval_arg);
12167                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), klass);
12168                         }
12169                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
12170
12171                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
12172                         ins->type = STACK_VTYPE;
12173                         ins->klass = mono_defaults.typed_reference_class;
12174                         *sp++ = ins;
12175                         ip += 5;
12176                         break;
12177                 }
12178                 case CEE_LDTOKEN: {
12179                         gpointer handle;
12180                         MonoClass *handle_class;
12181
12182                         CHECK_STACK_OVF (1);
12183
12184                         CHECK_OPSIZE (5);
12185                         n = read32 (ip + 1);
12186
12187                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
12188                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
12189                                 handle = mono_method_get_wrapper_data (method, n);
12190                                 handle_class = (MonoClass *)mono_method_get_wrapper_data (method, n + 1);
12191                                 if (handle_class == mono_defaults.typehandle_class)
12192                                         handle = &((MonoClass*)handle)->byval_arg;
12193                         }
12194                         else {
12195                                 handle = mono_ldtoken_checked (image, n, &handle_class, generic_context, &cfg->error);
12196                                 CHECK_CFG_ERROR;
12197                         }
12198                         if (!handle)
12199                                 LOAD_ERROR;
12200                         mono_class_init (handle_class);
12201                         if (cfg->gshared) {
12202                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
12203                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
12204                                         /* This case handles ldtoken
12205                                            of an open type, like for
12206                                            typeof(Gen<>). */
12207                                         context_used = 0;
12208                                 } else if (handle_class == mono_defaults.typehandle_class) {
12209                                         context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type ((MonoType *)handle));
12210                                 } else if (handle_class == mono_defaults.fieldhandle_class)
12211                                         context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
12212                                 else if (handle_class == mono_defaults.methodhandle_class)
12213                                         context_used = mini_method_check_context_used (cfg, (MonoMethod *)handle);
12214                                 else
12215                                         g_assert_not_reached ();
12216                         }
12217
12218                         if ((cfg->opt & MONO_OPT_SHARED) &&
12219                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
12220                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
12221                                 MonoInst *addr, *vtvar, *iargs [3];
12222                                 int method_context_used;
12223
12224                                 method_context_used = mini_method_check_context_used (cfg, method);
12225
12226                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
12227
12228                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
12229                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
12230                                 if (method_context_used) {
12231                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
12232                                                 method, MONO_RGCTX_INFO_METHOD);
12233                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
12234                                 } else {
12235                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
12236                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
12237                                 }
12238                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12239
12240                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
12241
12242                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12243                         } else {
12244                                 if ((ip + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 5) && 
12245                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
12246                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
12247                                         (cmethod->klass == mono_defaults.systemtype_class) &&
12248                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
12249                                         MonoClass *tclass = mono_class_from_mono_type ((MonoType *)handle);
12250
12251                                         mono_class_init (tclass);
12252                                         if (context_used) {
12253                                                 ins = emit_get_rgctx_klass (cfg, context_used,
12254                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
12255                                         } else if (cfg->compile_aot) {
12256                                                 if (method->wrapper_type) {
12257                                                         mono_error_init (&error); //got to do it since there are multiple conditionals below
12258                                                         if (mono_class_get_checked (tclass->image, tclass->type_token, &error) == tclass && !generic_context) {
12259                                                                 /* Special case for static synchronized wrappers */
12260                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
12261                                                         } else {
12262                                                                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
12263                                                                 /* FIXME: n is not a normal token */
12264                                                                 DISABLE_AOT (cfg);
12265                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12266                                                         }
12267                                                 } else {
12268                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
12269                                                 }
12270                                         } else {
12271                                                 MonoReflectionType *rt = mono_type_get_object_checked (cfg->domain, (MonoType *)handle, &cfg->error);
12272                                                 CHECK_CFG_ERROR;
12273                                                 EMIT_NEW_PCONST (cfg, ins, rt);
12274                                         }
12275                                         ins->type = STACK_OBJ;
12276                                         ins->klass = cmethod->klass;
12277                                         ip += 5;
12278                                 } else {
12279                                         MonoInst *addr, *vtvar;
12280
12281                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
12282
12283                                         if (context_used) {
12284                                                 if (handle_class == mono_defaults.typehandle_class) {
12285                                                         ins = emit_get_rgctx_klass (cfg, context_used,
12286                                                                         mono_class_from_mono_type ((MonoType *)handle),
12287                                                                         MONO_RGCTX_INFO_TYPE);
12288                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
12289                                                         ins = emit_get_rgctx_method (cfg, context_used,
12290                                                                         (MonoMethod *)handle, MONO_RGCTX_INFO_METHOD);
12291                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
12292                                                         ins = emit_get_rgctx_field (cfg, context_used,
12293                                                                         (MonoClassField *)handle, MONO_RGCTX_INFO_CLASS_FIELD);
12294                                                 } else {
12295                                                         g_assert_not_reached ();
12296                                                 }
12297                                         } else if (cfg->compile_aot) {
12298                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n, generic_context);
12299                                         } else {
12300                                                 EMIT_NEW_PCONST (cfg, ins, handle);
12301                                         }
12302                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12303                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
12304                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12305                                 }
12306                         }
12307
12308                         *sp++ = ins;
12309                         ip += 5;
12310                         break;
12311                 }
12312                 case CEE_THROW:
12313                         CHECK_STACK (1);
12314                         MONO_INST_NEW (cfg, ins, OP_THROW);
12315                         --sp;
12316                         ins->sreg1 = sp [0]->dreg;
12317                         ip++;
12318                         cfg->cbb->out_of_line = TRUE;
12319                         MONO_ADD_INS (cfg->cbb, ins);
12320                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
12321                         MONO_ADD_INS (cfg->cbb, ins);
12322                         sp = stack_start;
12323                         
12324                         link_bblock (cfg, cfg->cbb, end_bblock);
12325                         start_new_bblock = 1;
12326                         /* This can complicate code generation for llvm since the return value might not be defined */
12327                         if (COMPILE_LLVM (cfg))
12328                                 INLINE_FAILURE ("throw");
12329                         break;
12330                 case CEE_ENDFINALLY:
12331                         /* mono_save_seq_point_info () depends on this */
12332                         if (sp != stack_start)
12333                                 emit_seq_point (cfg, method, ip, FALSE, FALSE);
12334                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
12335                         MONO_ADD_INS (cfg->cbb, ins);
12336                         ip++;
12337                         start_new_bblock = 1;
12338
12339                         /*
12340                          * Control will leave the method so empty the stack, otherwise
12341                          * the next basic block will start with a nonempty stack.
12342                          */
12343                         while (sp != stack_start) {
12344                                 sp--;
12345                         }
12346                         break;
12347                 case CEE_LEAVE:
12348                 case CEE_LEAVE_S: {
12349                         GList *handlers;
12350
12351                         if (*ip == CEE_LEAVE) {
12352                                 CHECK_OPSIZE (5);
12353                                 target = ip + 5 + (gint32)read32(ip + 1);
12354                         } else {
12355                                 CHECK_OPSIZE (2);
12356                                 target = ip + 2 + (signed char)(ip [1]);
12357                         }
12358
12359                         /* empty the stack */
12360                         while (sp != stack_start) {
12361                                 sp--;
12362                         }
12363
12364                         /* 
12365                          * If this leave statement is in a catch block, check for a
12366                          * pending exception, and rethrow it if necessary.
12367                          * We avoid doing this in runtime invoke wrappers, since those are called
12368                          * by native code which excepts the wrapper to catch all exceptions.
12369                          */
12370                         for (i = 0; i < header->num_clauses; ++i) {
12371                                 MonoExceptionClause *clause = &header->clauses [i];
12372
12373                                 /* 
12374                                  * Use <= in the final comparison to handle clauses with multiple
12375                                  * leave statements, like in bug #78024.
12376                                  * The ordering of the exception clauses guarantees that we find the
12377                                  * innermost clause.
12378                                  */
12379                                 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) {
12380                                         MonoInst *exc_ins;
12381                                         MonoBasicBlock *dont_throw;
12382
12383                                         /*
12384                                           MonoInst *load;
12385
12386                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
12387                                         */
12388
12389                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
12390
12391                                         NEW_BBLOCK (cfg, dont_throw);
12392
12393                                         /*
12394                                          * Currently, we always rethrow the abort exception, despite the 
12395                                          * fact that this is not correct. See thread6.cs for an example. 
12396                                          * But propagating the abort exception is more important than 
12397                                          * getting the sematics right.
12398                                          */
12399                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
12400                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
12401                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
12402
12403                                         MONO_START_BB (cfg, dont_throw);
12404                                 }
12405                         }
12406
12407 #ifdef ENABLE_LLVM
12408                         cfg->cbb->try_end = (intptr_t)(ip - header->code);
12409 #endif
12410
12411                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
12412                                 GList *tmp;
12413                                 MonoExceptionClause *clause;
12414
12415                                 for (tmp = handlers; tmp; tmp = tmp->next) {
12416                                         clause = (MonoExceptionClause *)tmp->data;
12417                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
12418                                         g_assert (tblock);
12419                                         link_bblock (cfg, cfg->cbb, tblock);
12420                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
12421                                         ins->inst_target_bb = tblock;
12422                                         ins->inst_eh_block = clause;
12423                                         MONO_ADD_INS (cfg->cbb, ins);
12424                                         cfg->cbb->has_call_handler = 1;
12425                                         if (COMPILE_LLVM (cfg)) {
12426                                                 MonoBasicBlock *target_bb;
12427
12428                                                 /* 
12429                                                  * Link the finally bblock with the target, since it will
12430                                                  * conceptually branch there.
12431                                                  */
12432                                                 GET_BBLOCK (cfg, tblock, cfg->cil_start + clause->handler_offset + clause->handler_len - 1);
12433                                                 GET_BBLOCK (cfg, target_bb, target);
12434                                                 link_bblock (cfg, tblock, target_bb);
12435                                         }
12436                                 }
12437                                 g_list_free (handlers);
12438                         } 
12439
12440                         MONO_INST_NEW (cfg, ins, OP_BR);
12441                         MONO_ADD_INS (cfg->cbb, ins);
12442                         GET_BBLOCK (cfg, tblock, target);
12443                         link_bblock (cfg, cfg->cbb, tblock);
12444                         ins->inst_target_bb = tblock;
12445
12446                         start_new_bblock = 1;
12447
12448                         if (*ip == CEE_LEAVE)
12449                                 ip += 5;
12450                         else
12451                                 ip += 2;
12452
12453                         break;
12454                 }
12455
12456                         /*
12457                          * Mono specific opcodes
12458                          */
12459                 case MONO_CUSTOM_PREFIX: {
12460
12461                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
12462
12463                         CHECK_OPSIZE (2);
12464                         switch (ip [1]) {
12465                         case CEE_MONO_ICALL: {
12466                                 gpointer func;
12467                                 MonoJitICallInfo *info;
12468
12469                                 token = read32 (ip + 2);
12470                                 func = mono_method_get_wrapper_data (method, token);
12471                                 info = mono_find_jit_icall_by_addr (func);
12472                                 if (!info)
12473                                         g_error ("Could not find icall address in wrapper %s", mono_method_full_name (method, 1));
12474                                 g_assert (info);
12475
12476                                 CHECK_STACK (info->sig->param_count);
12477                                 sp -= info->sig->param_count;
12478
12479                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
12480                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
12481                                         *sp++ = ins;
12482
12483                                 ip += 6;
12484                                 inline_costs += 10 * num_calls++;
12485
12486                                 break;
12487                         }
12488                         case CEE_MONO_LDPTR_CARD_TABLE:
12489                         case CEE_MONO_LDPTR_NURSERY_START:
12490                         case CEE_MONO_LDPTR_NURSERY_BITS:
12491                         case CEE_MONO_LDPTR_INT_REQ_FLAG: {
12492                                 CHECK_STACK_OVF (1);
12493
12494                                 switch (ip [1]) {
12495                                         case CEE_MONO_LDPTR_CARD_TABLE:
12496                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
12497                                                 break;
12498                                         case CEE_MONO_LDPTR_NURSERY_START:
12499                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_START, NULL);
12500                                                 break;
12501                                         case CEE_MONO_LDPTR_NURSERY_BITS:
12502                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_BITS, NULL);
12503                                                 break;
12504                                         case CEE_MONO_LDPTR_INT_REQ_FLAG:
12505                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
12506                                                 break;
12507                                 }
12508
12509                                 *sp++ = ins;
12510                                 ip += 2;
12511                                 inline_costs += 10 * num_calls++;
12512                                 break;
12513                         }
12514                         case CEE_MONO_LDPTR: {
12515                                 gpointer ptr;
12516
12517                                 CHECK_STACK_OVF (1);
12518                                 CHECK_OPSIZE (6);
12519                                 token = read32 (ip + 2);
12520
12521                                 ptr = mono_method_get_wrapper_data (method, token);
12522                                 EMIT_NEW_PCONST (cfg, ins, ptr);
12523                                 *sp++ = ins;
12524                                 ip += 6;
12525                                 inline_costs += 10 * num_calls++;
12526                                 /* Can't embed random pointers into AOT code */
12527                                 DISABLE_AOT (cfg);
12528                                 break;
12529                         }
12530                         case CEE_MONO_JIT_ICALL_ADDR: {
12531                                 MonoJitICallInfo *callinfo;
12532                                 gpointer ptr;
12533
12534                                 CHECK_STACK_OVF (1);
12535                                 CHECK_OPSIZE (6);
12536                                 token = read32 (ip + 2);
12537
12538                                 ptr = mono_method_get_wrapper_data (method, token);
12539                                 callinfo = mono_find_jit_icall_by_addr (ptr);
12540                                 g_assert (callinfo);
12541                                 EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
12542                                 *sp++ = ins;
12543                                 ip += 6;
12544                                 inline_costs += 10 * num_calls++;
12545                                 break;
12546                         }
12547                         case CEE_MONO_ICALL_ADDR: {
12548                                 MonoMethod *cmethod;
12549                                 gpointer ptr;
12550
12551                                 CHECK_STACK_OVF (1);
12552                                 CHECK_OPSIZE (6);
12553                                 token = read32 (ip + 2);
12554
12555                                 cmethod = (MonoMethod *)mono_method_get_wrapper_data (method, token);
12556
12557                                 if (cfg->compile_aot) {
12558                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
12559                                 } else {
12560                                         ptr = mono_lookup_internal_call (cmethod);
12561                                         g_assert (ptr);
12562                                         EMIT_NEW_PCONST (cfg, ins, ptr);
12563                                 }
12564                                 *sp++ = ins;
12565                                 ip += 6;
12566                                 break;
12567                         }
12568                         case CEE_MONO_VTADDR: {
12569                                 MonoInst *src_var, *src;
12570
12571                                 CHECK_STACK (1);
12572                                 --sp;
12573
12574                                 // FIXME:
12575                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12576                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
12577                                 *sp++ = src;
12578                                 ip += 2;
12579                                 break;
12580                         }
12581                         case CEE_MONO_NEWOBJ: {
12582                                 MonoInst *iargs [2];
12583
12584                                 CHECK_STACK_OVF (1);
12585                                 CHECK_OPSIZE (6);
12586                                 token = read32 (ip + 2);
12587                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12588                                 mono_class_init (klass);
12589                                 NEW_DOMAINCONST (cfg, iargs [0]);
12590                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
12591                                 NEW_CLASSCONST (cfg, iargs [1], klass);
12592                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
12593                                 *sp++ = mono_emit_jit_icall (cfg, ves_icall_object_new, iargs);
12594                                 ip += 6;
12595                                 inline_costs += 10 * num_calls++;
12596                                 break;
12597                         }
12598                         case CEE_MONO_OBJADDR:
12599                                 CHECK_STACK (1);
12600                                 --sp;
12601                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
12602                                 ins->dreg = alloc_ireg_mp (cfg);
12603                                 ins->sreg1 = sp [0]->dreg;
12604                                 ins->type = STACK_MP;
12605                                 MONO_ADD_INS (cfg->cbb, ins);
12606                                 *sp++ = ins;
12607                                 ip += 2;
12608                                 break;
12609                         case CEE_MONO_LDNATIVEOBJ:
12610                                 /*
12611                                  * Similar to LDOBJ, but instead load the unmanaged 
12612                                  * representation of the vtype to the stack.
12613                                  */
12614                                 CHECK_STACK (1);
12615                                 CHECK_OPSIZE (6);
12616                                 --sp;
12617                                 token = read32 (ip + 2);
12618                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12619                                 g_assert (klass->valuetype);
12620                                 mono_class_init (klass);
12621
12622                                 {
12623                                         MonoInst *src, *dest, *temp;
12624
12625                                         src = sp [0];
12626                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
12627                                         temp->backend.is_pinvoke = 1;
12628                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
12629                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
12630
12631                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
12632                                         dest->type = STACK_VTYPE;
12633                                         dest->klass = klass;
12634
12635                                         *sp ++ = dest;
12636                                         ip += 6;
12637                                 }
12638                                 break;
12639                         case CEE_MONO_RETOBJ: {
12640                                 /*
12641                                  * Same as RET, but return the native representation of a vtype
12642                                  * to the caller.
12643                                  */
12644                                 g_assert (cfg->ret);
12645                                 g_assert (mono_method_signature (method)->pinvoke); 
12646                                 CHECK_STACK (1);
12647                                 --sp;
12648                                 
12649                                 CHECK_OPSIZE (6);
12650                                 token = read32 (ip + 2);    
12651                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12652
12653                                 if (!cfg->vret_addr) {
12654                                         g_assert (cfg->ret_var_is_local);
12655
12656                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
12657                                 } else {
12658                                         EMIT_NEW_RETLOADA (cfg, ins);
12659                                 }
12660                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
12661                                 
12662                                 if (sp != stack_start)
12663                                         UNVERIFIED;
12664                                 
12665                                 MONO_INST_NEW (cfg, ins, OP_BR);
12666                                 ins->inst_target_bb = end_bblock;
12667                                 MONO_ADD_INS (cfg->cbb, ins);
12668                                 link_bblock (cfg, cfg->cbb, end_bblock);
12669                                 start_new_bblock = 1;
12670                                 ip += 6;
12671                                 break;
12672                         }
12673                         case CEE_MONO_CISINST:
12674                         case CEE_MONO_CCASTCLASS: {
12675                                 int token;
12676                                 CHECK_STACK (1);
12677                                 --sp;
12678                                 CHECK_OPSIZE (6);
12679                                 token = read32 (ip + 2);
12680                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12681                                 if (ip [1] == CEE_MONO_CISINST)
12682                                         ins = handle_cisinst (cfg, klass, sp [0]);
12683                                 else
12684                                         ins = handle_ccastclass (cfg, klass, sp [0]);
12685                                 *sp++ = ins;
12686                                 ip += 6;
12687                                 break;
12688                         }
12689                         case CEE_MONO_SAVE_LMF:
12690                         case CEE_MONO_RESTORE_LMF:
12691                                 ip += 2;
12692                                 break;
12693                         case CEE_MONO_CLASSCONST:
12694                                 CHECK_STACK_OVF (1);
12695                                 CHECK_OPSIZE (6);
12696                                 token = read32 (ip + 2);
12697                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
12698                                 *sp++ = ins;
12699                                 ip += 6;
12700                                 inline_costs += 10 * num_calls++;
12701                                 break;
12702                         case CEE_MONO_NOT_TAKEN:
12703                                 cfg->cbb->out_of_line = TRUE;
12704                                 ip += 2;
12705                                 break;
12706                         case CEE_MONO_TLS: {
12707                                 MonoTlsKey key;
12708
12709                                 CHECK_STACK_OVF (1);
12710                                 CHECK_OPSIZE (6);
12711                                 key = (MonoTlsKey)read32 (ip + 2);
12712                                 g_assert (key < TLS_KEY_NUM);
12713
12714                                 ins = mono_create_tls_get (cfg, key);
12715                                 if (!ins) {
12716                                         if (cfg->compile_aot) {
12717                                                 DISABLE_AOT (cfg);
12718                                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
12719                                                 ins->dreg = alloc_preg (cfg);
12720                                                 ins->type = STACK_PTR;
12721                                         } else {
12722                                                 g_assert_not_reached ();
12723                                         }
12724                                 }
12725                                 ins->type = STACK_PTR;
12726                                 MONO_ADD_INS (cfg->cbb, ins);
12727                                 *sp++ = ins;
12728                                 ip += 6;
12729                                 break;
12730                         }
12731                         case CEE_MONO_DYN_CALL: {
12732                                 MonoCallInst *call;
12733
12734                                 /* It would be easier to call a trampoline, but that would put an
12735                                  * extra frame on the stack, confusing exception handling. So
12736                                  * implement it inline using an opcode for now.
12737                                  */
12738
12739                                 if (!cfg->dyn_call_var) {
12740                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12741                                         /* prevent it from being register allocated */
12742                                         cfg->dyn_call_var->flags |= MONO_INST_VOLATILE;
12743                                 }
12744
12745                                 /* Has to use a call inst since it local regalloc expects it */
12746                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
12747                                 ins = (MonoInst*)call;
12748                                 sp -= 2;
12749                                 ins->sreg1 = sp [0]->dreg;
12750                                 ins->sreg2 = sp [1]->dreg;
12751                                 MONO_ADD_INS (cfg->cbb, ins);
12752
12753                                 cfg->param_area = MAX (cfg->param_area, cfg->backend->dyn_call_param_area);
12754
12755                                 ip += 2;
12756                                 inline_costs += 10 * num_calls++;
12757
12758                                 break;
12759                         }
12760                         case CEE_MONO_MEMORY_BARRIER: {
12761                                 CHECK_OPSIZE (6);
12762                                 emit_memory_barrier (cfg, (int)read32 (ip + 2));
12763                                 ip += 6;
12764                                 break;
12765                         }
12766                         case CEE_MONO_JIT_ATTACH: {
12767                                 MonoInst *args [16], *domain_ins;
12768                                 MonoInst *ad_ins, *jit_tls_ins;
12769                                 MonoBasicBlock *next_bb = NULL, *call_bb = NULL;
12770
12771                                 cfg->attach_cookie = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12772                                 cfg->attach_dummy = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12773
12774                                 if (mono_threads_is_coop_enabled ()) {
12775                                         /* AOT code is only used in the root domain */
12776                                         EMIT_NEW_PCONST (cfg, args [0], cfg->compile_aot ? NULL : cfg->domain);
12777                                         EMIT_NEW_VARLOADA (cfg, args [1], cfg->attach_dummy, cfg->attach_dummy->inst_vtype);
12778                                         ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
12779                                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->attach_cookie->dreg, ins->dreg);
12780                                 } else {
12781                                         EMIT_NEW_PCONST (cfg, ins, NULL);
12782                                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->attach_cookie->dreg, ins->dreg);
12783
12784                                         ad_ins = mono_get_domain_intrinsic (cfg);
12785                                         jit_tls_ins = mono_get_jit_tls_intrinsic (cfg);
12786
12787                                         if (cfg->backend->have_tls_get && ad_ins && jit_tls_ins) {
12788                                                 NEW_BBLOCK (cfg, next_bb);
12789                                                 NEW_BBLOCK (cfg, call_bb);
12790
12791                                                 if (cfg->compile_aot) {
12792                                                         /* AOT code is only used in the root domain */
12793                                                         EMIT_NEW_PCONST (cfg, domain_ins, NULL);
12794                                                 } else {
12795                                                         EMIT_NEW_PCONST (cfg, domain_ins, cfg->domain);
12796                                                 }
12797                                                 MONO_ADD_INS (cfg->cbb, ad_ins);
12798                                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, ad_ins->dreg, domain_ins->dreg);
12799                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, call_bb);
12800
12801                                                 MONO_ADD_INS (cfg->cbb, jit_tls_ins);
12802                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, jit_tls_ins->dreg, 0);
12803                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, call_bb);
12804
12805                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, next_bb);
12806                                                 MONO_START_BB (cfg, call_bb);
12807                                         }
12808
12809                                         /* AOT code is only used in the root domain */
12810                                         EMIT_NEW_PCONST (cfg, args [0], cfg->compile_aot ? NULL : cfg->domain);
12811                                         EMIT_NEW_PCONST (cfg, args [1], NULL);
12812                                         ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
12813                                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->attach_cookie->dreg, ins->dreg);
12814
12815                                         if (next_bb)
12816                                                 MONO_START_BB (cfg, next_bb);
12817                                 }
12818
12819                                 ip += 2;
12820                                 break;
12821                         }
12822                         case CEE_MONO_JIT_DETACH: {
12823                                 MonoInst *args [16];
12824
12825                                 /* Restore the original domain */
12826                                 dreg = alloc_ireg (cfg);
12827                                 EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->attach_cookie->dreg);
12828                                 EMIT_NEW_VARLOADA (cfg, args [1], cfg->attach_dummy, cfg->attach_dummy->inst_vtype);
12829                                 mono_emit_jit_icall (cfg, mono_jit_thread_detach, args);
12830                                 ip += 2;
12831                                 break;
12832                         }
12833                         case CEE_MONO_CALLI_EXTRA_ARG: {
12834                                 MonoInst *addr;
12835                                 MonoMethodSignature *fsig;
12836                                 MonoInst *arg;
12837
12838                                 /*
12839                                  * This is the same as CEE_CALLI, but passes an additional argument
12840                                  * to the called method in llvmonly mode.
12841                                  * This is only used by delegate invoke wrappers to call the
12842                                  * actual delegate method.
12843                                  */
12844                                 g_assert (method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE);
12845
12846                                 CHECK_OPSIZE (6);
12847                                 token = read32 (ip + 2);
12848
12849                                 ins = NULL;
12850
12851                                 cmethod = NULL;
12852                                 CHECK_STACK (1);
12853                                 --sp;
12854                                 addr = *sp;
12855                                 fsig = mini_get_signature (method, token, generic_context);
12856
12857                                 if (cfg->llvm_only)
12858                                         cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, fsig);
12859
12860                                 n = fsig->param_count + fsig->hasthis + 1;
12861
12862                                 CHECK_STACK (n);
12863
12864                                 sp -= n;
12865                                 arg = sp [n - 1];
12866
12867                                 if (cfg->llvm_only) {
12868                                         /*
12869                                          * The lowest bit of 'arg' determines whenever the callee uses the gsharedvt
12870                                          * cconv. This is set by mono_init_delegate ().
12871                                          */
12872                                         if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig)) {
12873                                                 MonoInst *callee = addr;
12874                                                 MonoInst *call, *localloc_ins;
12875                                                 MonoBasicBlock *is_gsharedvt_bb, *end_bb;
12876                                                 int low_bit_reg = alloc_preg (cfg);
12877
12878                                                 NEW_BBLOCK (cfg, is_gsharedvt_bb);
12879                                                 NEW_BBLOCK (cfg, end_bb);
12880
12881                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, low_bit_reg, arg->dreg, 1);
12882                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_bit_reg, 0);
12883                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_gsharedvt_bb);
12884
12885                                                 /* Normal case: callee uses a normal cconv, have to add an out wrapper */
12886                                                 addr = emit_get_rgctx_sig (cfg, context_used,
12887                                                                                                    fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
12888                                                 /*
12889                                                  * ADDR points to a gsharedvt-out wrapper, have to pass <callee, arg> as an extra arg.
12890                                                  */
12891                                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
12892                                                 ins->dreg = alloc_preg (cfg);
12893                                                 ins->inst_imm = 2 * SIZEOF_VOID_P;
12894                                                 MONO_ADD_INS (cfg->cbb, ins);
12895                                                 localloc_ins = ins;
12896                                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12897                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, 0, callee->dreg);
12898                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, SIZEOF_VOID_P, arg->dreg);
12899
12900                                                 call = emit_extra_arg_calli (cfg, fsig, sp, localloc_ins->dreg, addr);
12901                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12902
12903                                                 /* Gsharedvt case: callee uses a gsharedvt cconv, no conversion is needed */
12904                                                 MONO_START_BB (cfg, is_gsharedvt_bb);
12905                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PXOR_IMM, arg->dreg, arg->dreg, 1);
12906                                                 ins = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
12907                                                 ins->dreg = call->dreg;
12908
12909                                                 MONO_START_BB (cfg, end_bb);
12910                                         } else {
12911                                                 /* Caller uses a normal calling conv */
12912
12913                                                 MonoInst *callee = addr;
12914                                                 MonoInst *call, *localloc_ins;
12915                                                 MonoBasicBlock *is_gsharedvt_bb, *end_bb;
12916                                                 int low_bit_reg = alloc_preg (cfg);
12917
12918                                                 NEW_BBLOCK (cfg, is_gsharedvt_bb);
12919                                                 NEW_BBLOCK (cfg, end_bb);
12920
12921                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, low_bit_reg, arg->dreg, 1);
12922                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_bit_reg, 0);
12923                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_gsharedvt_bb);
12924
12925                                                 /* Normal case: callee uses a normal cconv, no conversion is needed */
12926                                                 call = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
12927                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12928                                                 /* Gsharedvt case: callee uses a gsharedvt cconv, have to add an in wrapper */
12929                                                 MONO_START_BB (cfg, is_gsharedvt_bb);
12930                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PXOR_IMM, arg->dreg, arg->dreg, 1);
12931                                                 NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER, fsig);
12932                                                 MONO_ADD_INS (cfg->cbb, addr);
12933                                                 /*
12934                                                  * ADDR points to a gsharedvt-in wrapper, have to pass <callee, arg> as an extra arg.
12935                                                  */
12936                                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
12937                                                 ins->dreg = alloc_preg (cfg);
12938                                                 ins->inst_imm = 2 * SIZEOF_VOID_P;
12939                                                 MONO_ADD_INS (cfg->cbb, ins);
12940                                                 localloc_ins = ins;
12941                                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12942                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, 0, callee->dreg);
12943                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, SIZEOF_VOID_P, arg->dreg);
12944
12945                                                 ins = emit_extra_arg_calli (cfg, fsig, sp, localloc_ins->dreg, addr);
12946                                                 ins->dreg = call->dreg;
12947                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12948
12949                                                 MONO_START_BB (cfg, end_bb);
12950                                         }
12951                                 } else {
12952                                         /* Same as CEE_CALLI */
12953                                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
12954                                                 /*
12955                                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
12956                                                  */
12957                                                 MonoInst *callee = addr;
12958
12959                                                 addr = emit_get_rgctx_sig (cfg, context_used,
12960                                                                                                    fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
12961                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
12962                                         } else {
12963                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
12964                                         }
12965                                 }
12966
12967                                 if (!MONO_TYPE_IS_VOID (fsig->ret))
12968                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
12969
12970                                 CHECK_CFG_EXCEPTION;
12971
12972                                 ip += 6;
12973                                 ins_flag = 0;
12974                                 constrained_class = NULL;
12975                                 break;
12976                         }
12977                         default:
12978                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
12979                                 break;
12980                         }
12981                         break;
12982                 }
12983
12984                 case CEE_PREFIX1: {
12985                         CHECK_OPSIZE (2);
12986                         switch (ip [1]) {
12987                         case CEE_ARGLIST: {
12988                                 /* somewhat similar to LDTOKEN */
12989                                 MonoInst *addr, *vtvar;
12990                                 CHECK_STACK_OVF (1);
12991                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
12992
12993                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12994                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
12995
12996                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12997                                 ins->type = STACK_VTYPE;
12998                                 ins->klass = mono_defaults.argumenthandle_class;
12999                                 *sp++ = ins;
13000                                 ip += 2;
13001                                 break;
13002                         }
13003                         case CEE_CEQ:
13004                         case CEE_CGT:
13005                         case CEE_CGT_UN:
13006                         case CEE_CLT:
13007                         case CEE_CLT_UN: {
13008                                 MonoInst *cmp, *arg1, *arg2;
13009
13010                                 CHECK_STACK (2);
13011                                 sp -= 2;
13012                                 arg1 = sp [0];
13013                                 arg2 = sp [1];
13014
13015                                 /*
13016                                  * The following transforms:
13017                                  *    CEE_CEQ    into OP_CEQ
13018                                  *    CEE_CGT    into OP_CGT
13019                                  *    CEE_CGT_UN into OP_CGT_UN
13020                                  *    CEE_CLT    into OP_CLT
13021                                  *    CEE_CLT_UN into OP_CLT_UN
13022                                  */
13023                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
13024
13025                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
13026                                 cmp->sreg1 = arg1->dreg;
13027                                 cmp->sreg2 = arg2->dreg;
13028                                 type_from_op (cfg, cmp, arg1, arg2);
13029                                 CHECK_TYPE (cmp);
13030                                 add_widen_op (cfg, cmp, &arg1, &arg2);
13031                                 if ((arg1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((arg1->type == STACK_PTR) || (arg1->type == STACK_OBJ) || (arg1->type == STACK_MP))))
13032                                         cmp->opcode = OP_LCOMPARE;
13033                                 else if (arg1->type == STACK_R4)
13034                                         cmp->opcode = OP_RCOMPARE;
13035                                 else if (arg1->type == STACK_R8)
13036                                         cmp->opcode = OP_FCOMPARE;
13037                                 else
13038                                         cmp->opcode = OP_ICOMPARE;
13039                                 MONO_ADD_INS (cfg->cbb, cmp);
13040                                 ins->type = STACK_I4;
13041                                 ins->dreg = alloc_dreg (cfg, (MonoStackType)ins->type);
13042                                 type_from_op (cfg, ins, arg1, arg2);
13043
13044                                 if (cmp->opcode == OP_FCOMPARE || cmp->opcode == OP_RCOMPARE) {
13045                                         /*
13046                                          * The backends expect the fceq opcodes to do the
13047                                          * comparison too.
13048                                          */
13049                                         ins->sreg1 = cmp->sreg1;
13050                                         ins->sreg2 = cmp->sreg2;
13051                                         NULLIFY_INS (cmp);
13052                                 }
13053                                 MONO_ADD_INS (cfg->cbb, ins);
13054                                 *sp++ = ins;
13055                                 ip += 2;
13056                                 break;
13057                         }
13058                         case CEE_LDFTN: {
13059                                 MonoInst *argconst;
13060                                 MonoMethod *cil_method;
13061
13062                                 CHECK_STACK_OVF (1);
13063                                 CHECK_OPSIZE (6);
13064                                 n = read32 (ip + 2);
13065                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
13066                                 CHECK_CFG_ERROR;
13067
13068                                 mono_class_init (cmethod->klass);
13069
13070                                 mono_save_token_info (cfg, image, n, cmethod);
13071
13072                                 context_used = mini_method_check_context_used (cfg, cmethod);
13073
13074                                 cil_method = cmethod;
13075                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
13076                                         METHOD_ACCESS_FAILURE (method, cil_method);
13077
13078                                 if (mono_security_core_clr_enabled ())
13079                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
13080
13081                                 /* 
13082                                  * Optimize the common case of ldftn+delegate creation
13083                                  */
13084                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
13085                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
13086                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
13087                                                 MonoInst *target_ins, *handle_ins;
13088                                                 MonoMethod *invoke;
13089                                                 int invoke_context_used;
13090
13091                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
13092                                                 if (!invoke || !mono_method_signature (invoke))
13093                                                         LOAD_ERROR;
13094
13095                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
13096
13097                                                 target_ins = sp [-1];
13098
13099                                                 if (mono_security_core_clr_enabled ())
13100                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
13101
13102                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
13103                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
13104                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
13105                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
13106                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
13107                                                         }
13108                                                 }
13109
13110                                                 /* FIXME: SGEN support */
13111                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
13112                                                         ip += 6;
13113                                                         if (cfg->verbose_level > 3)
13114                                                                 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));
13115                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, FALSE))) {
13116                                                                 sp --;
13117                                                                 *sp = handle_ins;
13118                                                                 CHECK_CFG_EXCEPTION;
13119                                                                 ip += 5;
13120                                                                 sp ++;
13121                                                                 break;
13122                                                         }
13123                                                         ip -= 6;
13124                                                 }
13125                                         }
13126                                 }
13127
13128                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
13129                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
13130                                 *sp++ = ins;
13131                                 
13132                                 ip += 6;
13133                                 inline_costs += 10 * num_calls++;
13134                                 break;
13135                         }
13136                         case CEE_LDVIRTFTN: {
13137                                 MonoInst *args [2];
13138
13139                                 CHECK_STACK (1);
13140                                 CHECK_OPSIZE (6);
13141                                 n = read32 (ip + 2);
13142                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
13143                                 CHECK_CFG_ERROR;
13144
13145                                 mono_class_init (cmethod->klass);
13146  
13147                                 context_used = mini_method_check_context_used (cfg, cmethod);
13148
13149                                 if (mono_security_core_clr_enabled ())
13150                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
13151
13152                                 /*
13153                                  * Optimize the common case of ldvirtftn+delegate creation
13154                                  */
13155                                 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)) {
13156                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
13157                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
13158                                                 MonoInst *target_ins, *handle_ins;
13159                                                 MonoMethod *invoke;
13160                                                 int invoke_context_used;
13161                                                 gboolean is_virtual = cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL;
13162
13163                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
13164                                                 if (!invoke || !mono_method_signature (invoke))
13165                                                         LOAD_ERROR;
13166
13167                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
13168
13169                                                 target_ins = sp [-1];
13170
13171                                                 if (mono_security_core_clr_enabled ())
13172                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
13173
13174                                                 /* FIXME: SGEN support */
13175                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
13176                                                         ip += 6;
13177                                                         if (cfg->verbose_level > 3)
13178                                                                 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));
13179                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, is_virtual))) {
13180                                                                 sp -= 2;
13181                                                                 *sp = handle_ins;
13182                                                                 CHECK_CFG_EXCEPTION;
13183                                                                 ip += 5;
13184                                                                 sp ++;
13185                                                                 break;
13186                                                         }
13187                                                         ip -= 6;
13188                                                 }
13189                                         }
13190                                 }
13191
13192                                 --sp;
13193                                 args [0] = *sp;
13194
13195                                 args [1] = emit_get_rgctx_method (cfg, context_used,
13196                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
13197
13198                                 if (context_used)
13199                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
13200                                 else
13201                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
13202
13203                                 ip += 6;
13204                                 inline_costs += 10 * num_calls++;
13205                                 break;
13206                         }
13207                         case CEE_LDARG:
13208                                 CHECK_STACK_OVF (1);
13209                                 CHECK_OPSIZE (4);
13210                                 n = read16 (ip + 2);
13211                                 CHECK_ARG (n);
13212                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
13213                                 *sp++ = ins;
13214                                 ip += 4;
13215                                 break;
13216                         case CEE_LDARGA:
13217                                 CHECK_STACK_OVF (1);
13218                                 CHECK_OPSIZE (4);
13219                                 n = read16 (ip + 2);
13220                                 CHECK_ARG (n);
13221                                 NEW_ARGLOADA (cfg, ins, n);
13222                                 MONO_ADD_INS (cfg->cbb, ins);
13223                                 *sp++ = ins;
13224                                 ip += 4;
13225                                 break;
13226                         case CEE_STARG:
13227                                 CHECK_STACK (1);
13228                                 --sp;
13229                                 CHECK_OPSIZE (4);
13230                                 n = read16 (ip + 2);
13231                                 CHECK_ARG (n);
13232                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
13233                                         UNVERIFIED;
13234                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
13235                                 ip += 4;
13236                                 break;
13237                         case CEE_LDLOC:
13238                                 CHECK_STACK_OVF (1);
13239                                 CHECK_OPSIZE (4);
13240                                 n = read16 (ip + 2);
13241                                 CHECK_LOCAL (n);
13242                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
13243                                 *sp++ = ins;
13244                                 ip += 4;
13245                                 break;
13246                         case CEE_LDLOCA: {
13247                                 unsigned char *tmp_ip;
13248                                 CHECK_STACK_OVF (1);
13249                                 CHECK_OPSIZE (4);
13250                                 n = read16 (ip + 2);
13251                                 CHECK_LOCAL (n);
13252
13253                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
13254                                         ip = tmp_ip;
13255                                         inline_costs += 1;
13256                                         break;
13257                                 }                       
13258                                 
13259                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
13260                                 *sp++ = ins;
13261                                 ip += 4;
13262                                 break;
13263                         }
13264                         case CEE_STLOC:
13265                                 CHECK_STACK (1);
13266                                 --sp;
13267                                 CHECK_OPSIZE (4);
13268                                 n = read16 (ip + 2);
13269                                 CHECK_LOCAL (n);
13270                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
13271                                         UNVERIFIED;
13272                                 emit_stloc_ir (cfg, sp, header, n);
13273                                 ip += 4;
13274                                 inline_costs += 1;
13275                                 break;
13276                         case CEE_LOCALLOC:
13277                                 CHECK_STACK (1);
13278                                 --sp;
13279                                 if (sp != stack_start) 
13280                                         UNVERIFIED;
13281                                 if (cfg->method != method) 
13282                                         /* 
13283                                          * Inlining this into a loop in a parent could lead to 
13284                                          * stack overflows which is different behavior than the
13285                                          * non-inlined case, thus disable inlining in this case.
13286                                          */
13287                                         INLINE_FAILURE("localloc");
13288
13289                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
13290                                 ins->dreg = alloc_preg (cfg);
13291                                 ins->sreg1 = sp [0]->dreg;
13292                                 ins->type = STACK_PTR;
13293                                 MONO_ADD_INS (cfg->cbb, ins);
13294
13295                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
13296                                 if (init_locals)
13297                                         ins->flags |= MONO_INST_INIT;
13298
13299                                 *sp++ = ins;
13300                                 ip += 2;
13301                                 break;
13302                         case CEE_ENDFILTER: {
13303                                 MonoExceptionClause *clause, *nearest;
13304                                 int cc;
13305
13306                                 CHECK_STACK (1);
13307                                 --sp;
13308                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
13309                                         UNVERIFIED;
13310                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
13311                                 ins->sreg1 = (*sp)->dreg;
13312                                 MONO_ADD_INS (cfg->cbb, ins);
13313                                 start_new_bblock = 1;
13314                                 ip += 2;
13315
13316                                 nearest = NULL;
13317                                 for (cc = 0; cc < header->num_clauses; ++cc) {
13318                                         clause = &header->clauses [cc];
13319                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
13320                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
13321                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset)))
13322                                                 nearest = clause;
13323                                 }
13324                                 g_assert (nearest);
13325                                 if ((ip - header->code) != nearest->handler_offset)
13326                                         UNVERIFIED;
13327
13328                                 break;
13329                         }
13330                         case CEE_UNALIGNED_:
13331                                 ins_flag |= MONO_INST_UNALIGNED;
13332                                 /* FIXME: record alignment? we can assume 1 for now */
13333                                 CHECK_OPSIZE (3);
13334                                 ip += 3;
13335                                 break;
13336                         case CEE_VOLATILE_:
13337                                 ins_flag |= MONO_INST_VOLATILE;
13338                                 ip += 2;
13339                                 break;
13340                         case CEE_TAIL_:
13341                                 ins_flag   |= MONO_INST_TAILCALL;
13342                                 cfg->flags |= MONO_CFG_HAS_TAIL;
13343                                 /* Can't inline tail calls at this time */
13344                                 inline_costs += 100000;
13345                                 ip += 2;
13346                                 break;
13347                         case CEE_INITOBJ:
13348                                 CHECK_STACK (1);
13349                                 --sp;
13350                                 CHECK_OPSIZE (6);
13351                                 token = read32 (ip + 2);
13352                                 klass = mini_get_class (method, token, generic_context);
13353                                 CHECK_TYPELOAD (klass);
13354                                 if (generic_class_is_reference_type (cfg, klass))
13355                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
13356                                 else
13357                                         mini_emit_initobj (cfg, *sp, NULL, klass);
13358                                 ip += 6;
13359                                 inline_costs += 1;
13360                                 break;
13361                         case CEE_CONSTRAINED_:
13362                                 CHECK_OPSIZE (6);
13363                                 token = read32 (ip + 2);
13364                                 constrained_class = mini_get_class (method, token, generic_context);
13365                                 CHECK_TYPELOAD (constrained_class);
13366                                 ip += 6;
13367                                 break;
13368                         case CEE_CPBLK:
13369                         case CEE_INITBLK: {
13370                                 MonoInst *iargs [3];
13371                                 CHECK_STACK (3);
13372                                 sp -= 3;
13373
13374                                 /* Skip optimized paths for volatile operations. */
13375                                 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)) {
13376                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
13377                                 } 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)) {
13378                                         /* emit_memset only works when val == 0 */
13379                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
13380                                 } else {
13381                                         MonoInst *call;
13382                                         iargs [0] = sp [0];
13383                                         iargs [1] = sp [1];
13384                                         iargs [2] = sp [2];
13385                                         if (ip [1] == CEE_CPBLK) {
13386                                                 /*
13387                                                  * FIXME: It's unclear whether we should be emitting both the acquire
13388                                                  * and release barriers for cpblk. It is technically both a load and
13389                                                  * store operation, so it seems like that's the sensible thing to do.
13390                                                  *
13391                                                  * FIXME: We emit full barriers on both sides of the operation for
13392                                                  * simplicity. We should have a separate atomic memcpy method instead.
13393                                                  */
13394                                                 MonoMethod *memcpy_method = get_memcpy_method ();
13395
13396                                                 if (ins_flag & MONO_INST_VOLATILE)
13397                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
13398
13399                                                 call = mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
13400                                                 call->flags |= ins_flag;
13401
13402                                                 if (ins_flag & MONO_INST_VOLATILE)
13403                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
13404                                         } else {
13405                                                 MonoMethod *memset_method = get_memset_method ();
13406                                                 if (ins_flag & MONO_INST_VOLATILE) {
13407                                                         /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
13408                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
13409                                                 }
13410                                                 call = mono_emit_method_call (cfg, memset_method, iargs, NULL);
13411                                                 call->flags |= ins_flag;
13412                                         }
13413                                 }
13414                                 ip += 2;
13415                                 ins_flag = 0;
13416                                 inline_costs += 1;
13417                                 break;
13418                         }
13419                         case CEE_NO_:
13420                                 CHECK_OPSIZE (3);
13421                                 if (ip [2] & 0x1)
13422                                         ins_flag |= MONO_INST_NOTYPECHECK;
13423                                 if (ip [2] & 0x2)
13424                                         ins_flag |= MONO_INST_NORANGECHECK;
13425                                 /* we ignore the no-nullcheck for now since we
13426                                  * really do it explicitly only when doing callvirt->call
13427                                  */
13428                                 ip += 3;
13429                                 break;
13430                         case CEE_RETHROW: {
13431                                 MonoInst *load;
13432                                 int handler_offset = -1;
13433
13434                                 for (i = 0; i < header->num_clauses; ++i) {
13435                                         MonoExceptionClause *clause = &header->clauses [i];
13436                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
13437                                                 handler_offset = clause->handler_offset;
13438                                                 break;
13439                                         }
13440                                 }
13441
13442                                 cfg->cbb->flags |= BB_EXCEPTION_UNSAFE;
13443
13444                                 if (handler_offset == -1)
13445                                         UNVERIFIED;
13446
13447                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
13448                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
13449                                 ins->sreg1 = load->dreg;
13450                                 MONO_ADD_INS (cfg->cbb, ins);
13451
13452                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
13453                                 MONO_ADD_INS (cfg->cbb, ins);
13454
13455                                 sp = stack_start;
13456                                 link_bblock (cfg, cfg->cbb, end_bblock);
13457                                 start_new_bblock = 1;
13458                                 ip += 2;
13459                                 break;
13460                         }
13461                         case CEE_SIZEOF: {
13462                                 guint32 val;
13463                                 int ialign;
13464
13465                                 CHECK_STACK_OVF (1);
13466                                 CHECK_OPSIZE (6);
13467                                 token = read32 (ip + 2);
13468                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !image_is_dynamic (method->klass->image) && !generic_context) {
13469                                         MonoType *type = mono_type_create_from_typespec_checked (image, token, &cfg->error);
13470                                         CHECK_CFG_ERROR;
13471
13472                                         val = mono_type_size (type, &ialign);
13473                                 } else {
13474                                         MonoClass *klass = mini_get_class (method, token, generic_context);
13475                                         CHECK_TYPELOAD (klass);
13476
13477                                         val = mono_type_size (&klass->byval_arg, &ialign);
13478
13479                                         if (mini_is_gsharedvt_klass (klass))
13480                                                 GSHAREDVT_FAILURE (*ip);
13481                                 }
13482                                 EMIT_NEW_ICONST (cfg, ins, val);
13483                                 *sp++= ins;
13484                                 ip += 6;
13485                                 break;
13486                         }
13487                         case CEE_REFANYTYPE: {
13488                                 MonoInst *src_var, *src;
13489
13490                                 GSHAREDVT_FAILURE (*ip);
13491
13492                                 CHECK_STACK (1);
13493                                 --sp;
13494
13495                                 // FIXME:
13496                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
13497                                 if (!src_var)
13498                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
13499                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
13500                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type));
13501                                 *sp++ = ins;
13502                                 ip += 2;
13503                                 break;
13504                         }
13505                         case CEE_READONLY_:
13506                                 readonly = TRUE;
13507                                 ip += 2;
13508                                 break;
13509
13510                         case CEE_UNUSED56:
13511                         case CEE_UNUSED57:
13512                         case CEE_UNUSED70:
13513                         case CEE_UNUSED:
13514                         case CEE_UNUSED99:
13515                                 UNVERIFIED;
13516                                 
13517                         default:
13518                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
13519                                 UNVERIFIED;
13520                         }
13521                         break;
13522                 }
13523                 case CEE_UNUSED58:
13524                 case CEE_UNUSED1:
13525                         UNVERIFIED;
13526
13527                 default:
13528                         g_warning ("opcode 0x%02x not handled", *ip);
13529                         UNVERIFIED;
13530                 }
13531         }
13532         if (start_new_bblock != 1)
13533                 UNVERIFIED;
13534
13535         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
13536         if (cfg->cbb->next_bb) {
13537                 /* This could already be set because of inlining, #693905 */
13538                 MonoBasicBlock *bb = cfg->cbb;
13539
13540                 while (bb->next_bb)
13541                         bb = bb->next_bb;
13542                 bb->next_bb = end_bblock;
13543         } else {
13544                 cfg->cbb->next_bb = end_bblock;
13545         }
13546
13547         if (cfg->method == method && cfg->domainvar) {
13548                 MonoInst *store;
13549                 MonoInst *get_domain;
13550
13551                 cfg->cbb = init_localsbb;
13552
13553                 if ((get_domain = mono_get_domain_intrinsic (cfg))) {
13554                         MONO_ADD_INS (cfg->cbb, get_domain);
13555                 } else {
13556                         get_domain = mono_emit_jit_icall (cfg, mono_domain_get, NULL);
13557                 }
13558                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
13559                 MONO_ADD_INS (cfg->cbb, store);
13560         }
13561
13562 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
13563         if (cfg->compile_aot)
13564                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
13565                 mono_get_got_var (cfg);
13566 #endif
13567
13568         if (cfg->method == method && cfg->got_var)
13569                 mono_emit_load_got_addr (cfg);
13570
13571         if (init_localsbb) {
13572                 cfg->cbb = init_localsbb;
13573                 cfg->ip = NULL;
13574                 for (i = 0; i < header->num_locals; ++i) {
13575                         emit_init_local (cfg, i, header->locals [i], init_locals);
13576                 }
13577         }
13578
13579         if (cfg->init_ref_vars && cfg->method == method) {
13580                 /* Emit initialization for ref vars */
13581                 // FIXME: Avoid duplication initialization for IL locals.
13582                 for (i = 0; i < cfg->num_varinfo; ++i) {
13583                         MonoInst *ins = cfg->varinfo [i];
13584
13585                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
13586                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
13587                 }
13588         }
13589
13590         if (cfg->lmf_var && cfg->method == method && !cfg->llvm_only) {
13591                 cfg->cbb = init_localsbb;
13592                 emit_push_lmf (cfg);
13593         }
13594
13595         cfg->cbb = init_localsbb;
13596         emit_instrumentation_call (cfg, mono_profiler_method_enter);
13597
13598         if (seq_points) {
13599                 MonoBasicBlock *bb;
13600
13601                 /*
13602                  * Make seq points at backward branch targets interruptable.
13603                  */
13604                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
13605                         if (bb->code && bb->in_count > 1 && bb->code->opcode == OP_SEQ_POINT)
13606                                 bb->code->flags |= MONO_INST_SINGLE_STEP_LOC;
13607         }
13608
13609         /* Add a sequence point for method entry/exit events */
13610         if (seq_points && cfg->gen_sdb_seq_points) {
13611                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
13612                 MONO_ADD_INS (init_localsbb, ins);
13613                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
13614                 MONO_ADD_INS (cfg->bb_exit, ins);
13615         }
13616
13617         /*
13618          * Add seq points for IL offsets which have line number info, but wasn't generated a seq point during JITting because
13619          * the code they refer to was dead (#11880).
13620          */
13621         if (sym_seq_points) {
13622                 for (i = 0; i < header->code_size; ++i) {
13623                         if (mono_bitset_test_fast (seq_point_locs, i) && !mono_bitset_test_fast (seq_point_set_locs, i)) {
13624                                 MonoInst *ins;
13625
13626                                 NEW_SEQ_POINT (cfg, ins, i, FALSE);
13627                                 mono_add_seq_point (cfg, NULL, ins, SEQ_POINT_NATIVE_OFFSET_DEAD_CODE);
13628                         }
13629                 }
13630         }
13631
13632         cfg->ip = NULL;
13633
13634         if (cfg->method == method) {
13635                 MonoBasicBlock *bb;
13636                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13637                         bb->region = mono_find_block_region (cfg, bb->real_offset);
13638                         if (cfg->spvars)
13639                                 mono_create_spvar_for_region (cfg, bb->region);
13640                         if (cfg->verbose_level > 2)
13641                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
13642                 }
13643         }
13644
13645         if (inline_costs < 0) {
13646                 char *mname;
13647
13648                 /* Method is too large */
13649                 mname = mono_method_full_name (method, TRUE);
13650                 mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Method %s is too complex.", mname));
13651                 g_free (mname);
13652         }
13653
13654         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
13655                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
13656
13657         goto cleanup;
13658
13659 mono_error_exit:
13660         g_assert (!mono_error_ok (&cfg->error));
13661         goto cleanup;
13662  
13663  exception_exit:
13664         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
13665         goto cleanup;
13666
13667  unverified:
13668         set_exception_type_from_invalid_il (cfg, method, ip);
13669         goto cleanup;
13670
13671  cleanup:
13672         g_slist_free (class_inits);
13673         mono_basic_block_free (original_bb);
13674         cfg->dont_inline = g_list_remove (cfg->dont_inline, method);
13675         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
13676         if (cfg->exception_type)
13677                 return -1;
13678         else
13679                 return inline_costs;
13680 }
13681
13682 static int
13683 store_membase_reg_to_store_membase_imm (int opcode)
13684 {
13685         switch (opcode) {
13686         case OP_STORE_MEMBASE_REG:
13687                 return OP_STORE_MEMBASE_IMM;
13688         case OP_STOREI1_MEMBASE_REG:
13689                 return OP_STOREI1_MEMBASE_IMM;
13690         case OP_STOREI2_MEMBASE_REG:
13691                 return OP_STOREI2_MEMBASE_IMM;
13692         case OP_STOREI4_MEMBASE_REG:
13693                 return OP_STOREI4_MEMBASE_IMM;
13694         case OP_STOREI8_MEMBASE_REG:
13695                 return OP_STOREI8_MEMBASE_IMM;
13696         default:
13697                 g_assert_not_reached ();
13698         }
13699
13700         return -1;
13701 }               
13702
13703 int
13704 mono_op_to_op_imm (int opcode)
13705 {
13706         switch (opcode) {
13707         case OP_IADD:
13708                 return OP_IADD_IMM;
13709         case OP_ISUB:
13710                 return OP_ISUB_IMM;
13711         case OP_IDIV:
13712                 return OP_IDIV_IMM;
13713         case OP_IDIV_UN:
13714                 return OP_IDIV_UN_IMM;
13715         case OP_IREM:
13716                 return OP_IREM_IMM;
13717         case OP_IREM_UN:
13718                 return OP_IREM_UN_IMM;
13719         case OP_IMUL:
13720                 return OP_IMUL_IMM;
13721         case OP_IAND:
13722                 return OP_IAND_IMM;
13723         case OP_IOR:
13724                 return OP_IOR_IMM;
13725         case OP_IXOR:
13726                 return OP_IXOR_IMM;
13727         case OP_ISHL:
13728                 return OP_ISHL_IMM;
13729         case OP_ISHR:
13730                 return OP_ISHR_IMM;
13731         case OP_ISHR_UN:
13732                 return OP_ISHR_UN_IMM;
13733
13734         case OP_LADD:
13735                 return OP_LADD_IMM;
13736         case OP_LSUB:
13737                 return OP_LSUB_IMM;
13738         case OP_LAND:
13739                 return OP_LAND_IMM;
13740         case OP_LOR:
13741                 return OP_LOR_IMM;
13742         case OP_LXOR:
13743                 return OP_LXOR_IMM;
13744         case OP_LSHL:
13745                 return OP_LSHL_IMM;
13746         case OP_LSHR:
13747                 return OP_LSHR_IMM;
13748         case OP_LSHR_UN:
13749                 return OP_LSHR_UN_IMM;
13750 #if SIZEOF_REGISTER == 8
13751         case OP_LREM:
13752                 return OP_LREM_IMM;
13753 #endif
13754
13755         case OP_COMPARE:
13756                 return OP_COMPARE_IMM;
13757         case OP_ICOMPARE:
13758                 return OP_ICOMPARE_IMM;
13759         case OP_LCOMPARE:
13760                 return OP_LCOMPARE_IMM;
13761
13762         case OP_STORE_MEMBASE_REG:
13763                 return OP_STORE_MEMBASE_IMM;
13764         case OP_STOREI1_MEMBASE_REG:
13765                 return OP_STOREI1_MEMBASE_IMM;
13766         case OP_STOREI2_MEMBASE_REG:
13767                 return OP_STOREI2_MEMBASE_IMM;
13768         case OP_STOREI4_MEMBASE_REG:
13769                 return OP_STOREI4_MEMBASE_IMM;
13770
13771 #if defined(TARGET_X86) || defined (TARGET_AMD64)
13772         case OP_X86_PUSH:
13773                 return OP_X86_PUSH_IMM;
13774         case OP_X86_COMPARE_MEMBASE_REG:
13775                 return OP_X86_COMPARE_MEMBASE_IMM;
13776 #endif
13777 #if defined(TARGET_AMD64)
13778         case OP_AMD64_ICOMPARE_MEMBASE_REG:
13779                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13780 #endif
13781         case OP_VOIDCALL_REG:
13782                 return OP_VOIDCALL;
13783         case OP_CALL_REG:
13784                 return OP_CALL;
13785         case OP_LCALL_REG:
13786                 return OP_LCALL;
13787         case OP_FCALL_REG:
13788                 return OP_FCALL;
13789         case OP_LOCALLOC:
13790                 return OP_LOCALLOC_IMM;
13791         }
13792
13793         return -1;
13794 }
13795
13796 static int
13797 ldind_to_load_membase (int opcode)
13798 {
13799         switch (opcode) {
13800         case CEE_LDIND_I1:
13801                 return OP_LOADI1_MEMBASE;
13802         case CEE_LDIND_U1:
13803                 return OP_LOADU1_MEMBASE;
13804         case CEE_LDIND_I2:
13805                 return OP_LOADI2_MEMBASE;
13806         case CEE_LDIND_U2:
13807                 return OP_LOADU2_MEMBASE;
13808         case CEE_LDIND_I4:
13809                 return OP_LOADI4_MEMBASE;
13810         case CEE_LDIND_U4:
13811                 return OP_LOADU4_MEMBASE;
13812         case CEE_LDIND_I:
13813                 return OP_LOAD_MEMBASE;
13814         case CEE_LDIND_REF:
13815                 return OP_LOAD_MEMBASE;
13816         case CEE_LDIND_I8:
13817                 return OP_LOADI8_MEMBASE;
13818         case CEE_LDIND_R4:
13819                 return OP_LOADR4_MEMBASE;
13820         case CEE_LDIND_R8:
13821                 return OP_LOADR8_MEMBASE;
13822         default:
13823                 g_assert_not_reached ();
13824         }
13825
13826         return -1;
13827 }
13828
13829 static int
13830 stind_to_store_membase (int opcode)
13831 {
13832         switch (opcode) {
13833         case CEE_STIND_I1:
13834                 return OP_STOREI1_MEMBASE_REG;
13835         case CEE_STIND_I2:
13836                 return OP_STOREI2_MEMBASE_REG;
13837         case CEE_STIND_I4:
13838                 return OP_STOREI4_MEMBASE_REG;
13839         case CEE_STIND_I:
13840         case CEE_STIND_REF:
13841                 return OP_STORE_MEMBASE_REG;
13842         case CEE_STIND_I8:
13843                 return OP_STOREI8_MEMBASE_REG;
13844         case CEE_STIND_R4:
13845                 return OP_STORER4_MEMBASE_REG;
13846         case CEE_STIND_R8:
13847                 return OP_STORER8_MEMBASE_REG;
13848         default:
13849                 g_assert_not_reached ();
13850         }
13851
13852         return -1;
13853 }
13854
13855 int
13856 mono_load_membase_to_load_mem (int opcode)
13857 {
13858         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
13859 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13860         switch (opcode) {
13861         case OP_LOAD_MEMBASE:
13862                 return OP_LOAD_MEM;
13863         case OP_LOADU1_MEMBASE:
13864                 return OP_LOADU1_MEM;
13865         case OP_LOADU2_MEMBASE:
13866                 return OP_LOADU2_MEM;
13867         case OP_LOADI4_MEMBASE:
13868                 return OP_LOADI4_MEM;
13869         case OP_LOADU4_MEMBASE:
13870                 return OP_LOADU4_MEM;
13871 #if SIZEOF_REGISTER == 8
13872         case OP_LOADI8_MEMBASE:
13873                 return OP_LOADI8_MEM;
13874 #endif
13875         }
13876 #endif
13877
13878         return -1;
13879 }
13880
13881 static inline int
13882 op_to_op_dest_membase (int store_opcode, int opcode)
13883 {
13884 #if defined(TARGET_X86)
13885         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
13886                 return -1;
13887
13888         switch (opcode) {
13889         case OP_IADD:
13890                 return OP_X86_ADD_MEMBASE_REG;
13891         case OP_ISUB:
13892                 return OP_X86_SUB_MEMBASE_REG;
13893         case OP_IAND:
13894                 return OP_X86_AND_MEMBASE_REG;
13895         case OP_IOR:
13896                 return OP_X86_OR_MEMBASE_REG;
13897         case OP_IXOR:
13898                 return OP_X86_XOR_MEMBASE_REG;
13899         case OP_ADD_IMM:
13900         case OP_IADD_IMM:
13901                 return OP_X86_ADD_MEMBASE_IMM;
13902         case OP_SUB_IMM:
13903         case OP_ISUB_IMM:
13904                 return OP_X86_SUB_MEMBASE_IMM;
13905         case OP_AND_IMM:
13906         case OP_IAND_IMM:
13907                 return OP_X86_AND_MEMBASE_IMM;
13908         case OP_OR_IMM:
13909         case OP_IOR_IMM:
13910                 return OP_X86_OR_MEMBASE_IMM;
13911         case OP_XOR_IMM:
13912         case OP_IXOR_IMM:
13913                 return OP_X86_XOR_MEMBASE_IMM;
13914         case OP_MOVE:
13915                 return OP_NOP;
13916         }
13917 #endif
13918
13919 #if defined(TARGET_AMD64)
13920         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
13921                 return -1;
13922
13923         switch (opcode) {
13924         case OP_IADD:
13925                 return OP_X86_ADD_MEMBASE_REG;
13926         case OP_ISUB:
13927                 return OP_X86_SUB_MEMBASE_REG;
13928         case OP_IAND:
13929                 return OP_X86_AND_MEMBASE_REG;
13930         case OP_IOR:
13931                 return OP_X86_OR_MEMBASE_REG;
13932         case OP_IXOR:
13933                 return OP_X86_XOR_MEMBASE_REG;
13934         case OP_IADD_IMM:
13935                 return OP_X86_ADD_MEMBASE_IMM;
13936         case OP_ISUB_IMM:
13937                 return OP_X86_SUB_MEMBASE_IMM;
13938         case OP_IAND_IMM:
13939                 return OP_X86_AND_MEMBASE_IMM;
13940         case OP_IOR_IMM:
13941                 return OP_X86_OR_MEMBASE_IMM;
13942         case OP_IXOR_IMM:
13943                 return OP_X86_XOR_MEMBASE_IMM;
13944         case OP_LADD:
13945                 return OP_AMD64_ADD_MEMBASE_REG;
13946         case OP_LSUB:
13947                 return OP_AMD64_SUB_MEMBASE_REG;
13948         case OP_LAND:
13949                 return OP_AMD64_AND_MEMBASE_REG;
13950         case OP_LOR:
13951                 return OP_AMD64_OR_MEMBASE_REG;
13952         case OP_LXOR:
13953                 return OP_AMD64_XOR_MEMBASE_REG;
13954         case OP_ADD_IMM:
13955         case OP_LADD_IMM:
13956                 return OP_AMD64_ADD_MEMBASE_IMM;
13957         case OP_SUB_IMM:
13958         case OP_LSUB_IMM:
13959                 return OP_AMD64_SUB_MEMBASE_IMM;
13960         case OP_AND_IMM:
13961         case OP_LAND_IMM:
13962                 return OP_AMD64_AND_MEMBASE_IMM;
13963         case OP_OR_IMM:
13964         case OP_LOR_IMM:
13965                 return OP_AMD64_OR_MEMBASE_IMM;
13966         case OP_XOR_IMM:
13967         case OP_LXOR_IMM:
13968                 return OP_AMD64_XOR_MEMBASE_IMM;
13969         case OP_MOVE:
13970                 return OP_NOP;
13971         }
13972 #endif
13973
13974         return -1;
13975 }
13976
13977 static inline int
13978 op_to_op_store_membase (int store_opcode, int opcode)
13979 {
13980 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13981         switch (opcode) {
13982         case OP_ICEQ:
13983                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13984                         return OP_X86_SETEQ_MEMBASE;
13985         case OP_CNE:
13986                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13987                         return OP_X86_SETNE_MEMBASE;
13988         }
13989 #endif
13990
13991         return -1;
13992 }
13993
13994 static inline int
13995 op_to_op_src1_membase (MonoCompile *cfg, int load_opcode, int opcode)
13996 {
13997 #ifdef TARGET_X86
13998         /* FIXME: This has sign extension issues */
13999         /*
14000         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
14001                 return OP_X86_COMPARE_MEMBASE8_IMM;
14002         */
14003
14004         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
14005                 return -1;
14006
14007         switch (opcode) {
14008         case OP_X86_PUSH:
14009                 return OP_X86_PUSH_MEMBASE;
14010         case OP_COMPARE_IMM:
14011         case OP_ICOMPARE_IMM:
14012                 return OP_X86_COMPARE_MEMBASE_IMM;
14013         case OP_COMPARE:
14014         case OP_ICOMPARE:
14015                 return OP_X86_COMPARE_MEMBASE_REG;
14016         }
14017 #endif
14018
14019 #ifdef TARGET_AMD64
14020         /* FIXME: This has sign extension issues */
14021         /*
14022         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
14023                 return OP_X86_COMPARE_MEMBASE8_IMM;
14024         */
14025
14026         switch (opcode) {
14027         case OP_X86_PUSH:
14028                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
14029                         return OP_X86_PUSH_MEMBASE;
14030                 break;
14031                 /* FIXME: This only works for 32 bit immediates
14032         case OP_COMPARE_IMM:
14033         case OP_LCOMPARE_IMM:
14034                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
14035                         return OP_AMD64_COMPARE_MEMBASE_IMM;
14036                 */
14037         case OP_ICOMPARE_IMM:
14038                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
14039                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
14040                 break;
14041         case OP_COMPARE:
14042         case OP_LCOMPARE:
14043                 if (cfg->backend->ilp32 && load_opcode == OP_LOAD_MEMBASE)
14044                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
14045                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
14046                         return OP_AMD64_COMPARE_MEMBASE_REG;
14047                 break;
14048         case OP_ICOMPARE:
14049                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
14050                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
14051                 break;
14052         }
14053 #endif
14054
14055         return -1;
14056 }
14057
14058 static inline int
14059 op_to_op_src2_membase (MonoCompile *cfg, int load_opcode, int opcode)
14060 {
14061 #ifdef TARGET_X86
14062         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
14063                 return -1;
14064         
14065         switch (opcode) {
14066         case OP_COMPARE:
14067         case OP_ICOMPARE:
14068                 return OP_X86_COMPARE_REG_MEMBASE;
14069         case OP_IADD:
14070                 return OP_X86_ADD_REG_MEMBASE;
14071         case OP_ISUB:
14072                 return OP_X86_SUB_REG_MEMBASE;
14073         case OP_IAND:
14074                 return OP_X86_AND_REG_MEMBASE;
14075         case OP_IOR:
14076                 return OP_X86_OR_REG_MEMBASE;
14077         case OP_IXOR:
14078                 return OP_X86_XOR_REG_MEMBASE;
14079         }
14080 #endif
14081
14082 #ifdef TARGET_AMD64
14083         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && cfg->backend->ilp32)) {
14084                 switch (opcode) {
14085                 case OP_ICOMPARE:
14086                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
14087                 case OP_IADD:
14088                         return OP_X86_ADD_REG_MEMBASE;
14089                 case OP_ISUB:
14090                         return OP_X86_SUB_REG_MEMBASE;
14091                 case OP_IAND:
14092                         return OP_X86_AND_REG_MEMBASE;
14093                 case OP_IOR:
14094                         return OP_X86_OR_REG_MEMBASE;
14095                 case OP_IXOR:
14096                         return OP_X86_XOR_REG_MEMBASE;
14097                 }
14098         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32)) {
14099                 switch (opcode) {
14100                 case OP_COMPARE:
14101                 case OP_LCOMPARE:
14102                         return OP_AMD64_COMPARE_REG_MEMBASE;
14103                 case OP_LADD:
14104                         return OP_AMD64_ADD_REG_MEMBASE;
14105                 case OP_LSUB:
14106                         return OP_AMD64_SUB_REG_MEMBASE;
14107                 case OP_LAND:
14108                         return OP_AMD64_AND_REG_MEMBASE;
14109                 case OP_LOR:
14110                         return OP_AMD64_OR_REG_MEMBASE;
14111                 case OP_LXOR:
14112                         return OP_AMD64_XOR_REG_MEMBASE;
14113                 }
14114         }
14115 #endif
14116
14117         return -1;
14118 }
14119
14120 int
14121 mono_op_to_op_imm_noemul (int opcode)
14122 {
14123         switch (opcode) {
14124 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
14125         case OP_LSHR:
14126         case OP_LSHL:
14127         case OP_LSHR_UN:
14128                 return -1;
14129 #endif
14130 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
14131         case OP_IDIV:
14132         case OP_IDIV_UN:
14133         case OP_IREM:
14134         case OP_IREM_UN:
14135                 return -1;
14136 #endif
14137 #if defined(MONO_ARCH_EMULATE_MUL_DIV)
14138         case OP_IMUL:
14139                 return -1;
14140 #endif
14141         default:
14142                 return mono_op_to_op_imm (opcode);
14143         }
14144 }
14145
14146 /**
14147  * mono_handle_global_vregs:
14148  *
14149  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
14150  * for them.
14151  */
14152 void
14153 mono_handle_global_vregs (MonoCompile *cfg)
14154 {
14155         gint32 *vreg_to_bb;
14156         MonoBasicBlock *bb;
14157         int i, pos;
14158
14159         vreg_to_bb = (gint32 *)mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
14160
14161 #ifdef MONO_ARCH_SIMD_INTRINSICS
14162         if (cfg->uses_simd_intrinsics)
14163                 mono_simd_simplify_indirection (cfg);
14164 #endif
14165
14166         /* Find local vregs used in more than one bb */
14167         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
14168                 MonoInst *ins = bb->code;       
14169                 int block_num = bb->block_num;
14170
14171                 if (cfg->verbose_level > 2)
14172                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
14173
14174                 cfg->cbb = bb;
14175                 for (; ins; ins = ins->next) {
14176                         const char *spec = INS_INFO (ins->opcode);
14177                         int regtype = 0, regindex;
14178                         gint32 prev_bb;
14179
14180                         if (G_UNLIKELY (cfg->verbose_level > 2))
14181                                 mono_print_ins (ins);
14182
14183                         g_assert (ins->opcode >= MONO_CEE_LAST);
14184
14185                         for (regindex = 0; regindex < 4; regindex ++) {
14186                                 int vreg = 0;
14187
14188                                 if (regindex == 0) {
14189                                         regtype = spec [MONO_INST_DEST];
14190                                         if (regtype == ' ')
14191                                                 continue;
14192                                         vreg = ins->dreg;
14193                                 } else if (regindex == 1) {
14194                                         regtype = spec [MONO_INST_SRC1];
14195                                         if (regtype == ' ')
14196                                                 continue;
14197                                         vreg = ins->sreg1;
14198                                 } else if (regindex == 2) {
14199                                         regtype = spec [MONO_INST_SRC2];
14200                                         if (regtype == ' ')
14201                                                 continue;
14202                                         vreg = ins->sreg2;
14203                                 } else if (regindex == 3) {
14204                                         regtype = spec [MONO_INST_SRC3];
14205                                         if (regtype == ' ')
14206                                                 continue;
14207                                         vreg = ins->sreg3;
14208                                 }
14209
14210 #if SIZEOF_REGISTER == 4
14211                                 /* In the LLVM case, the long opcodes are not decomposed */
14212                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
14213                                         /*
14214                                          * Since some instructions reference the original long vreg,
14215                                          * and some reference the two component vregs, it is quite hard
14216                                          * to determine when it needs to be global. So be conservative.
14217                                          */
14218                                         if (!get_vreg_to_inst (cfg, vreg)) {
14219                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
14220
14221                                                 if (cfg->verbose_level > 2)
14222                                                         printf ("LONG VREG R%d made global.\n", vreg);
14223                                         }
14224
14225                                         /*
14226                                          * Make the component vregs volatile since the optimizations can
14227                                          * get confused otherwise.
14228                                          */
14229                                         get_vreg_to_inst (cfg, MONO_LVREG_LS (vreg))->flags |= MONO_INST_VOLATILE;
14230                                         get_vreg_to_inst (cfg, MONO_LVREG_MS (vreg))->flags |= MONO_INST_VOLATILE;
14231                                 }
14232 #endif
14233
14234                                 g_assert (vreg != -1);
14235
14236                                 prev_bb = vreg_to_bb [vreg];
14237                                 if (prev_bb == 0) {
14238                                         /* 0 is a valid block num */
14239                                         vreg_to_bb [vreg] = block_num + 1;
14240                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
14241                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
14242                                                 continue;
14243
14244                                         if (!get_vreg_to_inst (cfg, vreg)) {
14245                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14246                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
14247
14248                                                 switch (regtype) {
14249                                                 case 'i':
14250                                                         if (vreg_is_ref (cfg, vreg))
14251                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg);
14252                                                         else
14253                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
14254                                                         break;
14255                                                 case 'l':
14256                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
14257                                                         break;
14258                                                 case 'f':
14259                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
14260                                                         break;
14261                                                 case 'v':
14262                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
14263                                                         break;
14264                                                 default:
14265                                                         g_assert_not_reached ();
14266                                                 }
14267                                         }
14268
14269                                         /* Flag as having been used in more than one bb */
14270                                         vreg_to_bb [vreg] = -1;
14271                                 }
14272                         }
14273                 }
14274         }
14275
14276         /* If a variable is used in only one bblock, convert it into a local vreg */
14277         for (i = 0; i < cfg->num_varinfo; i++) {
14278                 MonoInst *var = cfg->varinfo [i];
14279                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
14280
14281                 switch (var->type) {
14282                 case STACK_I4:
14283                 case STACK_OBJ:
14284                 case STACK_PTR:
14285                 case STACK_MP:
14286                 case STACK_VTYPE:
14287 #if SIZEOF_REGISTER == 8
14288                 case STACK_I8:
14289 #endif
14290 #if !defined(TARGET_X86)
14291                 /* Enabling this screws up the fp stack on x86 */
14292                 case STACK_R8:
14293 #endif
14294                         if (mono_arch_is_soft_float ())
14295                                 break;
14296
14297                         /*
14298                         if (var->type == STACK_VTYPE && cfg->gsharedvt && mini_is_gsharedvt_variable_type (var->inst_vtype))
14299                                 break;
14300                         */
14301
14302                         /* Arguments are implicitly global */
14303                         /* Putting R4 vars into registers doesn't work currently */
14304                         /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
14305                         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) {
14306                                 /* 
14307                                  * Make that the variable's liveness interval doesn't contain a call, since
14308                                  * that would cause the lvreg to be spilled, making the whole optimization
14309                                  * useless.
14310                                  */
14311                                 /* This is too slow for JIT compilation */
14312 #if 0
14313                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
14314                                         MonoInst *ins;
14315                                         int def_index, call_index, ins_index;
14316                                         gboolean spilled = FALSE;
14317
14318                                         def_index = -1;
14319                                         call_index = -1;
14320                                         ins_index = 0;
14321                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
14322                                                 const char *spec = INS_INFO (ins->opcode);
14323
14324                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
14325                                                         def_index = ins_index;
14326
14327                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
14328                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
14329                                                         if (call_index > def_index) {
14330                                                                 spilled = TRUE;
14331                                                                 break;
14332                                                         }
14333                                                 }
14334
14335                                                 if (MONO_IS_CALL (ins))
14336                                                         call_index = ins_index;
14337
14338                                                 ins_index ++;
14339                                         }
14340
14341                                         if (spilled)
14342                                                 break;
14343                                 }
14344 #endif
14345
14346                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14347                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
14348                                 var->flags |= MONO_INST_IS_DEAD;
14349                                 cfg->vreg_to_inst [var->dreg] = NULL;
14350                         }
14351                         break;
14352                 }
14353         }
14354
14355         /* 
14356          * Compress the varinfo and vars tables so the liveness computation is faster and
14357          * takes up less space.
14358          */
14359         pos = 0;
14360         for (i = 0; i < cfg->num_varinfo; ++i) {
14361                 MonoInst *var = cfg->varinfo [i];
14362                 if (pos < i && cfg->locals_start == i)
14363                         cfg->locals_start = pos;
14364                 if (!(var->flags & MONO_INST_IS_DEAD)) {
14365                         if (pos < i) {
14366                                 cfg->varinfo [pos] = cfg->varinfo [i];
14367                                 cfg->varinfo [pos]->inst_c0 = pos;
14368                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
14369                                 cfg->vars [pos].idx = pos;
14370 #if SIZEOF_REGISTER == 4
14371                                 if (cfg->varinfo [pos]->type == STACK_I8) {
14372                                         /* Modify the two component vars too */
14373                                         MonoInst *var1;
14374
14375                                         var1 = get_vreg_to_inst (cfg, MONO_LVREG_LS (cfg->varinfo [pos]->dreg));
14376                                         var1->inst_c0 = pos;
14377                                         var1 = get_vreg_to_inst (cfg, MONO_LVREG_MS (cfg->varinfo [pos]->dreg));
14378                                         var1->inst_c0 = pos;
14379                                 }
14380 #endif
14381                         }
14382                         pos ++;
14383                 }
14384         }
14385         cfg->num_varinfo = pos;
14386         if (cfg->locals_start > cfg->num_varinfo)
14387                 cfg->locals_start = cfg->num_varinfo;
14388 }
14389
14390 /*
14391  * mono_allocate_gsharedvt_vars:
14392  *
14393  *   Allocate variables with gsharedvt types to entries in the MonoGSharedVtMethodRuntimeInfo.entries array.
14394  * Initialize cfg->gsharedvt_vreg_to_idx with the mapping between vregs and indexes.
14395  */
14396 void
14397 mono_allocate_gsharedvt_vars (MonoCompile *cfg)
14398 {
14399         int i;
14400
14401         cfg->gsharedvt_vreg_to_idx = (int *)mono_mempool_alloc0 (cfg->mempool, sizeof (int) * cfg->next_vreg);
14402
14403         for (i = 0; i < cfg->num_varinfo; ++i) {
14404                 MonoInst *ins = cfg->varinfo [i];
14405                 int idx;
14406
14407                 if (mini_is_gsharedvt_variable_type (ins->inst_vtype)) {
14408                         if (i >= cfg->locals_start) {
14409                                 /* Local */
14410                                 idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
14411                                 cfg->gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
14412                                 ins->opcode = OP_GSHAREDVT_LOCAL;
14413                                 ins->inst_imm = idx;
14414                         } else {
14415                                 /* Arg */
14416                                 cfg->gsharedvt_vreg_to_idx [ins->dreg] = -1;
14417                                 ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
14418                         }
14419                 }
14420         }
14421 }
14422
14423 /**
14424  * mono_spill_global_vars:
14425  *
14426  *   Generate spill code for variables which are not allocated to registers, 
14427  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
14428  * code is generated which could be optimized by the local optimization passes.
14429  */
14430 void
14431 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
14432 {
14433         MonoBasicBlock *bb;
14434         char spec2 [16];
14435         int orig_next_vreg;
14436         guint32 *vreg_to_lvreg;
14437         guint32 *lvregs;
14438         guint32 i, lvregs_len;
14439         gboolean dest_has_lvreg = FALSE;
14440         MonoStackType stacktypes [128];
14441         MonoInst **live_range_start, **live_range_end;
14442         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
14443
14444         *need_local_opts = FALSE;
14445
14446         memset (spec2, 0, sizeof (spec2));
14447
14448         /* FIXME: Move this function to mini.c */
14449         stacktypes ['i'] = STACK_PTR;
14450         stacktypes ['l'] = STACK_I8;
14451         stacktypes ['f'] = STACK_R8;
14452 #ifdef MONO_ARCH_SIMD_INTRINSICS
14453         stacktypes ['x'] = STACK_VTYPE;
14454 #endif
14455
14456 #if SIZEOF_REGISTER == 4
14457         /* Create MonoInsts for longs */
14458         for (i = 0; i < cfg->num_varinfo; i++) {
14459                 MonoInst *ins = cfg->varinfo [i];
14460
14461                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
14462                         switch (ins->type) {
14463                         case STACK_R8:
14464                         case STACK_I8: {
14465                                 MonoInst *tree;
14466
14467                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
14468                                         break;
14469
14470                                 g_assert (ins->opcode == OP_REGOFFSET);
14471
14472                                 tree = get_vreg_to_inst (cfg, MONO_LVREG_LS (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_LS_WORD_OFFSET;
14477
14478                                 tree = get_vreg_to_inst (cfg, MONO_LVREG_MS (ins->dreg));
14479                                 g_assert (tree);
14480                                 tree->opcode = OP_REGOFFSET;
14481                                 tree->inst_basereg = ins->inst_basereg;
14482                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
14483                                 break;
14484                         }
14485                         default:
14486                                 break;
14487                         }
14488                 }
14489         }
14490 #endif
14491
14492         if (cfg->compute_gc_maps) {
14493                 /* registers need liveness info even for !non refs */
14494                 for (i = 0; i < cfg->num_varinfo; i++) {
14495                         MonoInst *ins = cfg->varinfo [i];
14496
14497                         if (ins->opcode == OP_REGVAR)
14498                                 ins->flags |= MONO_INST_GC_TRACK;
14499                 }
14500         }
14501                 
14502         /* FIXME: widening and truncation */
14503
14504         /*
14505          * As an optimization, when a variable allocated to the stack is first loaded into 
14506          * an lvreg, we will remember the lvreg and use it the next time instead of loading
14507          * the variable again.
14508          */
14509         orig_next_vreg = cfg->next_vreg;
14510         vreg_to_lvreg = (guint32 *)mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
14511         lvregs = (guint32 *)mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
14512         lvregs_len = 0;
14513
14514         /* 
14515          * These arrays contain the first and last instructions accessing a given
14516          * variable.
14517          * Since we emit bblocks in the same order we process them here, and we
14518          * don't split live ranges, these will precisely describe the live range of
14519          * the variable, i.e. the instruction range where a valid value can be found
14520          * in the variables location.
14521          * The live range is computed using the liveness info computed by the liveness pass.
14522          * We can't use vmv->range, since that is an abstract live range, and we need
14523          * one which is instruction precise.
14524          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
14525          */
14526         /* FIXME: Only do this if debugging info is requested */
14527         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
14528         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
14529         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
14530         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
14531         
14532         /* Add spill loads/stores */
14533         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
14534                 MonoInst *ins;
14535
14536                 if (cfg->verbose_level > 2)
14537                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
14538
14539                 /* Clear vreg_to_lvreg array */
14540                 for (i = 0; i < lvregs_len; i++)
14541                         vreg_to_lvreg [lvregs [i]] = 0;
14542                 lvregs_len = 0;
14543
14544                 cfg->cbb = bb;
14545                 MONO_BB_FOR_EACH_INS (bb, ins) {
14546                         const char *spec = INS_INFO (ins->opcode);
14547                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
14548                         gboolean store, no_lvreg;
14549                         int sregs [MONO_MAX_SRC_REGS];
14550
14551                         if (G_UNLIKELY (cfg->verbose_level > 2))
14552                                 mono_print_ins (ins);
14553
14554                         if (ins->opcode == OP_NOP)
14555                                 continue;
14556
14557                         /* 
14558                          * We handle LDADDR here as well, since it can only be decomposed
14559                          * when variable addresses are known.
14560                          */
14561                         if (ins->opcode == OP_LDADDR) {
14562                                 MonoInst *var = (MonoInst *)ins->inst_p0;
14563
14564                                 if (var->opcode == OP_VTARG_ADDR) {
14565                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
14566                                         MonoInst *vtaddr = var->inst_left;
14567                                         if (vtaddr->opcode == OP_REGVAR) {
14568                                                 ins->opcode = OP_MOVE;
14569                                                 ins->sreg1 = vtaddr->dreg;
14570                                         }
14571                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
14572                                                 ins->opcode = OP_LOAD_MEMBASE;
14573                                                 ins->inst_basereg = vtaddr->inst_basereg;
14574                                                 ins->inst_offset = vtaddr->inst_offset;
14575                                         } else
14576                                                 NOT_IMPLEMENTED;
14577                                 } else if (cfg->gsharedvt && cfg->gsharedvt_vreg_to_idx [var->dreg] < 0) {
14578                                         /* gsharedvt arg passed by ref */
14579                                         g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
14580
14581                                         ins->opcode = OP_LOAD_MEMBASE;
14582                                         ins->inst_basereg = var->inst_basereg;
14583                                         ins->inst_offset = var->inst_offset;
14584                                 } else if (cfg->gsharedvt && cfg->gsharedvt_vreg_to_idx [var->dreg]) {
14585                                         MonoInst *load, *load2, *load3;
14586                                         int idx = cfg->gsharedvt_vreg_to_idx [var->dreg] - 1;
14587                                         int reg1, reg2, reg3;
14588                                         MonoInst *info_var = cfg->gsharedvt_info_var;
14589                                         MonoInst *locals_var = cfg->gsharedvt_locals_var;
14590
14591                                         /*
14592                                          * gsharedvt local.
14593                                          * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
14594                                          */
14595
14596                                         g_assert (var->opcode == OP_GSHAREDVT_LOCAL);
14597
14598                                         g_assert (info_var);
14599                                         g_assert (locals_var);
14600
14601                                         /* Mark the instruction used to compute the locals var as used */
14602                                         cfg->gsharedvt_locals_var_ins = NULL;
14603
14604                                         /* Load the offset */
14605                                         if (info_var->opcode == OP_REGOFFSET) {
14606                                                 reg1 = alloc_ireg (cfg);
14607                                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, reg1, info_var->inst_basereg, info_var->inst_offset);
14608                                         } else if (info_var->opcode == OP_REGVAR) {
14609                                                 load = NULL;
14610                                                 reg1 = info_var->dreg;
14611                                         } else {
14612                                                 g_assert_not_reached ();
14613                                         }
14614                                         reg2 = alloc_ireg (cfg);
14615                                         NEW_LOAD_MEMBASE (cfg, load2, OP_LOADI4_MEMBASE, reg2, reg1, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
14616                                         /* Load the locals area address */
14617                                         reg3 = alloc_ireg (cfg);
14618                                         if (locals_var->opcode == OP_REGOFFSET) {
14619                                                 NEW_LOAD_MEMBASE (cfg, load3, OP_LOAD_MEMBASE, reg3, locals_var->inst_basereg, locals_var->inst_offset);
14620                                         } else if (locals_var->opcode == OP_REGVAR) {
14621                                                 NEW_UNALU (cfg, load3, OP_MOVE, reg3, locals_var->dreg);
14622                                         } else {
14623                                                 g_assert_not_reached ();
14624                                         }
14625                                         /* Compute the address */
14626                                         ins->opcode = OP_PADD;
14627                                         ins->sreg1 = reg3;
14628                                         ins->sreg2 = reg2;
14629
14630                                         mono_bblock_insert_before_ins (bb, ins, load3);
14631                                         mono_bblock_insert_before_ins (bb, load3, load2);
14632                                         if (load)
14633                                                 mono_bblock_insert_before_ins (bb, load2, load);
14634                                 } else {
14635                                         g_assert (var->opcode == OP_REGOFFSET);
14636
14637                                         ins->opcode = OP_ADD_IMM;
14638                                         ins->sreg1 = var->inst_basereg;
14639                                         ins->inst_imm = var->inst_offset;
14640                                 }
14641
14642                                 *need_local_opts = TRUE;
14643                                 spec = INS_INFO (ins->opcode);
14644                         }
14645
14646                         if (ins->opcode < MONO_CEE_LAST) {
14647                                 mono_print_ins (ins);
14648                                 g_assert_not_reached ();
14649                         }
14650
14651                         /*
14652                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
14653                          * src register.
14654                          * FIXME:
14655                          */
14656                         if (MONO_IS_STORE_MEMBASE (ins)) {
14657                                 tmp_reg = ins->dreg;
14658                                 ins->dreg = ins->sreg2;
14659                                 ins->sreg2 = tmp_reg;
14660                                 store = TRUE;
14661
14662                                 spec2 [MONO_INST_DEST] = ' ';
14663                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14664                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14665                                 spec2 [MONO_INST_SRC3] = ' ';
14666                                 spec = spec2;
14667                         } else if (MONO_IS_STORE_MEMINDEX (ins))
14668                                 g_assert_not_reached ();
14669                         else
14670                                 store = FALSE;
14671                         no_lvreg = FALSE;
14672
14673                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
14674                                 printf ("\t %.3s %d", spec, ins->dreg);
14675                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
14676                                 for (srcindex = 0; srcindex < num_sregs; ++srcindex)
14677                                         printf (" %d", sregs [srcindex]);
14678                                 printf ("\n");
14679                         }
14680
14681                         /***************/
14682                         /*    DREG     */
14683                         /***************/
14684                         regtype = spec [MONO_INST_DEST];
14685                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
14686                         prev_dreg = -1;
14687
14688                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
14689                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
14690                                 MonoInst *store_ins;
14691                                 int store_opcode;
14692                                 MonoInst *def_ins = ins;
14693                                 int dreg = ins->dreg; /* The original vreg */
14694
14695                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
14696
14697                                 if (var->opcode == OP_REGVAR) {
14698                                         ins->dreg = var->dreg;
14699                                 } 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)) {
14700                                         /* 
14701                                          * Instead of emitting a load+store, use a _membase opcode.
14702                                          */
14703                                         g_assert (var->opcode == OP_REGOFFSET);
14704                                         if (ins->opcode == OP_MOVE) {
14705                                                 NULLIFY_INS (ins);
14706                                                 def_ins = NULL;
14707                                         } else {
14708                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
14709                                                 ins->inst_basereg = var->inst_basereg;
14710                                                 ins->inst_offset = var->inst_offset;
14711                                                 ins->dreg = -1;
14712                                         }
14713                                         spec = INS_INFO (ins->opcode);
14714                                 } else {
14715                                         guint32 lvreg;
14716
14717                                         g_assert (var->opcode == OP_REGOFFSET);
14718
14719                                         prev_dreg = ins->dreg;
14720
14721                                         /* Invalidate any previous lvreg for this vreg */
14722                                         vreg_to_lvreg [ins->dreg] = 0;
14723
14724                                         lvreg = 0;
14725
14726                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
14727                                                 regtype = 'l';
14728                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
14729                                         }
14730
14731                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
14732
14733 #if SIZEOF_REGISTER != 8
14734                                         if (regtype == 'l') {
14735                                                 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));
14736                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14737                                                 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));
14738                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14739                                                 def_ins = store_ins;
14740                                         }
14741                                         else
14742 #endif
14743                                         {
14744                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
14745
14746                                                 /* Try to fuse the store into the instruction itself */
14747                                                 /* FIXME: Add more instructions */
14748                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
14749                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
14750                                                         ins->inst_imm = ins->inst_c0;
14751                                                         ins->inst_destbasereg = var->inst_basereg;
14752                                                         ins->inst_offset = var->inst_offset;
14753                                                         spec = INS_INFO (ins->opcode);
14754                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE) || (ins->opcode == OP_RMOVE))) {
14755                                                         ins->opcode = store_opcode;
14756                                                         ins->inst_destbasereg = var->inst_basereg;
14757                                                         ins->inst_offset = var->inst_offset;
14758
14759                                                         no_lvreg = TRUE;
14760
14761                                                         tmp_reg = ins->dreg;
14762                                                         ins->dreg = ins->sreg2;
14763                                                         ins->sreg2 = tmp_reg;
14764                                                         store = TRUE;
14765
14766                                                         spec2 [MONO_INST_DEST] = ' ';
14767                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14768                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14769                                                         spec2 [MONO_INST_SRC3] = ' ';
14770                                                         spec = spec2;
14771                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
14772                                                         // FIXME: The backends expect the base reg to be in inst_basereg
14773                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
14774                                                         ins->dreg = -1;
14775                                                         ins->inst_basereg = var->inst_basereg;
14776                                                         ins->inst_offset = var->inst_offset;
14777                                                         spec = INS_INFO (ins->opcode);
14778                                                 } else {
14779                                                         /* printf ("INS: "); mono_print_ins (ins); */
14780                                                         /* Create a store instruction */
14781                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
14782
14783                                                         /* Insert it after the instruction */
14784                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
14785
14786                                                         def_ins = store_ins;
14787
14788                                                         /* 
14789                                                          * We can't assign ins->dreg to var->dreg here, since the
14790                                                          * sregs could use it. So set a flag, and do it after
14791                                                          * the sregs.
14792                                                          */
14793                                                         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)))
14794                                                                 dest_has_lvreg = TRUE;
14795                                                 }
14796                                         }
14797                                 }
14798
14799                                 if (def_ins && !live_range_start [dreg]) {
14800                                         live_range_start [dreg] = def_ins;
14801                                         live_range_start_bb [dreg] = bb;
14802                                 }
14803
14804                                 if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) {
14805                                         MonoInst *tmp;
14806
14807                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
14808                                         tmp->inst_c1 = dreg;
14809                                         mono_bblock_insert_after_ins (bb, def_ins, tmp);
14810                                 }
14811                         }
14812
14813                         /************/
14814                         /*  SREGS   */
14815                         /************/
14816                         num_sregs = mono_inst_get_src_registers (ins, sregs);
14817                         for (srcindex = 0; srcindex < 3; ++srcindex) {
14818                                 regtype = spec [MONO_INST_SRC1 + srcindex];
14819                                 sreg = sregs [srcindex];
14820
14821                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
14822                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
14823                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
14824                                         MonoInst *use_ins = ins;
14825                                         MonoInst *load_ins;
14826                                         guint32 load_opcode;
14827
14828                                         if (var->opcode == OP_REGVAR) {
14829                                                 sregs [srcindex] = var->dreg;
14830                                                 //mono_inst_set_src_registers (ins, sregs);
14831                                                 live_range_end [sreg] = use_ins;
14832                                                 live_range_end_bb [sreg] = bb;
14833
14834                                                 if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14835                                                         MonoInst *tmp;
14836
14837                                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14838                                                         /* var->dreg is a hreg */
14839                                                         tmp->inst_c1 = sreg;
14840                                                         mono_bblock_insert_after_ins (bb, ins, tmp);
14841                                                 }
14842
14843                                                 continue;
14844                                         }
14845
14846                                         g_assert (var->opcode == OP_REGOFFSET);
14847                                                 
14848                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
14849
14850                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
14851
14852                                         if (vreg_to_lvreg [sreg]) {
14853                                                 g_assert (vreg_to_lvreg [sreg] != -1);
14854
14855                                                 /* The variable is already loaded to an lvreg */
14856                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14857                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
14858                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
14859                                                 //mono_inst_set_src_registers (ins, sregs);
14860                                                 continue;
14861                                         }
14862
14863                                         /* Try to fuse the load into the instruction */
14864                                         if ((srcindex == 0) && (op_to_op_src1_membase (cfg, load_opcode, ins->opcode) != -1)) {
14865                                                 ins->opcode = op_to_op_src1_membase (cfg, load_opcode, ins->opcode);
14866                                                 sregs [0] = var->inst_basereg;
14867                                                 //mono_inst_set_src_registers (ins, sregs);
14868                                                 ins->inst_offset = var->inst_offset;
14869                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (cfg, load_opcode, ins->opcode) != -1)) {
14870                                                 ins->opcode = op_to_op_src2_membase (cfg, load_opcode, ins->opcode);
14871                                                 sregs [1] = var->inst_basereg;
14872                                                 //mono_inst_set_src_registers (ins, sregs);
14873                                                 ins->inst_offset = var->inst_offset;
14874                                         } else {
14875                                                 if (MONO_IS_REAL_MOVE (ins)) {
14876                                                         ins->opcode = OP_NOP;
14877                                                         sreg = ins->dreg;
14878                                                 } else {
14879                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
14880
14881                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
14882
14883                                                         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) {
14884                                                                 if (var->dreg == prev_dreg) {
14885                                                                         /*
14886                                                                          * sreg refers to the value loaded by the load
14887                                                                          * emitted below, but we need to use ins->dreg
14888                                                                          * since it refers to the store emitted earlier.
14889                                                                          */
14890                                                                         sreg = ins->dreg;
14891                                                                 }
14892                                                                 g_assert (sreg != -1);
14893                                                                 vreg_to_lvreg [var->dreg] = sreg;
14894                                                                 g_assert (lvregs_len < 1024);
14895                                                                 lvregs [lvregs_len ++] = var->dreg;
14896                                                         }
14897                                                 }
14898
14899                                                 sregs [srcindex] = sreg;
14900                                                 //mono_inst_set_src_registers (ins, sregs);
14901
14902 #if SIZEOF_REGISTER != 8
14903                                                 if (regtype == 'l') {
14904                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, MONO_LVREG_MS (sreg), var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
14905                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14906                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, MONO_LVREG_LS (sreg), var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
14907                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14908                                                         use_ins = load_ins;
14909                                                 }
14910                                                 else
14911 #endif
14912                                                 {
14913 #if SIZEOF_REGISTER == 4
14914                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
14915 #endif
14916                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
14917                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14918                                                         use_ins = load_ins;
14919                                                 }
14920                                         }
14921
14922                                         if (var->dreg < orig_next_vreg) {
14923                                                 live_range_end [var->dreg] = use_ins;
14924                                                 live_range_end_bb [var->dreg] = bb;
14925                                         }
14926
14927                                         if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14928                                                 MonoInst *tmp;
14929
14930                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14931                                                 tmp->inst_c1 = var->dreg;
14932                                                 mono_bblock_insert_after_ins (bb, ins, tmp);
14933                                         }
14934                                 }
14935                         }
14936                         mono_inst_set_src_registers (ins, sregs);
14937
14938                         if (dest_has_lvreg) {
14939                                 g_assert (ins->dreg != -1);
14940                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
14941                                 g_assert (lvregs_len < 1024);
14942                                 lvregs [lvregs_len ++] = prev_dreg;
14943                                 dest_has_lvreg = FALSE;
14944                         }
14945
14946                         if (store) {
14947                                 tmp_reg = ins->dreg;
14948                                 ins->dreg = ins->sreg2;
14949                                 ins->sreg2 = tmp_reg;
14950                         }
14951
14952                         if (MONO_IS_CALL (ins)) {
14953                                 /* Clear vreg_to_lvreg array */
14954                                 for (i = 0; i < lvregs_len; i++)
14955                                         vreg_to_lvreg [lvregs [i]] = 0;
14956                                 lvregs_len = 0;
14957                         } else if (ins->opcode == OP_NOP) {
14958                                 ins->dreg = -1;
14959                                 MONO_INST_NULLIFY_SREGS (ins);
14960                         }
14961
14962                         if (cfg->verbose_level > 2)
14963                                 mono_print_ins_index (1, ins);
14964                 }
14965
14966                 /* Extend the live range based on the liveness info */
14967                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
14968                         for (i = 0; i < cfg->num_varinfo; i ++) {
14969                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
14970
14971                                 if (vreg_is_volatile (cfg, vi->vreg))
14972                                         /* The liveness info is incomplete */
14973                                         continue;
14974
14975                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
14976                                         /* Live from at least the first ins of this bb */
14977                                         live_range_start [vi->vreg] = bb->code;
14978                                         live_range_start_bb [vi->vreg] = bb;
14979                                 }
14980
14981                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
14982                                         /* Live at least until the last ins of this bb */
14983                                         live_range_end [vi->vreg] = bb->last_ins;
14984                                         live_range_end_bb [vi->vreg] = bb;
14985                                 }
14986                         }
14987                 }
14988         }
14989         
14990         /*
14991          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
14992          * by storing the current native offset into MonoMethodVar->live_range_start/end.
14993          */
14994         if (cfg->backend->have_liverange_ops && cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
14995                 for (i = 0; i < cfg->num_varinfo; ++i) {
14996                         int vreg = MONO_VARINFO (cfg, i)->vreg;
14997                         MonoInst *ins;
14998
14999                         if (live_range_start [vreg]) {
15000                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
15001                                 ins->inst_c0 = i;
15002                                 ins->inst_c1 = vreg;
15003                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
15004                         }
15005                         if (live_range_end [vreg]) {
15006                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
15007                                 ins->inst_c0 = i;
15008                                 ins->inst_c1 = vreg;
15009                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
15010                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
15011                                 else
15012                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
15013                         }
15014                 }
15015         }
15016
15017         if (cfg->gsharedvt_locals_var_ins) {
15018                 /* Nullify if unused */
15019                 cfg->gsharedvt_locals_var_ins->opcode = OP_PCONST;
15020                 cfg->gsharedvt_locals_var_ins->inst_imm = 0;
15021         }
15022
15023         g_free (live_range_start);
15024         g_free (live_range_end);
15025         g_free (live_range_start_bb);
15026         g_free (live_range_end_bb);
15027 }
15028
15029 /**
15030  * FIXME:
15031  * - use 'iadd' instead of 'int_add'
15032  * - handling ovf opcodes: decompose in method_to_ir.
15033  * - unify iregs/fregs
15034  *   -> partly done, the missing parts are:
15035  *   - a more complete unification would involve unifying the hregs as well, so
15036  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
15037  *     would no longer map to the machine hregs, so the code generators would need to
15038  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
15039  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
15040  *     fp/non-fp branches speeds it up by about 15%.
15041  * - use sext/zext opcodes instead of shifts
15042  * - add OP_ICALL
15043  * - get rid of TEMPLOADs if possible and use vregs instead
15044  * - clean up usage of OP_P/OP_ opcodes
15045  * - cleanup usage of DUMMY_USE
15046  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
15047  *   stack
15048  * - set the stack type and allocate a dreg in the EMIT_NEW macros
15049  * - get rid of all the <foo>2 stuff when the new JIT is ready.
15050  * - make sure handle_stack_args () is called before the branch is emitted
15051  * - when the new IR is done, get rid of all unused stuff
15052  * - COMPARE/BEQ as separate instructions or unify them ?
15053  *   - keeping them separate allows specialized compare instructions like
15054  *     compare_imm, compare_membase
15055  *   - most back ends unify fp compare+branch, fp compare+ceq
15056  * - integrate mono_save_args into inline_method
15057  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
15058  * - handle long shift opts on 32 bit platforms somehow: they require 
15059  *   3 sregs (2 for arg1 and 1 for arg2)
15060  * - make byref a 'normal' type.
15061  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
15062  *   variable if needed.
15063  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
15064  *   like inline_method.
15065  * - remove inlining restrictions
15066  * - fix LNEG and enable cfold of INEG
15067  * - generalize x86 optimizations like ldelema as a peephole optimization
15068  * - add store_mem_imm for amd64
15069  * - optimize the loading of the interruption flag in the managed->native wrappers
15070  * - avoid special handling of OP_NOP in passes
15071  * - move code inserting instructions into one function/macro.
15072  * - try a coalescing phase after liveness analysis
15073  * - add float -> vreg conversion + local optimizations on !x86
15074  * - figure out how to handle decomposed branches during optimizations, ie.
15075  *   compare+branch, op_jump_table+op_br etc.
15076  * - promote RuntimeXHandles to vregs
15077  * - vtype cleanups:
15078  *   - add a NEW_VARLOADA_VREG macro
15079  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
15080  *   accessing vtype fields.
15081  * - get rid of I8CONST on 64 bit platforms
15082  * - dealing with the increase in code size due to branches created during opcode
15083  *   decomposition:
15084  *   - use extended basic blocks
15085  *     - all parts of the JIT
15086  *     - handle_global_vregs () && local regalloc
15087  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
15088  * - sources of increase in code size:
15089  *   - vtypes
15090  *   - long compares
15091  *   - isinst and castclass
15092  *   - lvregs not allocated to global registers even if used multiple times
15093  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
15094  *   meaningful.
15095  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
15096  * - add all micro optimizations from the old JIT
15097  * - put tree optimizations into the deadce pass
15098  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
15099  *   specific function.
15100  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
15101  *   fcompare + branchCC.
15102  * - create a helper function for allocating a stack slot, taking into account 
15103  *   MONO_CFG_HAS_SPILLUP.
15104  * - merge r68207.
15105  * - merge the ia64 switch changes.
15106  * - optimize mono_regstate2_alloc_int/float.
15107  * - fix the pessimistic handling of variables accessed in exception handler blocks.
15108  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
15109  *   parts of the tree could be separated by other instructions, killing the tree
15110  *   arguments, or stores killing loads etc. Also, should we fold loads into other
15111  *   instructions if the result of the load is used multiple times ?
15112  * - make the REM_IMM optimization in mini-x86.c arch-independent.
15113  * - LAST MERGE: 108395.
15114  * - when returning vtypes in registers, generate IR and append it to the end of the
15115  *   last bb instead of doing it in the epilog.
15116  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
15117  */
15118
15119 /*
15120
15121 NOTES
15122 -----
15123
15124 - When to decompose opcodes:
15125   - earlier: this makes some optimizations hard to implement, since the low level IR
15126   no longer contains the neccessary information. But it is easier to do.
15127   - later: harder to implement, enables more optimizations.
15128 - Branches inside bblocks:
15129   - created when decomposing complex opcodes. 
15130     - branches to another bblock: harmless, but not tracked by the branch 
15131       optimizations, so need to branch to a label at the start of the bblock.
15132     - branches to inside the same bblock: very problematic, trips up the local
15133       reg allocator. Can be fixed by spitting the current bblock, but that is a
15134       complex operation, since some local vregs can become global vregs etc.
15135 - Local/global vregs:
15136   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
15137     local register allocator.
15138   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
15139     structure, created by mono_create_var (). Assigned to hregs or the stack by
15140     the global register allocator.
15141 - When to do optimizations like alu->alu_imm:
15142   - earlier -> saves work later on since the IR will be smaller/simpler
15143   - later -> can work on more instructions
15144 - Handling of valuetypes:
15145   - When a vtype is pushed on the stack, a new temporary is created, an 
15146     instruction computing its address (LDADDR) is emitted and pushed on
15147     the stack. Need to optimize cases when the vtype is used immediately as in
15148     argument passing, stloc etc.
15149 - Instead of the to_end stuff in the old JIT, simply call the function handling
15150   the values on the stack before emitting the last instruction of the bb.
15151 */
15152
15153 #endif /* DISABLE_JIT */