Merge pull request #3586 from henricm/fix-win-uri-tests
[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  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
12  */
13
14 #include <config.h>
15
16 #ifndef DISABLE_JIT
17
18 #include <signal.h>
19
20 #ifdef HAVE_UNISTD_H
21 #include <unistd.h>
22 #endif
23
24 #include <math.h>
25 #include <string.h>
26 #include <ctype.h>
27
28 #ifdef HAVE_SYS_TIME_H
29 #include <sys/time.h>
30 #endif
31
32 #ifdef HAVE_ALLOCA_H
33 #include <alloca.h>
34 #endif
35
36 #include <mono/utils/memcheck.h>
37 #include "mini.h"
38 #include <mono/metadata/abi-details.h>
39 #include <mono/metadata/assembly.h>
40 #include <mono/metadata/attrdefs.h>
41 #include <mono/metadata/loader.h>
42 #include <mono/metadata/tabledefs.h>
43 #include <mono/metadata/class.h>
44 #include <mono/metadata/object.h>
45 #include <mono/metadata/exception.h>
46 #include <mono/metadata/opcodes.h>
47 #include <mono/metadata/mono-endian.h>
48 #include <mono/metadata/tokentype.h>
49 #include <mono/metadata/tabledefs.h>
50 #include <mono/metadata/marshal.h>
51 #include <mono/metadata/debug-helpers.h>
52 #include <mono/metadata/mono-debug.h>
53 #include <mono/metadata/mono-debug-debugger.h>
54 #include <mono/metadata/gc-internals.h>
55 #include <mono/metadata/security-manager.h>
56 #include <mono/metadata/threads-types.h>
57 #include <mono/metadata/security-core-clr.h>
58 #include <mono/metadata/profiler-private.h>
59 #include <mono/metadata/profiler.h>
60 #include <mono/metadata/monitor.h>
61 #include <mono/metadata/debug-mono-symfile.h>
62 #include <mono/utils/mono-compiler.h>
63 #include <mono/utils/mono-memory-model.h>
64 #include <mono/utils/mono-error-internals.h>
65 #include <mono/metadata/mono-basic-block.h>
66 #include <mono/metadata/reflection-internals.h>
67 #include <mono/utils/mono-threads-coop.h>
68
69 #include "trace.h"
70
71 #include "ir-emit.h"
72
73 #include "jit-icalls.h"
74 #include "jit.h"
75 #include "debugger-agent.h"
76 #include "seq-points.h"
77 #include "aot-compiler.h"
78 #include "mini-llvm.h"
79
80 #define BRANCH_COST 10
81 #define INLINE_LENGTH_LIMIT 20
82
83 /* These have 'cfg' as an implicit argument */
84 #define INLINE_FAILURE(msg) do {                                                                        \
85         if ((cfg->method != cfg->current_method) && (cfg->current_method->wrapper_type == MONO_WRAPPER_NONE)) { \
86                 inline_failure (cfg, msg);                                                                              \
87                 goto exception_exit;                                                                                    \
88         } \
89         } while (0)
90 #define CHECK_CFG_EXCEPTION do {\
91                 if (cfg->exception_type != MONO_EXCEPTION_NONE) \
92                         goto exception_exit;                                            \
93         } while (0)
94 #define FIELD_ACCESS_FAILURE(method, field) do {                                        \
95                 field_access_failure ((cfg), (method), (field));                        \
96                 goto exception_exit;    \
97         } while (0)
98 #define GENERIC_SHARING_FAILURE(opcode) do {            \
99                 if (cfg->gshared) {                                                                     \
100                         gshared_failure (cfg, opcode, __FILE__, __LINE__);      \
101                         goto exception_exit;    \
102                 }                       \
103         } while (0)
104 #define GSHAREDVT_FAILURE(opcode) do {          \
105         if (cfg->gsharedvt) {                                                                                           \
106                 gsharedvt_failure (cfg, opcode, __FILE__, __LINE__);                    \
107                 goto exception_exit;                                                                                    \
108         }                                                                                                                                       \
109         } while (0)
110 #define OUT_OF_MEMORY_FAILURE do {      \
111                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);                \
112                 mono_error_set_out_of_memory (&cfg->error, "");                                 \
113                 goto exception_exit;    \
114         } while (0)
115 #define DISABLE_AOT(cfg) do { \
116                 if ((cfg)->verbose_level >= 2)                                            \
117                         printf ("AOT disabled: %s:%d\n", __FILE__, __LINE__);   \
118                 (cfg)->disable_aot = TRUE;                                                        \
119         } while (0)
120 #define LOAD_ERROR do { \
121                 break_on_unverified ();                                                         \
122                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD); \
123                 goto exception_exit;                                                                    \
124         } while (0)
125
126 #define TYPE_LOAD_ERROR(klass) do { \
127                 cfg->exception_ptr = klass; \
128                 LOAD_ERROR;                                     \
129         } while (0)
130
131 #define CHECK_CFG_ERROR do {\
132                 if (!mono_error_ok (&cfg->error)) { \
133                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);        \
134                         goto mono_error_exit; \
135                 } \
136         } while (0)
137
138 /* Determine whenever 'ins' represents a load of the 'this' argument */
139 #define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && ((ins)->opcode == OP_MOVE) && ((ins)->sreg1 == cfg->args [0]->dreg))
140
141 static int ldind_to_load_membase (int opcode);
142 static int stind_to_store_membase (int opcode);
143
144 int mono_op_to_op_imm (int opcode);
145 int mono_op_to_op_imm_noemul (int opcode);
146
147 MONO_API MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
148
149 static int inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
150                                                   guchar *ip, guint real_offset, gboolean inline_always);
151 static MonoInst*
152 emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used, MonoInst **sp);
153
154 /* helper methods signatures */
155 static MonoMethodSignature *helper_sig_domain_get;
156 static MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline;
157 static MonoMethodSignature *helper_sig_llvmonly_imt_trampoline;
158
159 /* type loading helpers */
160 static GENERATE_GET_CLASS_WITH_CACHE (runtime_helpers, System.Runtime.CompilerServices, RuntimeHelpers)
161 static GENERATE_TRY_GET_CLASS_WITH_CACHE (debuggable_attribute, System.Diagnostics, DebuggableAttribute)
162
163 /*
164  * Instruction metadata
165  */
166 #ifdef MINI_OP
167 #undef MINI_OP
168 #endif
169 #ifdef MINI_OP3
170 #undef MINI_OP3
171 #endif
172 #define MINI_OP(a,b,dest,src1,src2) dest, src1, src2, ' ',
173 #define MINI_OP3(a,b,dest,src1,src2,src3) dest, src1, src2, src3,
174 #define NONE ' '
175 #define IREG 'i'
176 #define FREG 'f'
177 #define VREG 'v'
178 #define XREG 'x'
179 #if SIZEOF_REGISTER == 8 && SIZEOF_REGISTER == SIZEOF_VOID_P
180 #define LREG IREG
181 #else
182 #define LREG 'l'
183 #endif
184 /* keep in sync with the enum in mini.h */
185 const char
186 ins_info[] = {
187 #include "mini-ops.h"
188 };
189 #undef MINI_OP
190 #undef MINI_OP3
191
192 #define MINI_OP(a,b,dest,src1,src2) ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0)),
193 #define MINI_OP3(a,b,dest,src1,src2,src3) ((src3) != NONE ? 3 : ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0))),
194 /* 
195  * This should contain the index of the last sreg + 1. This is not the same
196  * as the number of sregs for opcodes like IA64_CMP_EQ_IMM.
197  */
198 const gint8 ins_sreg_counts[] = {
199 #include "mini-ops.h"
200 };
201 #undef MINI_OP
202 #undef MINI_OP3
203
204 #define MONO_INIT_VARINFO(vi,id) do { \
205         (vi)->range.first_use.pos.bid = 0xffff; \
206         (vi)->reg = -1; \
207         (vi)->idx = (id); \
208 } while (0)
209
210 guint32
211 mono_alloc_ireg (MonoCompile *cfg)
212 {
213         return alloc_ireg (cfg);
214 }
215
216 guint32
217 mono_alloc_lreg (MonoCompile *cfg)
218 {
219         return alloc_lreg (cfg);
220 }
221
222 guint32
223 mono_alloc_freg (MonoCompile *cfg)
224 {
225         return alloc_freg (cfg);
226 }
227
228 guint32
229 mono_alloc_preg (MonoCompile *cfg)
230 {
231         return alloc_preg (cfg);
232 }
233
234 guint32
235 mono_alloc_dreg (MonoCompile *cfg, MonoStackType stack_type)
236 {
237         return alloc_dreg (cfg, stack_type);
238 }
239
240 /*
241  * mono_alloc_ireg_ref:
242  *
243  *   Allocate an IREG, and mark it as holding a GC ref.
244  */
245 guint32
246 mono_alloc_ireg_ref (MonoCompile *cfg)
247 {
248         return alloc_ireg_ref (cfg);
249 }
250
251 /*
252  * mono_alloc_ireg_mp:
253  *
254  *   Allocate an IREG, and mark it as holding a managed pointer.
255  */
256 guint32
257 mono_alloc_ireg_mp (MonoCompile *cfg)
258 {
259         return alloc_ireg_mp (cfg);
260 }
261
262 /*
263  * mono_alloc_ireg_copy:
264  *
265  *   Allocate an IREG with the same GC type as VREG.
266  */
267 guint32
268 mono_alloc_ireg_copy (MonoCompile *cfg, guint32 vreg)
269 {
270         if (vreg_is_ref (cfg, vreg))
271                 return alloc_ireg_ref (cfg);
272         else if (vreg_is_mp (cfg, vreg))
273                 return alloc_ireg_mp (cfg);
274         else
275                 return alloc_ireg (cfg);
276 }
277
278 guint
279 mono_type_to_regmove (MonoCompile *cfg, MonoType *type)
280 {
281         if (type->byref)
282                 return OP_MOVE;
283
284         type = mini_get_underlying_type (type);
285 handle_enum:
286         switch (type->type) {
287         case MONO_TYPE_I1:
288         case MONO_TYPE_U1:
289                 return OP_MOVE;
290         case MONO_TYPE_I2:
291         case MONO_TYPE_U2:
292                 return OP_MOVE;
293         case MONO_TYPE_I4:
294         case MONO_TYPE_U4:
295                 return OP_MOVE;
296         case MONO_TYPE_I:
297         case MONO_TYPE_U:
298         case MONO_TYPE_PTR:
299         case MONO_TYPE_FNPTR:
300                 return OP_MOVE;
301         case MONO_TYPE_CLASS:
302         case MONO_TYPE_STRING:
303         case MONO_TYPE_OBJECT:
304         case MONO_TYPE_SZARRAY:
305         case MONO_TYPE_ARRAY:    
306                 return OP_MOVE;
307         case MONO_TYPE_I8:
308         case MONO_TYPE_U8:
309 #if SIZEOF_REGISTER == 8
310                 return OP_MOVE;
311 #else
312                 return OP_LMOVE;
313 #endif
314         case MONO_TYPE_R4:
315                 return cfg->r4fp ? OP_RMOVE : OP_FMOVE;
316         case MONO_TYPE_R8:
317                 return OP_FMOVE;
318         case MONO_TYPE_VALUETYPE:
319                 if (type->data.klass->enumtype) {
320                         type = mono_class_enum_basetype (type->data.klass);
321                         goto handle_enum;
322                 }
323                 if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
324                         return OP_XMOVE;
325                 return OP_VMOVE;
326         case MONO_TYPE_TYPEDBYREF:
327                 return OP_VMOVE;
328         case MONO_TYPE_GENERICINST:
329                 type = &type->data.generic_class->container_class->byval_arg;
330                 goto handle_enum;
331         case MONO_TYPE_VAR:
332         case MONO_TYPE_MVAR:
333                 g_assert (cfg->gshared);
334                 if (mini_type_var_is_vt (type))
335                         return OP_VMOVE;
336                 else
337                         return mono_type_to_regmove (cfg, mini_get_underlying_type (type));
338         default:
339                 g_error ("unknown type 0x%02x in type_to_regstore", type->type);
340         }
341         return -1;
342 }
343
344 void
345 mono_print_bb (MonoBasicBlock *bb, const char *msg)
346 {
347         int i;
348         MonoInst *tree;
349
350         printf ("\n%s %d: [IN: ", msg, bb->block_num);
351         for (i = 0; i < bb->in_count; ++i)
352                 printf (" BB%d(%d)", bb->in_bb [i]->block_num, bb->in_bb [i]->dfn);
353         printf (", OUT: ");
354         for (i = 0; i < bb->out_count; ++i)
355                 printf (" BB%d(%d)", bb->out_bb [i]->block_num, bb->out_bb [i]->dfn);
356         printf (" ]\n");
357         for (tree = bb->code; tree; tree = tree->next)
358                 mono_print_ins_index (-1, tree);
359 }
360
361 void
362 mono_create_helper_signatures (void)
363 {
364         helper_sig_domain_get = mono_create_icall_signature ("ptr");
365         helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
366         helper_sig_llvmonly_imt_trampoline = mono_create_icall_signature ("ptr ptr ptr");
367 }
368
369 static MONO_NEVER_INLINE void
370 break_on_unverified (void)
371 {
372         if (mini_get_debug_options ()->break_on_unverified)
373                 G_BREAKPOINT ();
374 }
375
376 static MONO_NEVER_INLINE void
377 field_access_failure (MonoCompile *cfg, MonoMethod *method, MonoClassField *field)
378 {
379         char *method_fname = mono_method_full_name (method, TRUE);
380         char *field_fname = mono_field_full_name (field);
381         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
382         mono_error_set_generic_error (&cfg->error, "System", "FieldAccessException", "Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname);
383         g_free (method_fname);
384         g_free (field_fname);
385 }
386
387 static MONO_NEVER_INLINE void
388 inline_failure (MonoCompile *cfg, const char *msg)
389 {
390         if (cfg->verbose_level >= 2)
391                 printf ("inline failed: %s\n", msg);
392         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INLINE_FAILED);
393 }
394
395 static MONO_NEVER_INLINE void
396 gshared_failure (MonoCompile *cfg, int opcode, const char *file, int line)
397 {
398         if (cfg->verbose_level > 2)                                                                                     \
399                 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);
400         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
401 }
402
403 static MONO_NEVER_INLINE void
404 gsharedvt_failure (MonoCompile *cfg, int opcode, const char *file, int line)
405 {
406         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);
407         if (cfg->verbose_level >= 2)
408                 printf ("%s\n", cfg->exception_message);
409         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
410 }
411
412 /*
413  * When using gsharedvt, some instatiations might be verifiable, and some might be not. i.e. 
414  * foo<T> (int i) { ldarg.0; box T; }
415  */
416 #define UNVERIFIED do { \
417         if (cfg->gsharedvt) { \
418                 if (cfg->verbose_level > 2)                                                                     \
419                         printf ("gsharedvt method failed to verify, falling back to instantiation.\n"); \
420                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED); \
421                 goto exception_exit;                                                                                    \
422         }                                                                                                                                       \
423         break_on_unverified ();                                                                                         \
424         goto unverified;                                                                                                        \
425 } while (0)
426
427 #define GET_BBLOCK(cfg,tblock,ip) do {  \
428                 (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
429                 if (!(tblock)) {        \
430                         if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
431             NEW_BBLOCK (cfg, (tblock)); \
432                         (tblock)->cil_code = (ip);      \
433                         ADD_BBLOCK (cfg, (tblock));     \
434                 } \
435         } while (0)
436
437 #if defined(TARGET_X86) || defined(TARGET_AMD64)
438 #define EMIT_NEW_X86_LEA(cfg,dest,sr1,sr2,shift,imm) do { \
439                 MONO_INST_NEW (cfg, dest, OP_X86_LEA); \
440                 (dest)->dreg = alloc_ireg_mp ((cfg)); \
441                 (dest)->sreg1 = (sr1); \
442                 (dest)->sreg2 = (sr2); \
443                 (dest)->inst_imm = (imm); \
444                 (dest)->backend.shift_amount = (shift); \
445                 MONO_ADD_INS ((cfg)->cbb, (dest)); \
446         } while (0)
447 #endif
448
449 /* Emit conversions so both operands of a binary opcode are of the same type */
450 static void
451 add_widen_op (MonoCompile *cfg, MonoInst *ins, MonoInst **arg1_ref, MonoInst **arg2_ref)
452 {
453         MonoInst *arg1 = *arg1_ref;
454         MonoInst *arg2 = *arg2_ref;
455
456         if (cfg->r4fp &&
457                 ((arg1->type == STACK_R4 && arg2->type == STACK_R8) ||
458                  (arg1->type == STACK_R8 && arg2->type == STACK_R4))) {
459                 MonoInst *conv;
460
461                 /* Mixing r4/r8 is allowed by the spec */
462                 if (arg1->type == STACK_R4) {
463                         int dreg = alloc_freg (cfg);
464
465                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg1->dreg);
466                         conv->type = STACK_R8;
467                         ins->sreg1 = dreg;
468                         *arg1_ref = conv;
469                 }
470                 if (arg2->type == STACK_R4) {
471                         int dreg = alloc_freg (cfg);
472
473                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg2->dreg);
474                         conv->type = STACK_R8;
475                         ins->sreg2 = dreg;
476                         *arg2_ref = conv;
477                 }
478         }
479
480 #if SIZEOF_REGISTER == 8
481         /* FIXME: Need to add many more cases */
482         if ((arg1)->type == STACK_PTR && (arg2)->type == STACK_I4) {
483                 MonoInst *widen;
484
485                 int dr = alloc_preg (cfg);
486                 EMIT_NEW_UNALU (cfg, widen, OP_SEXT_I4, dr, (arg2)->dreg);
487                 (ins)->sreg2 = widen->dreg;
488         }
489 #endif
490 }
491
492 #define ADD_BINOP(op) do {      \
493                 MONO_INST_NEW (cfg, ins, (op)); \
494                 sp -= 2;        \
495                 ins->sreg1 = sp [0]->dreg;      \
496                 ins->sreg2 = sp [1]->dreg;      \
497                 type_from_op (cfg, ins, sp [0], sp [1]);        \
498                 CHECK_TYPE (ins);       \
499                 /* Have to insert a widening op */               \
500         add_widen_op (cfg, ins, &sp [0], &sp [1]);               \
501         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type); \
502         MONO_ADD_INS ((cfg)->cbb, (ins)); \
503         *sp++ = mono_decompose_opcode ((cfg), (ins));   \
504         } while (0)
505
506 #define ADD_UNOP(op) do {       \
507                 MONO_INST_NEW (cfg, ins, (op)); \
508                 sp--;   \
509                 ins->sreg1 = sp [0]->dreg;      \
510                 type_from_op (cfg, ins, sp [0], NULL);  \
511                 CHECK_TYPE (ins);       \
512         (ins)->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type); \
513         MONO_ADD_INS ((cfg)->cbb, (ins)); \
514                 *sp++ = mono_decompose_opcode (cfg, ins);       \
515         } while (0)
516
517 #define ADD_BINCOND(next_block) do {    \
518                 MonoInst *cmp;  \
519                 sp -= 2; \
520                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
521                 cmp->sreg1 = sp [0]->dreg;      \
522                 cmp->sreg2 = sp [1]->dreg;      \
523                 type_from_op (cfg, cmp, sp [0], sp [1]);        \
524                 CHECK_TYPE (cmp);       \
525                 add_widen_op (cfg, cmp, &sp [0], &sp [1]);                                              \
526                 type_from_op (cfg, ins, sp [0], sp [1]);                                                        \
527                 ins->inst_many_bb = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);   \
528                 GET_BBLOCK (cfg, tblock, target);               \
529                 link_bblock (cfg, cfg->cbb, tblock);    \
530                 ins->inst_true_bb = tblock;     \
531                 if ((next_block)) {     \
532                         link_bblock (cfg, cfg->cbb, (next_block));      \
533                         ins->inst_false_bb = (next_block);      \
534                         start_new_bblock = 1;   \
535                 } else {        \
536                         GET_BBLOCK (cfg, tblock, ip);           \
537                         link_bblock (cfg, cfg->cbb, tblock);    \
538                         ins->inst_false_bb = tblock;    \
539                         start_new_bblock = 2;   \
540                 }       \
541                 if (sp != stack_start) {                                                                        \
542                     handle_stack_args (cfg, stack_start, sp - stack_start); \
543                         CHECK_UNVERIFIABLE (cfg); \
544                 } \
545         MONO_ADD_INS (cfg->cbb, cmp); \
546                 MONO_ADD_INS (cfg->cbb, ins);   \
547         } while (0)
548
549 /* *
550  * link_bblock: Links two basic blocks
551  *
552  * links two basic blocks in the control flow graph, the 'from'
553  * argument is the starting block and the 'to' argument is the block
554  * the control flow ends to after 'from'.
555  */
556 static void
557 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
558 {
559         MonoBasicBlock **newa;
560         int i, found;
561
562 #if 0
563         if (from->cil_code) {
564                 if (to->cil_code)
565                         printf ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
566                 else
567                         printf ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
568         } else {
569                 if (to->cil_code)
570                         printf ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
571                 else
572                         printf ("edge from entry to exit\n");
573         }
574 #endif
575
576         found = FALSE;
577         for (i = 0; i < from->out_count; ++i) {
578                 if (to == from->out_bb [i]) {
579                         found = TRUE;
580                         break;
581                 }
582         }
583         if (!found) {
584                 newa = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
585                 for (i = 0; i < from->out_count; ++i) {
586                         newa [i] = from->out_bb [i];
587                 }
588                 newa [i] = to;
589                 from->out_count++;
590                 from->out_bb = newa;
591         }
592
593         found = FALSE;
594         for (i = 0; i < to->in_count; ++i) {
595                 if (from == to->in_bb [i]) {
596                         found = TRUE;
597                         break;
598                 }
599         }
600         if (!found) {
601                 newa = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
602                 for (i = 0; i < to->in_count; ++i) {
603                         newa [i] = to->in_bb [i];
604                 }
605                 newa [i] = from;
606                 to->in_count++;
607                 to->in_bb = newa;
608         }
609 }
610
611 void
612 mono_link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
613 {
614         link_bblock (cfg, from, to);
615 }
616
617 /**
618  * mono_find_block_region:
619  *
620  *   We mark each basic block with a region ID. We use that to avoid BB
621  *   optimizations when blocks are in different regions.
622  *
623  * Returns:
624  *   A region token that encodes where this region is, and information
625  *   about the clause owner for this block.
626  *
627  *   The region encodes the try/catch/filter clause that owns this block
628  *   as well as the type.  -1 is a special value that represents a block
629  *   that is in none of try/catch/filter.
630  */
631 static int
632 mono_find_block_region (MonoCompile *cfg, int offset)
633 {
634         MonoMethodHeader *header = cfg->header;
635         MonoExceptionClause *clause;
636         int i;
637
638         for (i = 0; i < header->num_clauses; ++i) {
639                 clause = &header->clauses [i];
640                 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
641                     (offset < (clause->handler_offset)))
642                         return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
643                            
644                 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
645                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
646                                 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
647                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
648                                 return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
649                         else
650                                 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
651                 }
652         }
653         for (i = 0; i < header->num_clauses; ++i) {
654                 clause = &header->clauses [i];
655
656                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
657                         return ((i + 1) << 8) | clause->flags;
658         }
659
660         return -1;
661 }
662
663 static gboolean
664 ip_in_finally_clause (MonoCompile *cfg, int offset)
665 {
666         MonoMethodHeader *header = cfg->header;
667         MonoExceptionClause *clause;
668         int i;
669
670         for (i = 0; i < header->num_clauses; ++i) {
671                 clause = &header->clauses [i];
672                 if (clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FAULT)
673                         continue;
674
675                 if (MONO_OFFSET_IN_HANDLER (clause, offset))
676                         return TRUE;
677         }
678         return FALSE;
679 }
680
681 static GList*
682 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
683 {
684         MonoMethodHeader *header = cfg->header;
685         MonoExceptionClause *clause;
686         int i;
687         GList *res = NULL;
688
689         for (i = 0; i < header->num_clauses; ++i) {
690                 clause = &header->clauses [i];
691                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
692                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
693                         if (clause->flags == type)
694                                 res = g_list_append (res, clause);
695                 }
696         }
697         return res;
698 }
699
700 static void
701 mono_create_spvar_for_region (MonoCompile *cfg, int region)
702 {
703         MonoInst *var;
704
705         var = (MonoInst *)g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
706         if (var)
707                 return;
708
709         var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
710         /* prevent it from being register allocated */
711         var->flags |= MONO_INST_VOLATILE;
712
713         g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
714 }
715
716 MonoInst *
717 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
718 {
719         return (MonoInst *)g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
720 }
721
722 static MonoInst*
723 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
724 {
725         MonoInst *var;
726
727         var = (MonoInst *)g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
728         if (var)
729                 return var;
730
731         var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
732         /* prevent it from being register allocated */
733         var->flags |= MONO_INST_VOLATILE;
734
735         g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
736
737         return var;
738 }
739
740 /*
741  * Returns the type used in the eval stack when @type is loaded.
742  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
743  */
744 void
745 type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
746 {
747         MonoClass *klass;
748
749         type = mini_get_underlying_type (type);
750         inst->klass = klass = mono_class_from_mono_type (type);
751         if (type->byref) {
752                 inst->type = STACK_MP;
753                 return;
754         }
755
756 handle_enum:
757         switch (type->type) {
758         case MONO_TYPE_VOID:
759                 inst->type = STACK_INV;
760                 return;
761         case MONO_TYPE_I1:
762         case MONO_TYPE_U1:
763         case MONO_TYPE_I2:
764         case MONO_TYPE_U2:
765         case MONO_TYPE_I4:
766         case MONO_TYPE_U4:
767                 inst->type = STACK_I4;
768                 return;
769         case MONO_TYPE_I:
770         case MONO_TYPE_U:
771         case MONO_TYPE_PTR:
772         case MONO_TYPE_FNPTR:
773                 inst->type = STACK_PTR;
774                 return;
775         case MONO_TYPE_CLASS:
776         case MONO_TYPE_STRING:
777         case MONO_TYPE_OBJECT:
778         case MONO_TYPE_SZARRAY:
779         case MONO_TYPE_ARRAY:    
780                 inst->type = STACK_OBJ;
781                 return;
782         case MONO_TYPE_I8:
783         case MONO_TYPE_U8:
784                 inst->type = STACK_I8;
785                 return;
786         case MONO_TYPE_R4:
787                 inst->type = cfg->r4_stack_type;
788                 break;
789         case MONO_TYPE_R8:
790                 inst->type = STACK_R8;
791                 return;
792         case MONO_TYPE_VALUETYPE:
793                 if (type->data.klass->enumtype) {
794                         type = mono_class_enum_basetype (type->data.klass);
795                         goto handle_enum;
796                 } else {
797                         inst->klass = klass;
798                         inst->type = STACK_VTYPE;
799                         return;
800                 }
801         case MONO_TYPE_TYPEDBYREF:
802                 inst->klass = mono_defaults.typed_reference_class;
803                 inst->type = STACK_VTYPE;
804                 return;
805         case MONO_TYPE_GENERICINST:
806                 type = &type->data.generic_class->container_class->byval_arg;
807                 goto handle_enum;
808         case MONO_TYPE_VAR:
809         case MONO_TYPE_MVAR:
810                 g_assert (cfg->gshared);
811                 if (mini_is_gsharedvt_type (type)) {
812                         g_assert (cfg->gsharedvt);
813                         inst->type = STACK_VTYPE;
814                 } else {
815                         type_to_eval_stack_type (cfg, mini_get_underlying_type (type), inst);
816                 }
817                 return;
818         default:
819                 g_error ("unknown type 0x%02x in eval stack type", type->type);
820         }
821 }
822
823 /*
824  * The following tables are used to quickly validate the IL code in type_from_op ().
825  */
826 static const char
827 bin_num_table [STACK_MAX] [STACK_MAX] = {
828         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
829         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
830         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
831         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
832         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV, STACK_R8},
833         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
834         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
835         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
836         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4}
837 };
838
839 static const char 
840 neg_table [] = {
841         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4
842 };
843
844 /* reduce the size of this table */
845 static const char
846 bin_int_table [STACK_MAX] [STACK_MAX] = {
847         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
848         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
849         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
850         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
851         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
852         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
853         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
854         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
855 };
856
857 static const char
858 bin_comp_table [STACK_MAX] [STACK_MAX] = {
859 /*      Inv i  L  p  F  &  O  vt r4 */
860         {0},
861         {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
862         {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
863         {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
864         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* F, R8 */
865         {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
866         {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
867         {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
868         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* r, r4 */
869 };
870
871 /* reduce the size of this table */
872 static const char
873 shift_table [STACK_MAX] [STACK_MAX] = {
874         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
875         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
876         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
877         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
878         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
879         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
880         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
881         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
882 };
883
884 /*
885  * Tables to map from the non-specific opcode to the matching
886  * type-specific opcode.
887  */
888 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
889 static const guint16
890 binops_op_map [STACK_MAX] = {
891         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
892 };
893
894 /* handles from CEE_NEG to CEE_CONV_U8 */
895 static const guint16
896 unops_op_map [STACK_MAX] = {
897         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
898 };
899
900 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
901 static const guint16
902 ovfops_op_map [STACK_MAX] = {
903         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
904 };
905
906 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
907 static const guint16
908 ovf2ops_op_map [STACK_MAX] = {
909         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
910 };
911
912 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
913 static const guint16
914 ovf3ops_op_map [STACK_MAX] = {
915         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
916 };
917
918 /* handles from CEE_BEQ to CEE_BLT_UN */
919 static const guint16
920 beqops_op_map [STACK_MAX] = {
921         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
922 };
923
924 /* handles from CEE_CEQ to CEE_CLT_UN */
925 static const guint16
926 ceqops_op_map [STACK_MAX] = {
927         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
928 };
929
930 /*
931  * Sets ins->type (the type on the eval stack) according to the
932  * type of the opcode and the arguments to it.
933  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
934  *
935  * FIXME: this function sets ins->type unconditionally in some cases, but
936  * it should set it to invalid for some types (a conv.x on an object)
937  */
938 static void
939 type_from_op (MonoCompile *cfg, MonoInst *ins, MonoInst *src1, MonoInst *src2)
940 {
941         switch (ins->opcode) {
942         /* binops */
943         case CEE_ADD:
944         case CEE_SUB:
945         case CEE_MUL:
946         case CEE_DIV:
947         case CEE_REM:
948                 /* FIXME: check unverifiable args for STACK_MP */
949                 ins->type = bin_num_table [src1->type] [src2->type];
950                 ins->opcode += binops_op_map [ins->type];
951                 break;
952         case CEE_DIV_UN:
953         case CEE_REM_UN:
954         case CEE_AND:
955         case CEE_OR:
956         case CEE_XOR:
957                 ins->type = bin_int_table [src1->type] [src2->type];
958                 ins->opcode += binops_op_map [ins->type];
959                 break;
960         case CEE_SHL:
961         case CEE_SHR:
962         case CEE_SHR_UN:
963                 ins->type = shift_table [src1->type] [src2->type];
964                 ins->opcode += binops_op_map [ins->type];
965                 break;
966         case OP_COMPARE:
967         case OP_LCOMPARE:
968         case OP_ICOMPARE:
969                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
970                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
971                         ins->opcode = OP_LCOMPARE;
972                 else if (src1->type == STACK_R4)
973                         ins->opcode = OP_RCOMPARE;
974                 else if (src1->type == STACK_R8)
975                         ins->opcode = OP_FCOMPARE;
976                 else
977                         ins->opcode = OP_ICOMPARE;
978                 break;
979         case OP_ICOMPARE_IMM:
980                 ins->type = bin_comp_table [src1->type] [src1->type] ? STACK_I4 : STACK_INV;
981                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
982                         ins->opcode = OP_LCOMPARE_IMM;          
983                 break;
984         case CEE_BEQ:
985         case CEE_BGE:
986         case CEE_BGT:
987         case CEE_BLE:
988         case CEE_BLT:
989         case CEE_BNE_UN:
990         case CEE_BGE_UN:
991         case CEE_BGT_UN:
992         case CEE_BLE_UN:
993         case CEE_BLT_UN:
994                 ins->opcode += beqops_op_map [src1->type];
995                 break;
996         case OP_CEQ:
997                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
998                 ins->opcode += ceqops_op_map [src1->type];
999                 break;
1000         case OP_CGT:
1001         case OP_CGT_UN:
1002         case OP_CLT:
1003         case OP_CLT_UN:
1004                 ins->type = (bin_comp_table [src1->type] [src2->type] & 1) ? STACK_I4: STACK_INV;
1005                 ins->opcode += ceqops_op_map [src1->type];
1006                 break;
1007         /* unops */
1008         case CEE_NEG:
1009                 ins->type = neg_table [src1->type];
1010                 ins->opcode += unops_op_map [ins->type];
1011                 break;
1012         case CEE_NOT:
1013                 if (src1->type >= STACK_I4 && src1->type <= STACK_PTR)
1014                         ins->type = src1->type;
1015                 else
1016                         ins->type = STACK_INV;
1017                 ins->opcode += unops_op_map [ins->type];
1018                 break;
1019         case CEE_CONV_I1:
1020         case CEE_CONV_I2:
1021         case CEE_CONV_I4:
1022         case CEE_CONV_U4:
1023                 ins->type = STACK_I4;
1024                 ins->opcode += unops_op_map [src1->type];
1025                 break;
1026         case CEE_CONV_R_UN:
1027                 ins->type = STACK_R8;
1028                 switch (src1->type) {
1029                 case STACK_I4:
1030                 case STACK_PTR:
1031                         ins->opcode = OP_ICONV_TO_R_UN;
1032                         break;
1033                 case STACK_I8:
1034                         ins->opcode = OP_LCONV_TO_R_UN; 
1035                         break;
1036                 }
1037                 break;
1038         case CEE_CONV_OVF_I1:
1039         case CEE_CONV_OVF_U1:
1040         case CEE_CONV_OVF_I2:
1041         case CEE_CONV_OVF_U2:
1042         case CEE_CONV_OVF_I4:
1043         case CEE_CONV_OVF_U4:
1044                 ins->type = STACK_I4;
1045                 ins->opcode += ovf3ops_op_map [src1->type];
1046                 break;
1047         case CEE_CONV_OVF_I_UN:
1048         case CEE_CONV_OVF_U_UN:
1049                 ins->type = STACK_PTR;
1050                 ins->opcode += ovf2ops_op_map [src1->type];
1051                 break;
1052         case CEE_CONV_OVF_I1_UN:
1053         case CEE_CONV_OVF_I2_UN:
1054         case CEE_CONV_OVF_I4_UN:
1055         case CEE_CONV_OVF_U1_UN:
1056         case CEE_CONV_OVF_U2_UN:
1057         case CEE_CONV_OVF_U4_UN:
1058                 ins->type = STACK_I4;
1059                 ins->opcode += ovf2ops_op_map [src1->type];
1060                 break;
1061         case CEE_CONV_U:
1062                 ins->type = STACK_PTR;
1063                 switch (src1->type) {
1064                 case STACK_I4:
1065                         ins->opcode = OP_ICONV_TO_U;
1066                         break;
1067                 case STACK_PTR:
1068                 case STACK_MP:
1069 #if SIZEOF_VOID_P == 8
1070                         ins->opcode = OP_LCONV_TO_U;
1071 #else
1072                         ins->opcode = OP_MOVE;
1073 #endif
1074                         break;
1075                 case STACK_I8:
1076                         ins->opcode = OP_LCONV_TO_U;
1077                         break;
1078                 case STACK_R8:
1079                         ins->opcode = OP_FCONV_TO_U;
1080                         break;
1081                 }
1082                 break;
1083         case CEE_CONV_I8:
1084         case CEE_CONV_U8:
1085                 ins->type = STACK_I8;
1086                 ins->opcode += unops_op_map [src1->type];
1087                 break;
1088         case CEE_CONV_OVF_I8:
1089         case CEE_CONV_OVF_U8:
1090                 ins->type = STACK_I8;
1091                 ins->opcode += ovf3ops_op_map [src1->type];
1092                 break;
1093         case CEE_CONV_OVF_U8_UN:
1094         case CEE_CONV_OVF_I8_UN:
1095                 ins->type = STACK_I8;
1096                 ins->opcode += ovf2ops_op_map [src1->type];
1097                 break;
1098         case CEE_CONV_R4:
1099                 ins->type = cfg->r4_stack_type;
1100                 ins->opcode += unops_op_map [src1->type];
1101                 break;
1102         case CEE_CONV_R8:
1103                 ins->type = STACK_R8;
1104                 ins->opcode += unops_op_map [src1->type];
1105                 break;
1106         case OP_CKFINITE:
1107                 ins->type = STACK_R8;           
1108                 break;
1109         case CEE_CONV_U2:
1110         case CEE_CONV_U1:
1111                 ins->type = STACK_I4;
1112                 ins->opcode += ovfops_op_map [src1->type];
1113                 break;
1114         case CEE_CONV_I:
1115         case CEE_CONV_OVF_I:
1116         case CEE_CONV_OVF_U:
1117                 ins->type = STACK_PTR;
1118                 ins->opcode += ovfops_op_map [src1->type];
1119                 break;
1120         case CEE_ADD_OVF:
1121         case CEE_ADD_OVF_UN:
1122         case CEE_MUL_OVF:
1123         case CEE_MUL_OVF_UN:
1124         case CEE_SUB_OVF:
1125         case CEE_SUB_OVF_UN:
1126                 ins->type = bin_num_table [src1->type] [src2->type];
1127                 ins->opcode += ovfops_op_map [src1->type];
1128                 if (ins->type == STACK_R8)
1129                         ins->type = STACK_INV;
1130                 break;
1131         case OP_LOAD_MEMBASE:
1132                 ins->type = STACK_PTR;
1133                 break;
1134         case OP_LOADI1_MEMBASE:
1135         case OP_LOADU1_MEMBASE:
1136         case OP_LOADI2_MEMBASE:
1137         case OP_LOADU2_MEMBASE:
1138         case OP_LOADI4_MEMBASE:
1139         case OP_LOADU4_MEMBASE:
1140                 ins->type = STACK_PTR;
1141                 break;
1142         case OP_LOADI8_MEMBASE:
1143                 ins->type = STACK_I8;
1144                 break;
1145         case OP_LOADR4_MEMBASE:
1146                 ins->type = cfg->r4_stack_type;
1147                 break;
1148         case OP_LOADR8_MEMBASE:
1149                 ins->type = STACK_R8;
1150                 break;
1151         default:
1152                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1153                 break;
1154         }
1155
1156         if (ins->type == STACK_MP)
1157                 ins->klass = mono_defaults.object_class;
1158 }
1159
1160 static const char 
1161 ldind_type [] = {
1162         STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
1163 };
1164
1165 #if 0
1166
1167 static const char
1168 param_table [STACK_MAX] [STACK_MAX] = {
1169         {0},
1170 };
1171
1172 static int
1173 check_values_to_signature (MonoInst *args, MonoType *this_ins, MonoMethodSignature *sig)
1174 {
1175         int i;
1176
1177         if (sig->hasthis) {
1178                 switch (args->type) {
1179                 case STACK_I4:
1180                 case STACK_I8:
1181                 case STACK_R8:
1182                 case STACK_VTYPE:
1183                 case STACK_INV:
1184                         return 0;
1185                 }
1186                 args++;
1187         }
1188         for (i = 0; i < sig->param_count; ++i) {
1189                 switch (args [i].type) {
1190                 case STACK_INV:
1191                         return 0;
1192                 case STACK_MP:
1193                         if (!sig->params [i]->byref)
1194                                 return 0;
1195                         continue;
1196                 case STACK_OBJ:
1197                         if (sig->params [i]->byref)
1198                                 return 0;
1199                         switch (sig->params [i]->type) {
1200                         case MONO_TYPE_CLASS:
1201                         case MONO_TYPE_STRING:
1202                         case MONO_TYPE_OBJECT:
1203                         case MONO_TYPE_SZARRAY:
1204                         case MONO_TYPE_ARRAY:
1205                                 break;
1206                         default:
1207                                 return 0;
1208                         }
1209                         continue;
1210                 case STACK_R8:
1211                         if (sig->params [i]->byref)
1212                                 return 0;
1213                         if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1214                                 return 0;
1215                         continue;
1216                 case STACK_PTR:
1217                 case STACK_I4:
1218                 case STACK_I8:
1219                 case STACK_VTYPE:
1220                         break;
1221                 }
1222                 /*if (!param_table [args [i].type] [sig->params [i]->type])
1223                         return 0;*/
1224         }
1225         return 1;
1226 }
1227 #endif
1228
1229 /*
1230  * When we need a pointer to the current domain many times in a method, we
1231  * call mono_domain_get() once and we store the result in a local variable.
1232  * This function returns the variable that represents the MonoDomain*.
1233  */
1234 inline static MonoInst *
1235 mono_get_domainvar (MonoCompile *cfg)
1236 {
1237         if (!cfg->domainvar)
1238                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1239         return cfg->domainvar;
1240 }
1241
1242 /*
1243  * The got_var contains the address of the Global Offset Table when AOT 
1244  * compiling.
1245  */
1246 MonoInst *
1247 mono_get_got_var (MonoCompile *cfg)
1248 {
1249         if (!cfg->compile_aot || !cfg->backend->need_got_var)
1250                 return NULL;
1251         if (!cfg->got_var) {
1252                 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1253         }
1254         return cfg->got_var;
1255 }
1256
1257 static MonoInst *
1258 mono_get_vtable_var (MonoCompile *cfg)
1259 {
1260         g_assert (cfg->gshared);
1261
1262         if (!cfg->rgctx_var) {
1263                 cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1264                 /* force the var to be stack allocated */
1265                 cfg->rgctx_var->flags |= MONO_INST_VOLATILE;
1266         }
1267
1268         return cfg->rgctx_var;
1269 }
1270
1271 static MonoType*
1272 type_from_stack_type (MonoInst *ins) {
1273         switch (ins->type) {
1274         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1275         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1276         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1277         case STACK_R4: return &mono_defaults.single_class->byval_arg;
1278         case STACK_R8: return &mono_defaults.double_class->byval_arg;
1279         case STACK_MP:
1280                 return &ins->klass->this_arg;
1281         case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1282         case STACK_VTYPE: return &ins->klass->byval_arg;
1283         default:
1284                 g_error ("stack type %d to monotype not handled\n", ins->type);
1285         }
1286         return NULL;
1287 }
1288
1289 static G_GNUC_UNUSED int
1290 type_to_stack_type (MonoCompile *cfg, MonoType *t)
1291 {
1292         t = mono_type_get_underlying_type (t);
1293         switch (t->type) {
1294         case MONO_TYPE_I1:
1295         case MONO_TYPE_U1:
1296         case MONO_TYPE_I2:
1297         case MONO_TYPE_U2:
1298         case MONO_TYPE_I4:
1299         case MONO_TYPE_U4:
1300                 return STACK_I4;
1301         case MONO_TYPE_I:
1302         case MONO_TYPE_U:
1303         case MONO_TYPE_PTR:
1304         case MONO_TYPE_FNPTR:
1305                 return STACK_PTR;
1306         case MONO_TYPE_CLASS:
1307         case MONO_TYPE_STRING:
1308         case MONO_TYPE_OBJECT:
1309         case MONO_TYPE_SZARRAY:
1310         case MONO_TYPE_ARRAY:    
1311                 return STACK_OBJ;
1312         case MONO_TYPE_I8:
1313         case MONO_TYPE_U8:
1314                 return STACK_I8;
1315         case MONO_TYPE_R4:
1316                 return cfg->r4_stack_type;
1317         case MONO_TYPE_R8:
1318                 return STACK_R8;
1319         case MONO_TYPE_VALUETYPE:
1320         case MONO_TYPE_TYPEDBYREF:
1321                 return STACK_VTYPE;
1322         case MONO_TYPE_GENERICINST:
1323                 if (mono_type_generic_inst_is_valuetype (t))
1324                         return STACK_VTYPE;
1325                 else
1326                         return STACK_OBJ;
1327                 break;
1328         default:
1329                 g_assert_not_reached ();
1330         }
1331
1332         return -1;
1333 }
1334
1335 static MonoClass*
1336 array_access_to_klass (int opcode)
1337 {
1338         switch (opcode) {
1339         case CEE_LDELEM_U1:
1340                 return mono_defaults.byte_class;
1341         case CEE_LDELEM_U2:
1342                 return mono_defaults.uint16_class;
1343         case CEE_LDELEM_I:
1344         case CEE_STELEM_I:
1345                 return mono_defaults.int_class;
1346         case CEE_LDELEM_I1:
1347         case CEE_STELEM_I1:
1348                 return mono_defaults.sbyte_class;
1349         case CEE_LDELEM_I2:
1350         case CEE_STELEM_I2:
1351                 return mono_defaults.int16_class;
1352         case CEE_LDELEM_I4:
1353         case CEE_STELEM_I4:
1354                 return mono_defaults.int32_class;
1355         case CEE_LDELEM_U4:
1356                 return mono_defaults.uint32_class;
1357         case CEE_LDELEM_I8:
1358         case CEE_STELEM_I8:
1359                 return mono_defaults.int64_class;
1360         case CEE_LDELEM_R4:
1361         case CEE_STELEM_R4:
1362                 return mono_defaults.single_class;
1363         case CEE_LDELEM_R8:
1364         case CEE_STELEM_R8:
1365                 return mono_defaults.double_class;
1366         case CEE_LDELEM_REF:
1367         case CEE_STELEM_REF:
1368                 return mono_defaults.object_class;
1369         default:
1370                 g_assert_not_reached ();
1371         }
1372         return NULL;
1373 }
1374
1375 /*
1376  * We try to share variables when possible
1377  */
1378 static MonoInst *
1379 mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
1380 {
1381         MonoInst *res;
1382         int pos, vnum;
1383
1384         /* inlining can result in deeper stacks */ 
1385         if (slot >= cfg->header->max_stack)
1386                 return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1387
1388         pos = ins->type - 1 + slot * STACK_MAX;
1389
1390         switch (ins->type) {
1391         case STACK_I4:
1392         case STACK_I8:
1393         case STACK_R8:
1394         case STACK_PTR:
1395         case STACK_MP:
1396         case STACK_OBJ:
1397                 if ((vnum = cfg->intvars [pos]))
1398                         return cfg->varinfo [vnum];
1399                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1400                 cfg->intvars [pos] = res->inst_c0;
1401                 break;
1402         default:
1403                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1404         }
1405         return res;
1406 }
1407
1408 static void
1409 mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
1410 {
1411         /* 
1412          * Don't use this if a generic_context is set, since that means AOT can't
1413          * look up the method using just the image+token.
1414          * table == 0 means this is a reference made from a wrapper.
1415          */
1416         if (cfg->compile_aot && !cfg->generic_context && (mono_metadata_token_table (token) > 0)) {
1417                 MonoJumpInfoToken *jump_info_token = (MonoJumpInfoToken *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
1418                 jump_info_token->image = image;
1419                 jump_info_token->token = token;
1420                 g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
1421         }
1422 }
1423
1424 /*
1425  * This function is called to handle items that are left on the evaluation stack
1426  * at basic block boundaries. What happens is that we save the values to local variables
1427  * and we reload them later when first entering the target basic block (with the
1428  * handle_loaded_temps () function).
1429  * A single joint point will use the same variables (stored in the array bb->out_stack or
1430  * bb->in_stack, if the basic block is before or after the joint point).
1431  *
1432  * This function needs to be called _before_ emitting the last instruction of
1433  * the bb (i.e. before emitting a branch).
1434  * If the stack merge fails at a join point, cfg->unverifiable is set.
1435  */
1436 static void
1437 handle_stack_args (MonoCompile *cfg, MonoInst **sp, int count)
1438 {
1439         int i, bindex;
1440         MonoBasicBlock *bb = cfg->cbb;
1441         MonoBasicBlock *outb;
1442         MonoInst *inst, **locals;
1443         gboolean found;
1444
1445         if (!count)
1446                 return;
1447         if (cfg->verbose_level > 3)
1448                 printf ("%d item(s) on exit from B%d\n", count, bb->block_num);
1449         if (!bb->out_scount) {
1450                 bb->out_scount = count;
1451                 //printf ("bblock %d has out:", bb->block_num);
1452                 found = FALSE;
1453                 for (i = 0; i < bb->out_count; ++i) {
1454                         outb = bb->out_bb [i];
1455                         /* exception handlers are linked, but they should not be considered for stack args */
1456                         if (outb->flags & BB_EXCEPTION_HANDLER)
1457                                 continue;
1458                         //printf (" %d", outb->block_num);
1459                         if (outb->in_stack) {
1460                                 found = TRUE;
1461                                 bb->out_stack = outb->in_stack;
1462                                 break;
1463                         }
1464                 }
1465                 //printf ("\n");
1466                 if (!found) {
1467                         bb->out_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1468                         for (i = 0; i < count; ++i) {
1469                                 /* 
1470                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
1471                                  * stack slot and if they are of the same type.
1472                                  * This won't cause conflicts since if 'local' is used to 
1473                                  * store one of the values in the in_stack of a bblock, then
1474                                  * the same variable will be used for the same outgoing stack 
1475                                  * slot as well. 
1476                                  * This doesn't work when inlining methods, since the bblocks
1477                                  * in the inlined methods do not inherit their in_stack from
1478                                  * the bblock they are inlined to. See bug #58863 for an
1479                                  * example.
1480                                  */
1481                                 if (cfg->inlined_method)
1482                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1483                                 else
1484                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
1485                         }
1486                 }
1487         }
1488
1489         for (i = 0; i < bb->out_count; ++i) {
1490                 outb = bb->out_bb [i];
1491                 /* exception handlers are linked, but they should not be considered for stack args */
1492                 if (outb->flags & BB_EXCEPTION_HANDLER)
1493                         continue;
1494                 if (outb->in_scount) {
1495                         if (outb->in_scount != bb->out_scount) {
1496                                 cfg->unverifiable = TRUE;
1497                                 return;
1498                         }
1499                         continue; /* check they are the same locals */
1500                 }
1501                 outb->in_scount = count;
1502                 outb->in_stack = bb->out_stack;
1503         }
1504
1505         locals = bb->out_stack;
1506         cfg->cbb = bb;
1507         for (i = 0; i < count; ++i) {
1508                 EMIT_NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
1509                 inst->cil_code = sp [i]->cil_code;
1510                 sp [i] = locals [i];
1511                 if (cfg->verbose_level > 3)
1512                         printf ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
1513         }
1514
1515         /*
1516          * It is possible that the out bblocks already have in_stack assigned, and
1517          * the in_stacks differ. In this case, we will store to all the different 
1518          * in_stacks.
1519          */
1520
1521         found = TRUE;
1522         bindex = 0;
1523         while (found) {
1524                 /* Find a bblock which has a different in_stack */
1525                 found = FALSE;
1526                 while (bindex < bb->out_count) {
1527                         outb = bb->out_bb [bindex];
1528                         /* exception handlers are linked, but they should not be considered for stack args */
1529                         if (outb->flags & BB_EXCEPTION_HANDLER) {
1530                                 bindex++;
1531                                 continue;
1532                         }
1533                         if (outb->in_stack != locals) {
1534                                 for (i = 0; i < count; ++i) {
1535                                         EMIT_NEW_TEMPSTORE (cfg, inst, outb->in_stack [i]->inst_c0, sp [i]);
1536                                         inst->cil_code = sp [i]->cil_code;
1537                                         sp [i] = locals [i];
1538                                         if (cfg->verbose_level > 3)
1539                                                 printf ("storing %d to temp %d\n", i, (int)outb->in_stack [i]->inst_c0);
1540                                 }
1541                                 locals = outb->in_stack;
1542                                 found = TRUE;
1543                                 break;
1544                         }
1545                         bindex ++;
1546                 }
1547         }
1548 }
1549
1550 static MonoInst*
1551 emit_runtime_constant (MonoCompile *cfg, MonoJumpInfoType patch_type, gpointer data)
1552 {
1553         MonoInst *ins;
1554
1555         if (cfg->compile_aot) {
1556                 EMIT_NEW_AOTCONST (cfg, ins, patch_type, data);
1557         } else {
1558                 MonoJumpInfo ji;
1559                 gpointer target;
1560                 MonoError error;
1561
1562                 ji.type = patch_type;
1563                 ji.data.target = data;
1564                 target = mono_resolve_patch_target (NULL, cfg->domain, NULL, &ji, FALSE, &error);
1565                 mono_error_assert_ok (&error);
1566
1567                 EMIT_NEW_PCONST (cfg, ins, target);
1568         }
1569         return ins;
1570 }
1571
1572 static void
1573 mini_emit_interface_bitmap_check (MonoCompile *cfg, int intf_bit_reg, int base_reg, int offset, MonoClass *klass)
1574 {
1575         int ibitmap_reg = alloc_preg (cfg);
1576 #ifdef COMPRESSED_INTERFACE_BITMAP
1577         MonoInst *args [2];
1578         MonoInst *res, *ins;
1579         NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, ibitmap_reg, base_reg, offset);
1580         MONO_ADD_INS (cfg->cbb, ins);
1581         args [0] = ins;
1582         args [1] = emit_runtime_constant (cfg, MONO_PATCH_INFO_IID, klass);
1583         res = mono_emit_jit_icall (cfg, mono_class_interface_match, args);
1584         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, intf_bit_reg, res->dreg);
1585 #else
1586         int ibitmap_byte_reg = alloc_preg (cfg);
1587
1588         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, base_reg, offset);
1589
1590         if (cfg->compile_aot) {
1591                 int iid_reg = alloc_preg (cfg);
1592                 int shifted_iid_reg = alloc_preg (cfg);
1593                 int ibitmap_byte_address_reg = alloc_preg (cfg);
1594                 int masked_iid_reg = alloc_preg (cfg);
1595                 int iid_one_bit_reg = alloc_preg (cfg);
1596                 int iid_bit_reg = alloc_preg (cfg);
1597                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1598                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, shifted_iid_reg, iid_reg, 3);
1599                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ibitmap_byte_address_reg, ibitmap_reg, shifted_iid_reg);
1600                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, ibitmap_byte_reg, ibitmap_byte_address_reg, 0);
1601                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, masked_iid_reg, iid_reg, 7);
1602                 MONO_EMIT_NEW_ICONST (cfg, iid_one_bit_reg, 1);
1603                 MONO_EMIT_NEW_BIALU (cfg, OP_ISHL, iid_bit_reg, iid_one_bit_reg, masked_iid_reg);
1604                 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, intf_bit_reg, ibitmap_byte_reg, iid_bit_reg);
1605         } else {
1606                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, klass->interface_id >> 3);
1607                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (klass->interface_id & 7));
1608         }
1609 #endif
1610 }
1611
1612 /* 
1613  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoClass
1614  * stored in "klass_reg" implements the interface "klass".
1615  */
1616 static void
1617 mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass_reg, MonoClass *klass)
1618 {
1619         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, interface_bitmap), klass);
1620 }
1621
1622 /* 
1623  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoVTable
1624  * stored in "vtable_reg" implements the interface "klass".
1625  */
1626 static void
1627 mini_emit_load_intf_bit_reg_vtable (MonoCompile *cfg, int intf_bit_reg, int vtable_reg, MonoClass *klass)
1628 {
1629         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, interface_bitmap), klass);
1630 }
1631
1632 /* 
1633  * Emit code which checks whenever the interface id of @klass is smaller than
1634  * than the value given by max_iid_reg.
1635 */
1636 static void
1637 mini_emit_max_iid_check (MonoCompile *cfg, int max_iid_reg, MonoClass *klass,
1638                                                  MonoBasicBlock *false_target)
1639 {
1640         if (cfg->compile_aot) {
1641                 int iid_reg = alloc_preg (cfg);
1642                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1643                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, max_iid_reg, iid_reg);
1644         }
1645         else
1646                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, max_iid_reg, klass->interface_id);
1647         if (false_target)
1648                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1649         else
1650                 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1651 }
1652
1653 /* Same as above, but obtains max_iid from a vtable */
1654 static void
1655 mini_emit_max_iid_check_vtable (MonoCompile *cfg, int vtable_reg, MonoClass *klass,
1656                                                                  MonoBasicBlock *false_target)
1657 {
1658         int max_iid_reg = alloc_preg (cfg);
1659                 
1660         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, max_interface_id));
1661         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1662 }
1663
1664 /* Same as above, but obtains max_iid from a klass */
1665 static void
1666 mini_emit_max_iid_check_class (MonoCompile *cfg, int klass_reg, MonoClass *klass,
1667                                                                  MonoBasicBlock *false_target)
1668 {
1669         int max_iid_reg = alloc_preg (cfg);
1670
1671         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, max_interface_id));
1672         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1673 }
1674
1675 static void
1676 mini_emit_isninst_cast_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_ins, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1677 {
1678         int idepth_reg = alloc_preg (cfg);
1679         int stypes_reg = alloc_preg (cfg);
1680         int stype = alloc_preg (cfg);
1681
1682         mono_class_setup_supertypes (klass);
1683
1684         if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1685                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1686                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1687                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1688         }
1689         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1690         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1691         if (klass_ins) {
1692                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, klass_ins->dreg);
1693         } else if (cfg->compile_aot) {
1694                 int const_reg = alloc_preg (cfg);
1695                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1696                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, const_reg);
1697         } else {
1698                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, stype, klass);
1699         }
1700         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, true_target);
1701 }
1702
1703 static void
1704 mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1705 {
1706         mini_emit_isninst_cast_inst (cfg, klass_reg, klass, NULL, false_target, true_target);
1707 }
1708
1709 static void
1710 mini_emit_iface_cast (MonoCompile *cfg, int vtable_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1711 {
1712         int intf_reg = alloc_preg (cfg);
1713
1714         mini_emit_max_iid_check_vtable (cfg, vtable_reg, klass, false_target);
1715         mini_emit_load_intf_bit_reg_vtable (cfg, intf_reg, vtable_reg, klass);
1716         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_reg, 0);
1717         if (true_target)
1718                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1719         else
1720                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");               
1721 }
1722
1723 /*
1724  * Variant of the above that takes a register to the class, not the vtable.
1725  */
1726 static void
1727 mini_emit_iface_class_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1728 {
1729         int intf_bit_reg = alloc_preg (cfg);
1730
1731         mini_emit_max_iid_check_class (cfg, klass_reg, klass, false_target);
1732         mini_emit_load_intf_bit_reg_class (cfg, intf_bit_reg, klass_reg, klass);
1733         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_bit_reg, 0);
1734         if (true_target)
1735                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1736         else
1737                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
1738 }
1739
1740 static inline void
1741 mini_emit_class_check_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_inst)
1742 {
1743         if (klass_inst) {
1744                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_inst->dreg);
1745         } else {
1746                 MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
1747                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, ins->dreg);
1748         }
1749         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1750 }
1751
1752 static inline void
1753 mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass)
1754 {
1755         mini_emit_class_check_inst (cfg, klass_reg, klass, NULL);
1756 }
1757
1758 static inline void
1759 mini_emit_class_check_branch (MonoCompile *cfg, int klass_reg, MonoClass *klass, int branch_op, MonoBasicBlock *target)
1760 {
1761         if (cfg->compile_aot) {
1762                 int const_reg = alloc_preg (cfg);
1763                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1764                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1765         } else {
1766                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1767         }
1768         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, branch_op, target);
1769 }
1770
1771 static void
1772 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null);
1773         
1774 static void
1775 mini_emit_castclass_inst (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoInst *klass_inst, MonoBasicBlock *object_is_null)
1776 {
1777         if (klass->rank) {
1778                 int rank_reg = alloc_preg (cfg);
1779                 int eclass_reg = alloc_preg (cfg);
1780
1781                 g_assert (!klass_inst);
1782                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, rank));
1783                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
1784                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1785                 //              MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
1786                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
1787                 if (klass->cast_class == mono_defaults.object_class) {
1788                         int parent_reg = alloc_preg (cfg);
1789                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
1790                         mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, object_is_null);
1791                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1792                 } else if (klass->cast_class == mono_defaults.enum_class->parent) {
1793                         mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, object_is_null);
1794                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1795                 } else if (klass->cast_class == mono_defaults.enum_class) {
1796                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1797                 } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1798                         mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, NULL, NULL);
1799                 } else {
1800                         // Pass -1 as obj_reg to skip the check below for arrays of arrays
1801                         mini_emit_castclass (cfg, -1, eclass_reg, klass->cast_class, object_is_null);
1802                 }
1803
1804                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY) && (obj_reg != -1)) {
1805                         /* Check that the object is a vector too */
1806                         int bounds_reg = alloc_preg (cfg);
1807                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
1808                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
1809                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1810                 }
1811         } else {
1812                 int idepth_reg = alloc_preg (cfg);
1813                 int stypes_reg = alloc_preg (cfg);
1814                 int stype = alloc_preg (cfg);
1815
1816                 mono_class_setup_supertypes (klass);
1817
1818                 if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1819                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1820                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1821                         MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1822                 }
1823                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1824                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1825                 mini_emit_class_check_inst (cfg, stype, klass, klass_inst);
1826         }
1827 }
1828
1829 static void
1830 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null)
1831 {
1832         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, NULL, object_is_null);
1833 }
1834
1835 static void 
1836 mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align)
1837 {
1838         int val_reg;
1839
1840         g_assert (val == 0);
1841
1842         if (align == 0)
1843                 align = 4;
1844
1845         if ((size <= SIZEOF_REGISTER) && (size <= align)) {
1846                 switch (size) {
1847                 case 1:
1848                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, destreg, offset, val);
1849                         return;
1850                 case 2:
1851                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI2_MEMBASE_IMM, destreg, offset, val);
1852                         return;
1853                 case 4:
1854                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI4_MEMBASE_IMM, destreg, offset, val);
1855                         return;
1856 #if SIZEOF_REGISTER == 8
1857                 case 8:
1858                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI8_MEMBASE_IMM, destreg, offset, val);
1859                         return;
1860 #endif
1861                 }
1862         }
1863
1864         val_reg = alloc_preg (cfg);
1865
1866         if (SIZEOF_REGISTER == 8)
1867                 MONO_EMIT_NEW_I8CONST (cfg, val_reg, val);
1868         else
1869                 MONO_EMIT_NEW_ICONST (cfg, val_reg, val);
1870
1871         if (align < 4) {
1872                 /* This could be optimized further if neccesary */
1873                 while (size >= 1) {
1874                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1875                         offset += 1;
1876                         size -= 1;
1877                 }
1878                 return;
1879         }       
1880
1881         if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
1882                 if (offset % 8) {
1883                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1884                         offset += 4;
1885                         size -= 4;
1886                 }
1887                 while (size >= 8) {
1888                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, offset, val_reg);
1889                         offset += 8;
1890                         size -= 8;
1891                 }
1892         }       
1893
1894         while (size >= 4) {
1895                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1896                 offset += 4;
1897                 size -= 4;
1898         }
1899         while (size >= 2) {
1900                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, val_reg);
1901                 offset += 2;
1902                 size -= 2;
1903         }
1904         while (size >= 1) {
1905                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1906                 offset += 1;
1907                 size -= 1;
1908         }
1909 }
1910
1911 void 
1912 mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align)
1913 {
1914         int cur_reg;
1915
1916         if (align == 0)
1917                 align = 4;
1918
1919         /*FIXME arbitrary hack to avoid unbound code expansion.*/
1920         g_assert (size < 10000);
1921
1922         if (align < 4) {
1923                 /* This could be optimized further if neccesary */
1924                 while (size >= 1) {
1925                         cur_reg = alloc_preg (cfg);
1926                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1927                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1928                         doffset += 1;
1929                         soffset += 1;
1930                         size -= 1;
1931                 }
1932         }
1933
1934         if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
1935                 while (size >= 8) {
1936                         cur_reg = alloc_preg (cfg);
1937                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI8_MEMBASE, cur_reg, srcreg, soffset);
1938                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, doffset, cur_reg);
1939                         doffset += 8;
1940                         soffset += 8;
1941                         size -= 8;
1942                 }
1943         }       
1944
1945         while (size >= 4) {
1946                 cur_reg = alloc_preg (cfg);
1947                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, cur_reg, srcreg, soffset);
1948                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, doffset, cur_reg);
1949                 doffset += 4;
1950                 soffset += 4;
1951                 size -= 4;
1952         }
1953         while (size >= 2) {
1954                 cur_reg = alloc_preg (cfg);
1955                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, cur_reg, srcreg, soffset);
1956                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, doffset, cur_reg);
1957                 doffset += 2;
1958                 soffset += 2;
1959                 size -= 2;
1960         }
1961         while (size >= 1) {
1962                 cur_reg = alloc_preg (cfg);
1963                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1964                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1965                 doffset += 1;
1966                 soffset += 1;
1967                 size -= 1;
1968         }
1969 }
1970
1971 static void
1972 emit_tls_set (MonoCompile *cfg, int sreg1, MonoTlsKey tls_key)
1973 {
1974         MonoInst *ins, *c;
1975
1976         if (cfg->compile_aot) {
1977                 EMIT_NEW_TLS_OFFSETCONST (cfg, c, tls_key);
1978                 MONO_INST_NEW (cfg, ins, OP_TLS_SET_REG);
1979                 ins->sreg1 = sreg1;
1980                 ins->sreg2 = c->dreg;
1981                 MONO_ADD_INS (cfg->cbb, ins);
1982         } else {
1983                 MONO_INST_NEW (cfg, ins, OP_TLS_SET);
1984                 ins->sreg1 = sreg1;
1985                 ins->inst_offset = mini_get_tls_offset (tls_key);
1986                 MONO_ADD_INS (cfg->cbb, ins);
1987         }
1988 }
1989
1990 /*
1991  * emit_push_lmf:
1992  *
1993  *   Emit IR to push the current LMF onto the LMF stack.
1994  */
1995 static void
1996 emit_push_lmf (MonoCompile *cfg)
1997 {
1998         /*
1999          * Emit IR to push the LMF:
2000          * lmf_addr = <lmf_addr from tls>
2001          * lmf->lmf_addr = lmf_addr
2002          * lmf->prev_lmf = *lmf_addr
2003          * *lmf_addr = lmf
2004          */
2005         int lmf_reg, prev_lmf_reg;
2006         MonoInst *ins, *lmf_ins;
2007
2008         if (!cfg->lmf_ir)
2009                 return;
2010
2011         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
2012                 /* Load current lmf */
2013                 lmf_ins = mono_get_lmf_intrinsic (cfg);
2014                 g_assert (lmf_ins);
2015                 MONO_ADD_INS (cfg->cbb, lmf_ins);
2016                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2017                 lmf_reg = ins->dreg;
2018                 /* Save previous_lmf */
2019                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), lmf_ins->dreg);
2020                 /* Set new LMF */
2021                 emit_tls_set (cfg, lmf_reg, TLS_KEY_LMF);
2022         } else {
2023                 /*
2024                  * Store lmf_addr in a variable, so it can be allocated to a global register.
2025                  */
2026                 if (!cfg->lmf_addr_var)
2027                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2028
2029 #ifdef HOST_WIN32
2030                 ins = mono_get_jit_tls_intrinsic (cfg);
2031                 if (ins) {
2032                         int jit_tls_dreg = ins->dreg;
2033
2034                         MONO_ADD_INS (cfg->cbb, ins);
2035                         lmf_reg = alloc_preg (cfg);
2036                         EMIT_NEW_BIALU_IMM (cfg, lmf_ins, OP_PADD_IMM, lmf_reg, jit_tls_dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2037                 } else {
2038                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2039                 }
2040 #else
2041                 lmf_ins = mono_get_lmf_addr_intrinsic (cfg);
2042                 if (lmf_ins) {
2043                         MONO_ADD_INS (cfg->cbb, lmf_ins);
2044                 } else {
2045 #ifdef TARGET_IOS
2046                         MonoInst *args [16], *jit_tls_ins, *ins;
2047
2048                         /* Inline mono_get_lmf_addr () */
2049                         /* jit_tls = pthread_getspecific (mono_jit_tls_id); lmf_addr = &jit_tls->lmf; */
2050
2051                         /* Load mono_jit_tls_id */
2052                         if (cfg->compile_aot)
2053                                 EMIT_NEW_AOTCONST (cfg, args [0], MONO_PATCH_INFO_JIT_TLS_ID, NULL);
2054                         else
2055                                 EMIT_NEW_ICONST (cfg, args [0], mono_jit_tls_id);
2056                         /* call pthread_getspecific () */
2057                         jit_tls_ins = mono_emit_jit_icall (cfg, pthread_getspecific, args);
2058                         /* lmf_addr = &jit_tls->lmf */
2059                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, cfg->lmf_addr_var->dreg, jit_tls_ins->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2060                         lmf_ins = ins;
2061 #else
2062                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2063 #endif
2064                 }
2065 #endif
2066                 lmf_ins->dreg = cfg->lmf_addr_var->dreg;
2067
2068                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2069                 lmf_reg = ins->dreg;
2070
2071                 prev_lmf_reg = alloc_preg (cfg);
2072                 /* Save previous_lmf */
2073                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, cfg->lmf_addr_var->dreg, 0);
2074                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), prev_lmf_reg);
2075                 /* Set new lmf */
2076                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, cfg->lmf_addr_var->dreg, 0, lmf_reg);
2077         }
2078 }
2079
2080 /*
2081  * emit_pop_lmf:
2082  *
2083  *   Emit IR to pop the current LMF from the LMF stack.
2084  */
2085 static void
2086 emit_pop_lmf (MonoCompile *cfg)
2087 {
2088         int lmf_reg, lmf_addr_reg, prev_lmf_reg;
2089         MonoInst *ins;
2090
2091         if (!cfg->lmf_ir)
2092                 return;
2093
2094         EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2095         lmf_reg = ins->dreg;
2096
2097         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
2098                 /* Load previous_lmf */
2099                 prev_lmf_reg = alloc_preg (cfg);
2100                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2101                 /* Set new LMF */
2102                 emit_tls_set (cfg, prev_lmf_reg, TLS_KEY_LMF);
2103         } else {
2104                 /*
2105                  * Emit IR to pop the LMF:
2106                  * *(lmf->lmf_addr) = lmf->prev_lmf
2107                  */
2108                 /* This could be called before emit_push_lmf () */
2109                 if (!cfg->lmf_addr_var)
2110                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2111                 lmf_addr_reg = cfg->lmf_addr_var->dreg;
2112
2113                 prev_lmf_reg = alloc_preg (cfg);
2114                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2115                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_addr_reg, 0, prev_lmf_reg);
2116         }
2117 }
2118
2119 static void
2120 emit_instrumentation_call (MonoCompile *cfg, void *func)
2121 {
2122         MonoInst *iargs [1];
2123
2124         /*
2125          * Avoid instrumenting inlined methods since it can
2126          * distort profiling results.
2127          */
2128         if (cfg->method != cfg->current_method)
2129                 return;
2130
2131         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
2132                 EMIT_NEW_METHODCONST (cfg, iargs [0], cfg->method);
2133                 mono_emit_jit_icall (cfg, func, iargs);
2134         }
2135 }
2136
2137 static int
2138 ret_type_to_call_opcode (MonoCompile *cfg, MonoType *type, int calli, int virt)
2139 {
2140 handle_enum:
2141         type = mini_get_underlying_type (type);
2142         switch (type->type) {
2143         case MONO_TYPE_VOID:
2144                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALL_MEMBASE: OP_VOIDCALL;
2145         case MONO_TYPE_I1:
2146         case MONO_TYPE_U1:
2147         case MONO_TYPE_I2:
2148         case MONO_TYPE_U2:
2149         case MONO_TYPE_I4:
2150         case MONO_TYPE_U4:
2151                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2152         case MONO_TYPE_I:
2153         case MONO_TYPE_U:
2154         case MONO_TYPE_PTR:
2155         case MONO_TYPE_FNPTR:
2156                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2157         case MONO_TYPE_CLASS:
2158         case MONO_TYPE_STRING:
2159         case MONO_TYPE_OBJECT:
2160         case MONO_TYPE_SZARRAY:
2161         case MONO_TYPE_ARRAY:    
2162                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2163         case MONO_TYPE_I8:
2164         case MONO_TYPE_U8:
2165                 return calli? OP_LCALL_REG: virt? OP_LCALL_MEMBASE: OP_LCALL;
2166         case MONO_TYPE_R4:
2167                 if (cfg->r4fp)
2168                         return calli? OP_RCALL_REG: virt? OP_RCALL_MEMBASE: OP_RCALL;
2169                 else
2170                         return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2171         case MONO_TYPE_R8:
2172                 return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2173         case MONO_TYPE_VALUETYPE:
2174                 if (type->data.klass->enumtype) {
2175                         type = mono_class_enum_basetype (type->data.klass);
2176                         goto handle_enum;
2177                 } else
2178                         return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2179         case MONO_TYPE_TYPEDBYREF:
2180                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2181         case MONO_TYPE_GENERICINST:
2182                 type = &type->data.generic_class->container_class->byval_arg;
2183                 goto handle_enum;
2184         case MONO_TYPE_VAR:
2185         case MONO_TYPE_MVAR:
2186                 /* gsharedvt */
2187                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2188         default:
2189                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
2190         }
2191         return -1;
2192 }
2193
2194 //XXX this ignores if t is byref
2195 #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)))))
2196
2197 /*
2198  * target_type_is_incompatible:
2199  * @cfg: MonoCompile context
2200  *
2201  * Check that the item @arg on the evaluation stack can be stored
2202  * in the target type (can be a local, or field, etc).
2203  * The cfg arg can be used to check if we need verification or just
2204  * validity checks.
2205  *
2206  * Returns: non-0 value if arg can't be stored on a target.
2207  */
2208 static int
2209 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
2210 {
2211         MonoType *simple_type;
2212         MonoClass *klass;
2213
2214         if (target->byref) {
2215                 /* FIXME: check that the pointed to types match */
2216                 if (arg->type == STACK_MP) {
2217                         /* This is needed to handle gshared types + ldaddr. We lower the types so we can handle enums and other typedef-like types. */
2218                         MonoClass *target_class_lowered = mono_class_from_mono_type (mini_get_underlying_type (&mono_class_from_mono_type (target)->byval_arg));
2219                         MonoClass *source_class_lowered = mono_class_from_mono_type (mini_get_underlying_type (&arg->klass->byval_arg));
2220
2221                         /* if the target is native int& or same type */
2222                         if (target->type == MONO_TYPE_I || target_class_lowered == source_class_lowered)
2223                                 return 0;
2224
2225                         /* Both are primitive type byrefs and the source points to a larger type that the destination */
2226                         if (MONO_TYPE_IS_PRIMITIVE_SCALAR (&target_class_lowered->byval_arg) && MONO_TYPE_IS_PRIMITIVE_SCALAR (&source_class_lowered->byval_arg) &&
2227                                 mono_class_instance_size (target_class_lowered) <= mono_class_instance_size (source_class_lowered))
2228                                 return 0;
2229                         return 1;
2230                 }
2231                 if (arg->type == STACK_PTR)
2232                         return 0;
2233                 return 1;
2234         }
2235
2236         simple_type = mini_get_underlying_type (target);
2237         switch (simple_type->type) {
2238         case MONO_TYPE_VOID:
2239                 return 1;
2240         case MONO_TYPE_I1:
2241         case MONO_TYPE_U1:
2242         case MONO_TYPE_I2:
2243         case MONO_TYPE_U2:
2244         case MONO_TYPE_I4:
2245         case MONO_TYPE_U4:
2246                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2247                         return 1;
2248                 return 0;
2249         case MONO_TYPE_PTR:
2250                 /* STACK_MP is needed when setting pinned locals */
2251                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2252                         return 1;
2253                 return 0;
2254         case MONO_TYPE_I:
2255         case MONO_TYPE_U:
2256         case MONO_TYPE_FNPTR:
2257                 /* 
2258                  * Some opcodes like ldloca returns 'transient pointers' which can be stored in
2259                  * in native int. (#688008).
2260                  */
2261                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2262                         return 1;
2263                 return 0;
2264         case MONO_TYPE_CLASS:
2265         case MONO_TYPE_STRING:
2266         case MONO_TYPE_OBJECT:
2267         case MONO_TYPE_SZARRAY:
2268         case MONO_TYPE_ARRAY:    
2269                 if (arg->type != STACK_OBJ)
2270                         return 1;
2271                 /* FIXME: check type compatibility */
2272                 return 0;
2273         case MONO_TYPE_I8:
2274         case MONO_TYPE_U8:
2275                 if (arg->type != STACK_I8)
2276                         return 1;
2277                 return 0;
2278         case MONO_TYPE_R4:
2279                 if (arg->type != cfg->r4_stack_type)
2280                         return 1;
2281                 return 0;
2282         case MONO_TYPE_R8:
2283                 if (arg->type != STACK_R8)
2284                         return 1;
2285                 return 0;
2286         case MONO_TYPE_VALUETYPE:
2287                 if (arg->type != STACK_VTYPE)
2288                         return 1;
2289                 klass = mono_class_from_mono_type (simple_type);
2290                 if (klass != arg->klass)
2291                         return 1;
2292                 return 0;
2293         case MONO_TYPE_TYPEDBYREF:
2294                 if (arg->type != STACK_VTYPE)
2295                         return 1;
2296                 klass = mono_class_from_mono_type (simple_type);
2297                 if (klass != arg->klass)
2298                         return 1;
2299                 return 0;
2300         case MONO_TYPE_GENERICINST:
2301                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
2302                         MonoClass *target_class;
2303                         if (arg->type != STACK_VTYPE)
2304                                 return 1;
2305                         klass = mono_class_from_mono_type (simple_type);
2306                         target_class = mono_class_from_mono_type (target);
2307                         /* The second cases is needed when doing partial sharing */
2308                         if (klass != arg->klass && target_class != arg->klass && target_class != mono_class_from_mono_type (mini_get_underlying_type (&arg->klass->byval_arg)))
2309                                 return 1;
2310                         return 0;
2311                 } else {
2312                         if (arg->type != STACK_OBJ)
2313                                 return 1;
2314                         /* FIXME: check type compatibility */
2315                         return 0;
2316                 }
2317         case MONO_TYPE_VAR:
2318         case MONO_TYPE_MVAR:
2319                 g_assert (cfg->gshared);
2320                 if (mini_type_var_is_vt (simple_type)) {
2321                         if (arg->type != STACK_VTYPE)
2322                                 return 1;
2323                 } else {
2324                         if (arg->type != STACK_OBJ)
2325                                 return 1;
2326                 }
2327                 return 0;
2328         default:
2329                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
2330         }
2331         return 1;
2332 }
2333
2334 /*
2335  * Prepare arguments for passing to a function call.
2336  * Return a non-zero value if the arguments can't be passed to the given
2337  * signature.
2338  * The type checks are not yet complete and some conversions may need
2339  * casts on 32 or 64 bit architectures.
2340  *
2341  * FIXME: implement this using target_type_is_incompatible ()
2342  */
2343 static int
2344 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2345 {
2346         MonoType *simple_type;
2347         int i;
2348
2349         if (sig->hasthis) {
2350                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2351                         return 1;
2352                 args++;
2353         }
2354         for (i = 0; i < sig->param_count; ++i) {
2355                 if (sig->params [i]->byref) {
2356                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2357                                 return 1;
2358                         continue;
2359                 }
2360                 simple_type = mini_get_underlying_type (sig->params [i]);
2361 handle_enum:
2362                 switch (simple_type->type) {
2363                 case MONO_TYPE_VOID:
2364                         return 1;
2365                         continue;
2366                 case MONO_TYPE_I1:
2367                 case MONO_TYPE_U1:
2368                 case MONO_TYPE_I2:
2369                 case MONO_TYPE_U2:
2370                 case MONO_TYPE_I4:
2371                 case MONO_TYPE_U4:
2372                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2373                                 return 1;
2374                         continue;
2375                 case MONO_TYPE_I:
2376                 case MONO_TYPE_U:
2377                 case MONO_TYPE_PTR:
2378                 case MONO_TYPE_FNPTR:
2379                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2380                                 return 1;
2381                         continue;
2382                 case MONO_TYPE_CLASS:
2383                 case MONO_TYPE_STRING:
2384                 case MONO_TYPE_OBJECT:
2385                 case MONO_TYPE_SZARRAY:
2386                 case MONO_TYPE_ARRAY:    
2387                         if (args [i]->type != STACK_OBJ)
2388                                 return 1;
2389                         continue;
2390                 case MONO_TYPE_I8:
2391                 case MONO_TYPE_U8:
2392                         if (args [i]->type != STACK_I8)
2393                                 return 1;
2394                         continue;
2395                 case MONO_TYPE_R4:
2396                         if (args [i]->type != cfg->r4_stack_type)
2397                                 return 1;
2398                         continue;
2399                 case MONO_TYPE_R8:
2400                         if (args [i]->type != STACK_R8)
2401                                 return 1;
2402                         continue;
2403                 case MONO_TYPE_VALUETYPE:
2404                         if (simple_type->data.klass->enumtype) {
2405                                 simple_type = mono_class_enum_basetype (simple_type->data.klass);
2406                                 goto handle_enum;
2407                         }
2408                         if (args [i]->type != STACK_VTYPE)
2409                                 return 1;
2410                         continue;
2411                 case MONO_TYPE_TYPEDBYREF:
2412                         if (args [i]->type != STACK_VTYPE)
2413                                 return 1;
2414                         continue;
2415                 case MONO_TYPE_GENERICINST:
2416                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2417                         goto handle_enum;
2418                 case MONO_TYPE_VAR:
2419                 case MONO_TYPE_MVAR:
2420                         /* gsharedvt */
2421                         if (args [i]->type != STACK_VTYPE)
2422                                 return 1;
2423                         continue;
2424                 default:
2425                         g_error ("unknown type 0x%02x in check_call_signature",
2426                                  simple_type->type);
2427                 }
2428         }
2429         return 0;
2430 }
2431
2432 static int
2433 callvirt_to_call (int opcode)
2434 {
2435         switch (opcode) {
2436         case OP_CALL_MEMBASE:
2437                 return OP_CALL;
2438         case OP_VOIDCALL_MEMBASE:
2439                 return OP_VOIDCALL;
2440         case OP_FCALL_MEMBASE:
2441                 return OP_FCALL;
2442         case OP_RCALL_MEMBASE:
2443                 return OP_RCALL;
2444         case OP_VCALL_MEMBASE:
2445                 return OP_VCALL;
2446         case OP_LCALL_MEMBASE:
2447                 return OP_LCALL;
2448         default:
2449                 g_assert_not_reached ();
2450         }
2451
2452         return -1;
2453 }
2454
2455 static int
2456 callvirt_to_call_reg (int opcode)
2457 {
2458         switch (opcode) {
2459         case OP_CALL_MEMBASE:
2460                 return OP_CALL_REG;
2461         case OP_VOIDCALL_MEMBASE:
2462                 return OP_VOIDCALL_REG;
2463         case OP_FCALL_MEMBASE:
2464                 return OP_FCALL_REG;
2465         case OP_RCALL_MEMBASE:
2466                 return OP_RCALL_REG;
2467         case OP_VCALL_MEMBASE:
2468                 return OP_VCALL_REG;
2469         case OP_LCALL_MEMBASE:
2470                 return OP_LCALL_REG;
2471         default:
2472                 g_assert_not_reached ();
2473         }
2474
2475         return -1;
2476 }
2477
2478 /* Either METHOD or IMT_ARG needs to be set */
2479 static void
2480 emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoMethod *method, MonoInst *imt_arg)
2481 {
2482         int method_reg;
2483
2484         if (COMPILE_LLVM (cfg)) {
2485                 if (imt_arg) {
2486                         method_reg = alloc_preg (cfg);
2487                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2488                 } else {
2489                         MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHODCONST, method);
2490                         method_reg = ins->dreg;
2491                 }
2492
2493 #ifdef ENABLE_LLVM
2494                 call->imt_arg_reg = method_reg;
2495 #endif
2496                 mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2497                 return;
2498         }
2499
2500         if (imt_arg) {
2501                 method_reg = alloc_preg (cfg);
2502                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2503         } else {
2504                 MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHODCONST, method);
2505                 method_reg = ins->dreg;
2506         }
2507
2508         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2509 }
2510
2511 static MonoJumpInfo *
2512 mono_patch_info_new (MonoMemPool *mp, int ip, MonoJumpInfoType type, gconstpointer target)
2513 {
2514         MonoJumpInfo *ji = (MonoJumpInfo *)mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
2515
2516         ji->ip.i = ip;
2517         ji->type = type;
2518         ji->data.target = target;
2519
2520         return ji;
2521 }
2522
2523 static int
2524 mini_class_check_context_used (MonoCompile *cfg, MonoClass *klass)
2525 {
2526         if (cfg->gshared)
2527                 return mono_class_check_context_used (klass);
2528         else
2529                 return 0;
2530 }
2531
2532 static int
2533 mini_method_check_context_used (MonoCompile *cfg, MonoMethod *method)
2534 {
2535         if (cfg->gshared)
2536                 return mono_method_check_context_used (method);
2537         else
2538                 return 0;
2539 }
2540
2541 /*
2542  * check_method_sharing:
2543  *
2544  *   Check whenever the vtable or an mrgctx needs to be passed when calling CMETHOD.
2545  */
2546 static void
2547 check_method_sharing (MonoCompile *cfg, MonoMethod *cmethod, gboolean *out_pass_vtable, gboolean *out_pass_mrgctx)
2548 {
2549         gboolean pass_vtable = FALSE;
2550         gboolean pass_mrgctx = FALSE;
2551
2552         if (((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
2553                 (cmethod->klass->generic_class || cmethod->klass->generic_container)) {
2554                 gboolean sharable = FALSE;
2555
2556                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE))
2557                         sharable = TRUE;
2558
2559                 /*
2560                  * Pass vtable iff target method might
2561                  * be shared, which means that sharing
2562                  * is enabled for its class and its
2563                  * context is sharable (and it's not a
2564                  * generic method).
2565                  */
2566                 if (sharable && !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
2567                         pass_vtable = TRUE;
2568         }
2569
2570         if (mini_method_get_context (cmethod) &&
2571                 mini_method_get_context (cmethod)->method_inst) {
2572                 g_assert (!pass_vtable);
2573
2574                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE)) {
2575                         pass_mrgctx = TRUE;
2576                 } else {
2577                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (mono_method_signature (cmethod)))
2578                                 pass_mrgctx = TRUE;
2579                 }
2580         }
2581
2582         if (out_pass_vtable)
2583                 *out_pass_vtable = pass_vtable;
2584         if (out_pass_mrgctx)
2585                 *out_pass_mrgctx = pass_mrgctx;
2586 }
2587
2588 inline static MonoCallInst *
2589 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
2590                                          MonoInst **args, int calli, int virtual_, int tail, int rgctx, int unbox_trampoline)
2591 {
2592         MonoType *sig_ret;
2593         MonoCallInst *call;
2594 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2595         int i;
2596 #endif
2597
2598         if (cfg->llvm_only)
2599                 tail = FALSE;
2600
2601         if (tail) {
2602                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
2603
2604                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
2605         } else
2606                 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (cfg, sig->ret, calli, virtual_));
2607
2608         call->args = args;
2609         call->signature = sig;
2610         call->rgctx_reg = rgctx;
2611         sig_ret = mini_get_underlying_type (sig->ret);
2612
2613         type_to_eval_stack_type ((cfg), sig_ret, &call->inst);
2614
2615         if (tail) {
2616                 if (mini_type_is_vtype (sig_ret)) {
2617                         call->vret_var = cfg->vret_addr;
2618                         //g_assert_not_reached ();
2619                 }
2620         } else if (mini_type_is_vtype (sig_ret)) {
2621                 MonoInst *temp = mono_compile_create_var (cfg, sig_ret, OP_LOCAL);
2622                 MonoInst *loada;
2623
2624                 temp->backend.is_pinvoke = sig->pinvoke;
2625
2626                 /*
2627                  * We use a new opcode OP_OUTARG_VTRETADDR instead of LDADDR for emitting the
2628                  * address of return value to increase optimization opportunities.
2629                  * Before vtype decomposition, the dreg of the call ins itself represents the
2630                  * fact the call modifies the return value. After decomposition, the call will
2631                  * be transformed into one of the OP_VOIDCALL opcodes, and the VTRETADDR opcode
2632                  * will be transformed into an LDADDR.
2633                  */
2634                 MONO_INST_NEW (cfg, loada, OP_OUTARG_VTRETADDR);
2635                 loada->dreg = alloc_preg (cfg);
2636                 loada->inst_p0 = temp;
2637                 /* We reference the call too since call->dreg could change during optimization */
2638                 loada->inst_p1 = call;
2639                 MONO_ADD_INS (cfg->cbb, loada);
2640
2641                 call->inst.dreg = temp->dreg;
2642
2643                 call->vret_var = loada;
2644         } else if (!MONO_TYPE_IS_VOID (sig_ret))
2645                 call->inst.dreg = alloc_dreg (cfg, (MonoStackType)call->inst.type);
2646
2647 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2648         if (COMPILE_SOFT_FLOAT (cfg)) {
2649                 /* 
2650                  * If the call has a float argument, we would need to do an r8->r4 conversion using 
2651                  * an icall, but that cannot be done during the call sequence since it would clobber
2652                  * the call registers + the stack. So we do it before emitting the call.
2653                  */
2654                 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2655                         MonoType *t;
2656                         MonoInst *in = call->args [i];
2657
2658                         if (i >= sig->hasthis)
2659                                 t = sig->params [i - sig->hasthis];
2660                         else
2661                                 t = &mono_defaults.int_class->byval_arg;
2662                         t = mono_type_get_underlying_type (t);
2663
2664                         if (!t->byref && t->type == MONO_TYPE_R4) {
2665                                 MonoInst *iargs [1];
2666                                 MonoInst *conv;
2667
2668                                 iargs [0] = in;
2669                                 conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
2670
2671                                 /* The result will be in an int vreg */
2672                                 call->args [i] = conv;
2673                         }
2674                 }
2675         }
2676 #endif
2677
2678         call->need_unbox_trampoline = unbox_trampoline;
2679
2680 #ifdef ENABLE_LLVM
2681         if (COMPILE_LLVM (cfg))
2682                 mono_llvm_emit_call (cfg, call);
2683         else
2684                 mono_arch_emit_call (cfg, call);
2685 #else
2686         mono_arch_emit_call (cfg, call);
2687 #endif
2688
2689         cfg->param_area = MAX (cfg->param_area, call->stack_usage);
2690         cfg->flags |= MONO_CFG_HAS_CALLS;
2691         
2692         return call;
2693 }
2694
2695 static void
2696 set_rgctx_arg (MonoCompile *cfg, MonoCallInst *call, int rgctx_reg, MonoInst *rgctx_arg)
2697 {
2698         mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
2699         cfg->uses_rgctx_reg = TRUE;
2700         call->rgctx_reg = TRUE;
2701 #ifdef ENABLE_LLVM
2702         call->rgctx_arg_reg = rgctx_reg;
2703 #endif
2704 }       
2705
2706 inline static MonoInst*
2707 mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg)
2708 {
2709         MonoCallInst *call;
2710         MonoInst *ins;
2711         int rgctx_reg = -1;
2712         gboolean check_sp = FALSE;
2713
2714         if (cfg->check_pinvoke_callconv && cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
2715                 WrapperInfo *info = mono_marshal_get_wrapper_info (cfg->method);
2716
2717                 if (info && info->subtype == WRAPPER_SUBTYPE_PINVOKE)
2718                         check_sp = TRUE;
2719         }
2720
2721         if (rgctx_arg) {
2722                 rgctx_reg = mono_alloc_preg (cfg);
2723                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2724         }
2725
2726         if (check_sp) {
2727                 if (!cfg->stack_inbalance_var)
2728                         cfg->stack_inbalance_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2729
2730                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2731                 ins->dreg = cfg->stack_inbalance_var->dreg;
2732                 MONO_ADD_INS (cfg->cbb, ins);
2733         }
2734
2735         call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE, FALSE);
2736
2737         call->inst.sreg1 = addr->dreg;
2738
2739         if (imt_arg)
2740                 emit_imt_argument (cfg, call, NULL, imt_arg);
2741
2742         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2743
2744         if (check_sp) {
2745                 int sp_reg;
2746
2747                 sp_reg = mono_alloc_preg (cfg);
2748
2749                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2750                 ins->dreg = sp_reg;
2751                 MONO_ADD_INS (cfg->cbb, ins);
2752
2753                 /* Restore the stack so we don't crash when throwing the exception */
2754                 MONO_INST_NEW (cfg, ins, OP_SET_SP);
2755                 ins->sreg1 = cfg->stack_inbalance_var->dreg;
2756                 MONO_ADD_INS (cfg->cbb, ins);
2757
2758                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, cfg->stack_inbalance_var->dreg, sp_reg);
2759                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ExecutionEngineException");
2760         }
2761
2762         if (rgctx_arg)
2763                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2764
2765         return (MonoInst*)call;
2766 }
2767
2768 static MonoInst*
2769 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2770
2771 static MonoInst*
2772 emit_get_rgctx_method (MonoCompile *cfg, int context_used, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type);
2773 static MonoInst*
2774 emit_get_rgctx_klass (MonoCompile *cfg, int context_used, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2775
2776 static MonoInst*
2777 mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig, gboolean tail,
2778                                                         MonoInst **args, MonoInst *this_ins, MonoInst *imt_arg, MonoInst *rgctx_arg)
2779 {
2780 #ifndef DISABLE_REMOTING
2781         gboolean might_be_remote = FALSE;
2782 #endif
2783         gboolean virtual_ = this_ins != NULL;
2784         gboolean enable_for_aot = TRUE;
2785         int context_used;
2786         MonoCallInst *call;
2787         MonoInst *call_target = NULL;
2788         int rgctx_reg = 0;
2789         gboolean need_unbox_trampoline;
2790
2791         if (!sig)
2792                 sig = mono_method_signature (method);
2793
2794         if (cfg->llvm_only && (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE))
2795                 g_assert_not_reached ();
2796
2797         if (rgctx_arg) {
2798                 rgctx_reg = mono_alloc_preg (cfg);
2799                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2800         }
2801
2802         if (method->string_ctor) {
2803                 /* Create the real signature */
2804                 /* FIXME: Cache these */
2805                 MonoMethodSignature *ctor_sig = mono_metadata_signature_dup_mempool (cfg->mempool, sig);
2806                 ctor_sig->ret = &mono_defaults.string_class->byval_arg;
2807
2808                 sig = ctor_sig;
2809         }
2810
2811         context_used = mini_method_check_context_used (cfg, method);
2812
2813 #ifndef DISABLE_REMOTING
2814         might_be_remote = this_ins && sig->hasthis &&
2815                 (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) &&
2816                 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && (!MONO_CHECK_THIS (this_ins) || context_used);
2817
2818         if (might_be_remote && context_used) {
2819                 MonoInst *addr;
2820
2821                 g_assert (cfg->gshared);
2822
2823                 addr = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK);
2824
2825                 return mono_emit_calli (cfg, sig, args, addr, NULL, NULL);
2826         }
2827 #endif
2828
2829         if (cfg->llvm_only && !call_target && virtual_ && (method->flags & METHOD_ATTRIBUTE_VIRTUAL))
2830                 return emit_llvmonly_virtual_call (cfg, method, sig, 0, args);
2831
2832         need_unbox_trampoline = method->klass == mono_defaults.object_class || (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
2833
2834         call = mono_emit_call_args (cfg, sig, args, FALSE, virtual_, tail, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline);
2835
2836 #ifndef DISABLE_REMOTING
2837         if (might_be_remote)
2838                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2839         else
2840 #endif
2841                 call->method = method;
2842         call->inst.flags |= MONO_INST_HAS_METHOD;
2843         call->inst.inst_left = this_ins;
2844         call->tail_call = tail;
2845
2846         if (virtual_) {
2847                 int vtable_reg, slot_reg, this_reg;
2848                 int offset;
2849
2850                 this_reg = this_ins->dreg;
2851
2852                 if (!cfg->llvm_only && (method->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (method->name, "Invoke")) {
2853                         MonoInst *dummy_use;
2854
2855                         MONO_EMIT_NULL_CHECK (cfg, this_reg);
2856
2857                         /* Make a call to delegate->invoke_impl */
2858                         call->inst.inst_basereg = this_reg;
2859                         call->inst.inst_offset = MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl);
2860                         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2861
2862                         /* We must emit a dummy use here because the delegate trampoline will
2863                         replace the 'this' argument with the delegate target making this activation
2864                         no longer a root for the delegate.
2865                         This is an issue for delegates that target collectible code such as dynamic
2866                         methods of GC'able assemblies.
2867
2868                         For a test case look into #667921.
2869
2870                         FIXME: a dummy use is not the best way to do it as the local register allocator
2871                         will put it on a caller save register and spil it around the call. 
2872                         Ideally, we would either put it on a callee save register or only do the store part.  
2873                          */
2874                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, args [0]);
2875
2876                         return (MonoInst*)call;
2877                 }
2878
2879                 if ((!cfg->compile_aot || enable_for_aot) && 
2880                         (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || 
2881                          (MONO_METHOD_IS_FINAL (method) &&
2882                           method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)) &&
2883                         !(mono_class_is_marshalbyref (method->klass) && context_used)) {
2884                         /* 
2885                          * the method is not virtual, we just need to ensure this is not null
2886                          * and then we can call the method directly.
2887                          */
2888 #ifndef DISABLE_REMOTING
2889                         if (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) {
2890                                 /* 
2891                                  * The check above ensures method is not gshared, this is needed since
2892                                  * gshared methods can't have wrappers.
2893                                  */
2894                                 method = call->method = mono_marshal_get_remoting_invoke_with_check (method);
2895                         }
2896 #endif
2897
2898                         if (!method->string_ctor)
2899                                 MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2900
2901                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2902                 } else if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && MONO_METHOD_IS_FINAL (method)) {
2903                         /*
2904                          * the method is virtual, but we can statically dispatch since either
2905                          * it's class or the method itself are sealed.
2906                          * But first we need to ensure it's not a null reference.
2907                          */
2908                         MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2909
2910                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2911                 } else if (call_target) {
2912                         vtable_reg = alloc_preg (cfg);
2913                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2914
2915                         call->inst.opcode = callvirt_to_call_reg (call->inst.opcode);
2916                         call->inst.sreg1 = call_target->dreg;
2917                         call->inst.flags &= !MONO_INST_HAS_METHOD;
2918                 } else {
2919                         vtable_reg = alloc_preg (cfg);
2920                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2921                         if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2922                                 guint32 imt_slot = mono_method_get_imt_slot (method);
2923                                 emit_imt_argument (cfg, call, call->method, imt_arg);
2924                                 slot_reg = vtable_reg;
2925                                 offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
2926                         } else {
2927                                 slot_reg = vtable_reg;
2928                                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) +
2929                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
2930                                 if (imt_arg) {
2931                                         g_assert (mono_method_signature (method)->generic_param_count);
2932                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2933                                 }
2934                         }
2935
2936                         call->inst.sreg1 = slot_reg;
2937                         call->inst.inst_offset = offset;
2938                         call->is_virtual = TRUE;
2939                 }
2940         }
2941
2942         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2943
2944         if (rgctx_arg)
2945                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2946
2947         return (MonoInst*)call;
2948 }
2949
2950 MonoInst*
2951 mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoInst **args, MonoInst *this_ins)
2952 {
2953         return mono_emit_method_call_full (cfg, method, mono_method_signature (method), FALSE, args, this_ins, NULL, NULL);
2954 }
2955
2956 MonoInst*
2957 mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig,
2958                                            MonoInst **args)
2959 {
2960         MonoCallInst *call;
2961
2962         g_assert (sig);
2963
2964         call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE, FALSE, FALSE);
2965         call->fptr = func;
2966
2967         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2968
2969         return (MonoInst*)call;
2970 }
2971
2972 MonoInst*
2973 mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args)
2974 {
2975         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2976
2977         g_assert (info);
2978
2979         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2980 }
2981
2982 /*
2983  * mono_emit_abs_call:
2984  *
2985  *   Emit a call to the runtime function described by PATCH_TYPE and DATA.
2986  */
2987 inline static MonoInst*
2988 mono_emit_abs_call (MonoCompile *cfg, MonoJumpInfoType patch_type, gconstpointer data, 
2989                                         MonoMethodSignature *sig, MonoInst **args)
2990 {
2991         MonoJumpInfo *ji = mono_patch_info_new (cfg->mempool, 0, patch_type, data);
2992         MonoInst *ins;
2993
2994         /* 
2995          * We pass ji as the call address, the PATCH_INFO_ABS resolving code will
2996          * handle it.
2997          */
2998         if (cfg->abs_patches == NULL)
2999                 cfg->abs_patches = g_hash_table_new (NULL, NULL);
3000         g_hash_table_insert (cfg->abs_patches, ji, ji);
3001         ins = mono_emit_native_call (cfg, ji, sig, args);
3002         ((MonoCallInst*)ins)->fptr_is_patch = TRUE;
3003         return ins;
3004 }
3005
3006 static MonoMethodSignature*
3007 sig_to_rgctx_sig (MonoMethodSignature *sig)
3008 {
3009         // FIXME: memory allocation
3010         MonoMethodSignature *res;
3011         int i;
3012
3013         res = (MonoMethodSignature *)g_malloc (MONO_SIZEOF_METHOD_SIGNATURE + (sig->param_count + 1) * sizeof (MonoType*));
3014         memcpy (res, sig, MONO_SIZEOF_METHOD_SIGNATURE);
3015         res->param_count = sig->param_count + 1;
3016         for (i = 0; i < sig->param_count; ++i)
3017                 res->params [i] = sig->params [i];
3018         res->params [sig->param_count] = &mono_defaults.int_class->this_arg;
3019         return res;
3020 }
3021
3022 /* Make an indirect call to FSIG passing an additional argument */
3023 static MonoInst*
3024 emit_extra_arg_calli (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **orig_args, int arg_reg, MonoInst *call_target)
3025 {
3026         MonoMethodSignature *csig;
3027         MonoInst *args_buf [16];
3028         MonoInst **args;
3029         int i, pindex, tmp_reg;
3030
3031         /* Make a call with an rgctx/extra arg */
3032         if (fsig->param_count + 2 < 16)
3033                 args = args_buf;
3034         else
3035                 args = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (fsig->param_count + 2));
3036         pindex = 0;
3037         if (fsig->hasthis)
3038                 args [pindex ++] = orig_args [0];
3039         for (i = 0; i < fsig->param_count; ++i)
3040                 args [pindex ++] = orig_args [fsig->hasthis + i];
3041         tmp_reg = alloc_preg (cfg);
3042         EMIT_NEW_UNALU (cfg, args [pindex], OP_MOVE, tmp_reg, arg_reg);
3043         csig = sig_to_rgctx_sig (fsig);
3044         return mono_emit_calli (cfg, csig, args, call_target, NULL, NULL);
3045 }
3046
3047 /* Emit an indirect call to the function descriptor ADDR */
3048 static MonoInst*
3049 emit_llvmonly_calli (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, MonoInst *addr)
3050 {
3051         int addr_reg, arg_reg;
3052         MonoInst *call_target;
3053
3054         g_assert (cfg->llvm_only);
3055
3056         /*
3057          * addr points to a <addr, arg> pair, load both of them, and
3058          * make a call to addr, passing arg as an extra arg.
3059          */
3060         addr_reg = alloc_preg (cfg);
3061         EMIT_NEW_LOAD_MEMBASE (cfg, call_target, OP_LOAD_MEMBASE, addr_reg, addr->dreg, 0);
3062         arg_reg = alloc_preg (cfg);
3063         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, arg_reg, addr->dreg, sizeof (gpointer));
3064
3065         return emit_extra_arg_calli (cfg, fsig, args, arg_reg, call_target);
3066 }
3067
3068 static gboolean
3069 direct_icalls_enabled (MonoCompile *cfg)
3070 {
3071         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
3072 #ifdef TARGET_AMD64
3073         if (cfg->compile_llvm && !cfg->llvm_only)
3074                 return FALSE;
3075 #endif
3076         if (cfg->gen_sdb_seq_points || cfg->disable_direct_icalls)
3077                 return FALSE;
3078         return TRUE;
3079 }
3080
3081 MonoInst*
3082 mono_emit_jit_icall_by_info (MonoCompile *cfg, int il_offset, MonoJitICallInfo *info, MonoInst **args)
3083 {
3084         /*
3085          * Call the jit icall without a wrapper if possible.
3086          * The wrapper is needed for the following reasons:
3087          * - to handle exceptions thrown using mono_raise_exceptions () from the
3088          *   icall function. The EH code needs the lmf frame pushed by the
3089          *   wrapper to be able to unwind back to managed code.
3090          * - to be able to do stack walks for asynchronously suspended
3091          *   threads when debugging.
3092          */
3093         if (info->no_raise && direct_icalls_enabled (cfg)) {
3094                 char *name;
3095                 int costs;
3096
3097                 if (!info->wrapper_method) {
3098                         name = g_strdup_printf ("__icall_wrapper_%s", info->name);
3099                         info->wrapper_method = mono_marshal_get_icall_wrapper (info->sig, name, info->func, TRUE);
3100                         g_free (name);
3101                         mono_memory_barrier ();
3102                 }
3103
3104                 /*
3105                  * Inline the wrapper method, which is basically a call to the C icall, and
3106                  * an exception check.
3107                  */
3108                 costs = inline_method (cfg, info->wrapper_method, NULL,
3109                                                            args, NULL, il_offset, TRUE);
3110                 g_assert (costs > 0);
3111                 g_assert (!MONO_TYPE_IS_VOID (info->sig->ret));
3112
3113                 return args [0];
3114         } else {
3115                 return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
3116         }
3117 }
3118  
3119 static MonoInst*
3120 mono_emit_widen_call_res (MonoCompile *cfg, MonoInst *ins, MonoMethodSignature *fsig)
3121 {
3122         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
3123                 if ((fsig->pinvoke || LLVM_ENABLED) && !fsig->ret->byref) {
3124                         int widen_op = -1;
3125
3126                         /* 
3127                          * Native code might return non register sized integers 
3128                          * without initializing the upper bits.
3129                          */
3130                         switch (mono_type_to_load_membase (cfg, fsig->ret)) {
3131                         case OP_LOADI1_MEMBASE:
3132                                 widen_op = OP_ICONV_TO_I1;
3133                                 break;
3134                         case OP_LOADU1_MEMBASE:
3135                                 widen_op = OP_ICONV_TO_U1;
3136                                 break;
3137                         case OP_LOADI2_MEMBASE:
3138                                 widen_op = OP_ICONV_TO_I2;
3139                                 break;
3140                         case OP_LOADU2_MEMBASE:
3141                                 widen_op = OP_ICONV_TO_U2;
3142                                 break;
3143                         default:
3144                                 break;
3145                         }
3146
3147                         if (widen_op != -1) {
3148                                 int dreg = alloc_preg (cfg);
3149                                 MonoInst *widen;
3150
3151                                 EMIT_NEW_UNALU (cfg, widen, widen_op, dreg, ins->dreg);
3152                                 widen->type = ins->type;
3153                                 ins = widen;
3154                         }
3155                 }
3156         }
3157
3158         return ins;
3159 }
3160
3161
3162 static void
3163 emit_method_access_failure (MonoCompile *cfg, MonoMethod *method, MonoMethod *cil_method)
3164 {
3165         MonoInst *args [16];
3166
3167         args [0] = emit_get_rgctx_method (cfg, mono_method_check_context_used (method), method, MONO_RGCTX_INFO_METHOD);
3168         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cil_method), cil_method, MONO_RGCTX_INFO_METHOD);
3169
3170         mono_emit_jit_icall (cfg, mono_throw_method_access, args);
3171 }
3172
3173 static MonoMethod*
3174 get_memcpy_method (void)
3175 {
3176         static MonoMethod *memcpy_method = NULL;
3177         if (!memcpy_method) {
3178                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
3179                 if (!memcpy_method)
3180                         g_error ("Old corlib found. Install a new one");
3181         }
3182         return memcpy_method;
3183 }
3184
3185 static void
3186 create_write_barrier_bitmap (MonoCompile *cfg, MonoClass *klass, unsigned *wb_bitmap, int offset)
3187 {
3188         MonoClassField *field;
3189         gpointer iter = NULL;
3190
3191         while ((field = mono_class_get_fields (klass, &iter))) {
3192                 int foffset;
3193
3194                 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3195                         continue;
3196                 foffset = klass->valuetype ? field->offset - sizeof (MonoObject): field->offset;
3197                 if (mini_type_is_reference (mono_field_get_type (field))) {
3198                         g_assert ((foffset % SIZEOF_VOID_P) == 0);
3199                         *wb_bitmap |= 1 << ((offset + foffset) / SIZEOF_VOID_P);
3200                 } else {
3201                         MonoClass *field_class = mono_class_from_mono_type (field->type);
3202                         if (field_class->has_references)
3203                                 create_write_barrier_bitmap (cfg, field_class, wb_bitmap, offset + foffset);
3204                 }
3205         }
3206 }
3207
3208 static void
3209 emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value)
3210 {
3211         int card_table_shift_bits;
3212         gpointer card_table_mask;
3213         guint8 *card_table;
3214         MonoInst *dummy_use;
3215         int nursery_shift_bits;
3216         size_t nursery_size;
3217
3218         if (!cfg->gen_write_barriers)
3219                 return;
3220
3221         card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
3222
3223         mono_gc_get_nursery (&nursery_shift_bits, &nursery_size);
3224
3225         if (cfg->backend->have_card_table_wb && !cfg->compile_aot && card_table && nursery_shift_bits > 0 && !COMPILE_LLVM (cfg)) {
3226                 MonoInst *wbarrier;
3227
3228                 MONO_INST_NEW (cfg, wbarrier, OP_CARD_TABLE_WBARRIER);
3229                 wbarrier->sreg1 = ptr->dreg;
3230                 wbarrier->sreg2 = value->dreg;
3231                 MONO_ADD_INS (cfg->cbb, wbarrier);
3232         } else if (card_table && !cfg->compile_aot && !mono_gc_card_table_nursery_check ()) {
3233                 int offset_reg = alloc_preg (cfg);
3234                 int card_reg;
3235                 MonoInst *ins;
3236
3237                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, offset_reg, ptr->dreg, card_table_shift_bits);
3238                 if (card_table_mask)
3239                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, offset_reg, offset_reg, card_table_mask);
3240
3241                 /*We can't use PADD_IMM since the cardtable might end up in high addresses and amd64 doesn't support
3242                  * IMM's larger than 32bits.
3243                  */
3244                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
3245                 card_reg = ins->dreg;
3246
3247                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, offset_reg, offset_reg, card_reg);
3248                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, offset_reg, 0, 1);
3249         } else {
3250                 MonoMethod *write_barrier = mono_gc_get_write_barrier ();
3251                 mono_emit_method_call (cfg, write_barrier, &ptr, NULL);
3252         }
3253
3254         EMIT_NEW_DUMMY_USE (cfg, dummy_use, value);
3255 }
3256
3257 static gboolean
3258 mono_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align)
3259 {
3260         int dest_ptr_reg, tmp_reg, destreg, srcreg, offset;
3261         unsigned need_wb = 0;
3262
3263         if (align == 0)
3264                 align = 4;
3265
3266         /*types with references can't have alignment smaller than sizeof(void*) */
3267         if (align < SIZEOF_VOID_P)
3268                 return FALSE;
3269
3270         /*This value cannot be bigger than 32 due to the way we calculate the required wb bitmap.*/
3271         if (size > 32 * SIZEOF_VOID_P)
3272                 return FALSE;
3273
3274         create_write_barrier_bitmap (cfg, klass, &need_wb, 0);
3275
3276         /* We don't unroll more than 5 stores to avoid code bloat. */
3277         if (size > 5 * SIZEOF_VOID_P) {
3278                 /*This is harmless and simplify mono_gc_wbarrier_value_copy_bitmap */
3279                 size += (SIZEOF_VOID_P - 1);
3280                 size &= ~(SIZEOF_VOID_P - 1);
3281
3282                 EMIT_NEW_ICONST (cfg, iargs [2], size);
3283                 EMIT_NEW_ICONST (cfg, iargs [3], need_wb);
3284                 mono_emit_jit_icall (cfg, mono_gc_wbarrier_value_copy_bitmap, iargs);
3285                 return TRUE;
3286         }
3287
3288         destreg = iargs [0]->dreg;
3289         srcreg = iargs [1]->dreg;
3290         offset = 0;
3291
3292         dest_ptr_reg = alloc_preg (cfg);
3293         tmp_reg = alloc_preg (cfg);
3294
3295         /*tmp = dreg*/
3296         EMIT_NEW_UNALU (cfg, iargs [0], OP_MOVE, dest_ptr_reg, destreg);
3297
3298         while (size >= SIZEOF_VOID_P) {
3299                 MonoInst *load_inst;
3300                 MONO_INST_NEW (cfg, load_inst, OP_LOAD_MEMBASE);
3301                 load_inst->dreg = tmp_reg;
3302                 load_inst->inst_basereg = srcreg;
3303                 load_inst->inst_offset = offset;
3304                 MONO_ADD_INS (cfg->cbb, load_inst);
3305
3306                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, dest_ptr_reg, 0, tmp_reg);
3307
3308                 if (need_wb & 0x1)
3309                         emit_write_barrier (cfg, iargs [0], load_inst);
3310
3311                 offset += SIZEOF_VOID_P;
3312                 size -= SIZEOF_VOID_P;
3313                 need_wb >>= 1;
3314
3315                 /*tmp += sizeof (void*)*/
3316                 if (size >= SIZEOF_VOID_P) {
3317                         NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dest_ptr_reg, dest_ptr_reg, SIZEOF_VOID_P);
3318                         MONO_ADD_INS (cfg->cbb, iargs [0]);
3319                 }
3320         }
3321
3322         /* Those cannot be references since size < sizeof (void*) */
3323         while (size >= 4) {
3324                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tmp_reg, srcreg, offset);
3325                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, tmp_reg);
3326                 offset += 4;
3327                 size -= 4;
3328         }
3329
3330         while (size >= 2) {
3331                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmp_reg, srcreg, offset);
3332                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, tmp_reg);
3333                 offset += 2;
3334                 size -= 2;
3335         }
3336
3337         while (size >= 1) {
3338                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmp_reg, srcreg, offset);
3339                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, tmp_reg);
3340                 offset += 1;
3341                 size -= 1;
3342         }
3343
3344         return TRUE;
3345 }
3346
3347 /*
3348  * Emit code to copy a valuetype of type @klass whose address is stored in
3349  * @src->dreg to memory whose address is stored at @dest->dreg.
3350  */
3351 void
3352 mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native)
3353 {
3354         MonoInst *iargs [4];
3355         int n;
3356         guint32 align = 0;
3357         MonoMethod *memcpy_method;
3358         MonoInst *size_ins = NULL;
3359         MonoInst *memcpy_ins = NULL;
3360
3361         g_assert (klass);
3362         if (cfg->gshared)
3363                 klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg));
3364
3365         /*
3366          * This check breaks with spilled vars... need to handle it during verification anyway.
3367          * g_assert (klass && klass == src->klass && klass == dest->klass);
3368          */
3369
3370         if (mini_is_gsharedvt_klass (klass)) {
3371                 g_assert (!native);
3372                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3373                 memcpy_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_MEMCPY);
3374         }
3375
3376         if (native)
3377                 n = mono_class_native_size (klass, &align);
3378         else
3379                 n = mono_class_value_size (klass, &align);
3380
3381         /* if native is true there should be no references in the struct */
3382         if (cfg->gen_write_barriers && (klass->has_references || size_ins) && !native) {
3383                 /* Avoid barriers when storing to the stack */
3384                 if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) ||
3385                           (dest->opcode == OP_LDADDR))) {
3386                         int context_used;
3387
3388                         iargs [0] = dest;
3389                         iargs [1] = src;
3390
3391                         context_used = mini_class_check_context_used (cfg, klass);
3392
3393                         /* It's ok to intrinsify under gsharing since shared code types are layout stable. */
3394                         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && mono_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
3395                                 return;
3396                         } else if (context_used) {
3397                                 iargs [2] = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3398                         }  else {
3399                                 iargs [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
3400                                 if (!cfg->compile_aot)
3401                                         mono_class_compute_gc_descriptor (klass);
3402                         }
3403
3404                         if (size_ins)
3405                                 mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs);
3406                         else
3407                                 mono_emit_jit_icall (cfg, mono_value_copy, iargs);
3408                         return;
3409                 }
3410         }
3411
3412         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 8) {
3413                 /* FIXME: Optimize the case when src/dest is OP_LDADDR */
3414                 mini_emit_memcpy (cfg, dest->dreg, 0, src->dreg, 0, n, align);
3415         } else {
3416                 iargs [0] = dest;
3417                 iargs [1] = src;
3418                 if (size_ins)
3419                         iargs [2] = size_ins;
3420                 else
3421                         EMIT_NEW_ICONST (cfg, iargs [2], n);
3422                 
3423                 memcpy_method = get_memcpy_method ();
3424                 if (memcpy_ins)
3425                         mono_emit_calli (cfg, mono_method_signature (memcpy_method), iargs, memcpy_ins, NULL, NULL);
3426                 else
3427                         mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
3428         }
3429 }
3430
3431 static MonoMethod*
3432 get_memset_method (void)
3433 {
3434         static MonoMethod *memset_method = NULL;
3435         if (!memset_method) {
3436                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
3437                 if (!memset_method)
3438                         g_error ("Old corlib found. Install a new one");
3439         }
3440         return memset_method;
3441 }
3442
3443 void
3444 mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass)
3445 {
3446         MonoInst *iargs [3];
3447         int n;
3448         guint32 align;
3449         MonoMethod *memset_method;
3450         MonoInst *size_ins = NULL;
3451         MonoInst *bzero_ins = NULL;
3452         static MonoMethod *bzero_method;
3453
3454         /* FIXME: Optimize this for the case when dest is an LDADDR */
3455         mono_class_init (klass);
3456         if (mini_is_gsharedvt_klass (klass)) {
3457                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3458                 bzero_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_BZERO);
3459                 if (!bzero_method)
3460                         bzero_method = mono_class_get_method_from_name (mono_defaults.string_class, "bzero_aligned_1", 2);
3461                 g_assert (bzero_method);
3462                 iargs [0] = dest;
3463                 iargs [1] = size_ins;
3464                 mono_emit_calli (cfg, mono_method_signature (bzero_method), iargs, bzero_ins, NULL, NULL);
3465                 return;
3466         }
3467
3468         klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg));
3469
3470         n = mono_class_value_size (klass, &align);
3471
3472         if (n <= sizeof (gpointer) * 8) {
3473                 mini_emit_memset (cfg, dest->dreg, 0, n, 0, align);
3474         }
3475         else {
3476                 memset_method = get_memset_method ();
3477                 iargs [0] = dest;
3478                 EMIT_NEW_ICONST (cfg, iargs [1], 0);
3479                 EMIT_NEW_ICONST (cfg, iargs [2], n);
3480                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
3481         }
3482 }
3483
3484 /*
3485  * emit_get_rgctx:
3486  *
3487  *   Emit IR to return either the this pointer for instance method,
3488  * or the mrgctx for static methods.
3489  */
3490 static MonoInst*
3491 emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used)
3492 {
3493         MonoInst *this_ins = NULL;
3494
3495         g_assert (cfg->gshared);
3496
3497         if (!(method->flags & METHOD_ATTRIBUTE_STATIC) &&
3498                         !(context_used & MONO_GENERIC_CONTEXT_USED_METHOD) &&
3499                         !method->klass->valuetype)
3500                 EMIT_NEW_ARGLOAD (cfg, this_ins, 0);
3501
3502         if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
3503                 MonoInst *mrgctx_loc, *mrgctx_var;
3504
3505                 g_assert (!this_ins);
3506                 g_assert (method->is_inflated && mono_method_get_context (method)->method_inst);
3507
3508                 mrgctx_loc = mono_get_vtable_var (cfg);
3509                 EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
3510
3511                 return mrgctx_var;
3512         } else if (method->flags & METHOD_ATTRIBUTE_STATIC || method->klass->valuetype) {
3513                 MonoInst *vtable_loc, *vtable_var;
3514
3515                 g_assert (!this_ins);
3516
3517                 vtable_loc = mono_get_vtable_var (cfg);
3518                 EMIT_NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
3519
3520                 if (method->is_inflated && mono_method_get_context (method)->method_inst) {
3521                         MonoInst *mrgctx_var = vtable_var;
3522                         int vtable_reg;
3523
3524                         vtable_reg = alloc_preg (cfg);
3525                         EMIT_NEW_LOAD_MEMBASE (cfg, vtable_var, OP_LOAD_MEMBASE, vtable_reg, mrgctx_var->dreg, MONO_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, class_vtable));
3526                         vtable_var->type = STACK_PTR;
3527                 }
3528
3529                 return vtable_var;
3530         } else {
3531                 MonoInst *ins;
3532                 int vtable_reg;
3533         
3534                 vtable_reg = alloc_preg (cfg);
3535                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, vtable_reg, this_ins->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3536                 return ins;
3537         }
3538 }
3539
3540 static MonoJumpInfoRgctxEntry *
3541 mono_patch_info_rgctx_entry_new (MonoMemPool *mp, MonoMethod *method, gboolean in_mrgctx, MonoJumpInfoType patch_type, gconstpointer patch_data, MonoRgctxInfoType info_type)
3542 {
3543         MonoJumpInfoRgctxEntry *res = (MonoJumpInfoRgctxEntry *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoRgctxEntry));
3544         res->method = method;
3545         res->in_mrgctx = in_mrgctx;
3546         res->data = (MonoJumpInfo *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
3547         res->data->type = patch_type;
3548         res->data->data.target = patch_data;
3549         res->info_type = info_type;
3550
3551         return res;
3552 }
3553
3554 static inline MonoInst*
3555 emit_rgctx_fetch_inline (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3556 {
3557         MonoInst *args [16];
3558         MonoInst *call;
3559
3560         // FIXME: No fastpath since the slot is not a compile time constant
3561         args [0] = rgctx;
3562         EMIT_NEW_AOTCONST (cfg, args [1], MONO_PATCH_INFO_RGCTX_SLOT_INDEX, entry);
3563         if (entry->in_mrgctx)
3564                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3565         else
3566                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3567         return call;
3568 #if 0
3569         /*
3570          * FIXME: This can be called during decompose, which is a problem since it creates
3571          * new bblocks.
3572          * Also, the fastpath doesn't work since the slot number is dynamically allocated.
3573          */
3574         int i, slot, depth, index, rgctx_reg, val_reg, res_reg;
3575         gboolean mrgctx;
3576         MonoBasicBlock *is_null_bb, *end_bb;
3577         MonoInst *res, *ins, *call;
3578         MonoInst *args[16];
3579
3580         slot = mini_get_rgctx_entry_slot (entry);
3581
3582         mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot);
3583         index = MONO_RGCTX_SLOT_INDEX (slot);
3584         if (mrgctx)
3585                 index += MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
3586         for (depth = 0; ; ++depth) {
3587                 int size = mono_class_rgctx_get_array_size (depth, mrgctx);
3588
3589                 if (index < size - 1)
3590                         break;
3591                 index -= size - 1;
3592         }
3593
3594         NEW_BBLOCK (cfg, end_bb);
3595         NEW_BBLOCK (cfg, is_null_bb);
3596
3597         if (mrgctx) {
3598                 rgctx_reg = rgctx->dreg;
3599         } else {
3600                 rgctx_reg = alloc_preg (cfg);
3601
3602                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, rgctx_reg, rgctx->dreg, MONO_STRUCT_OFFSET (MonoVTable, runtime_generic_context));
3603                 // FIXME: Avoid this check by allocating the table when the vtable is created etc.
3604                 NEW_BBLOCK (cfg, is_null_bb);
3605
3606                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3607                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3608         }
3609
3610         for (i = 0; i < depth; ++i) {
3611                 int array_reg = alloc_preg (cfg);
3612
3613                 /* load ptr to next array */
3614                 if (mrgctx && i == 0)
3615                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT);
3616                 else
3617                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, 0);
3618                 rgctx_reg = array_reg;
3619                 /* is the ptr null? */
3620                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3621                 /* if yes, jump to actual trampoline */
3622                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3623         }
3624
3625         /* fetch slot */
3626         val_reg = alloc_preg (cfg);
3627         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, val_reg, rgctx_reg, (index + 1) * sizeof (gpointer));
3628         /* is the slot null? */
3629         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, val_reg, 0);
3630         /* if yes, jump to actual trampoline */
3631         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3632
3633         /* Fastpath */
3634         res_reg = alloc_preg (cfg);
3635         MONO_INST_NEW (cfg, ins, OP_MOVE);
3636         ins->dreg = res_reg;
3637         ins->sreg1 = val_reg;
3638         MONO_ADD_INS (cfg->cbb, ins);
3639         res = ins;
3640         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3641
3642         /* Slowpath */
3643         MONO_START_BB (cfg, is_null_bb);
3644         args [0] = rgctx;
3645         EMIT_NEW_ICONST (cfg, args [1], index);
3646         if (mrgctx)
3647                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3648         else
3649                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3650         MONO_INST_NEW (cfg, ins, OP_MOVE);
3651         ins->dreg = res_reg;
3652         ins->sreg1 = call->dreg;
3653         MONO_ADD_INS (cfg->cbb, ins);
3654         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3655
3656         MONO_START_BB (cfg, end_bb);
3657
3658         return res;
3659 #endif
3660 }
3661
3662 /*
3663  * emit_rgctx_fetch:
3664  *
3665  *   Emit IR to load the value of the rgctx entry ENTRY from the rgctx
3666  * given by RGCTX.
3667  */
3668 static inline MonoInst*
3669 emit_rgctx_fetch (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3670 {
3671         if (cfg->llvm_only)
3672                 return emit_rgctx_fetch_inline (cfg, rgctx, entry);
3673         else
3674                 return mono_emit_abs_call (cfg, MONO_PATCH_INFO_RGCTX_FETCH, entry, helper_sig_rgctx_lazy_fetch_trampoline, &rgctx);
3675 }
3676
3677 static MonoInst*
3678 emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
3679                                           MonoClass *klass, MonoRgctxInfoType rgctx_type)
3680 {
3681         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);
3682         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3683
3684         return emit_rgctx_fetch (cfg, rgctx, entry);
3685 }
3686
3687 static MonoInst*
3688 emit_get_rgctx_sig (MonoCompile *cfg, int context_used,
3689                                         MonoMethodSignature *sig, MonoRgctxInfoType rgctx_type)
3690 {
3691         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);
3692         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3693
3694         return emit_rgctx_fetch (cfg, rgctx, entry);
3695 }
3696
3697 static MonoInst*
3698 emit_get_rgctx_gsharedvt_call (MonoCompile *cfg, int context_used,
3699                                                            MonoMethodSignature *sig, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3700 {
3701         MonoJumpInfoGSharedVtCall *call_info;
3702         MonoJumpInfoRgctxEntry *entry;
3703         MonoInst *rgctx;
3704
3705         call_info = (MonoJumpInfoGSharedVtCall *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoGSharedVtCall));
3706         call_info->sig = sig;
3707         call_info->method = cmethod;
3708
3709         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);
3710         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3711
3712         return emit_rgctx_fetch (cfg, rgctx, entry);
3713 }
3714
3715 /*
3716  * emit_get_rgctx_virt_method:
3717  *
3718  *   Return data for method VIRT_METHOD for a receiver of type KLASS.
3719  */
3720 static MonoInst*
3721 emit_get_rgctx_virt_method (MonoCompile *cfg, int context_used,
3722                                                         MonoClass *klass, MonoMethod *virt_method, MonoRgctxInfoType rgctx_type)
3723 {
3724         MonoJumpInfoVirtMethod *info;
3725         MonoJumpInfoRgctxEntry *entry;
3726         MonoInst *rgctx;
3727
3728         info = (MonoJumpInfoVirtMethod *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoVirtMethod));
3729         info->klass = klass;
3730         info->method = virt_method;
3731
3732         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);
3733         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3734
3735         return emit_rgctx_fetch (cfg, rgctx, entry);
3736 }
3737
3738 static MonoInst*
3739 emit_get_rgctx_gsharedvt_method (MonoCompile *cfg, int context_used,
3740                                                                  MonoMethod *cmethod, MonoGSharedVtMethodInfo *info)
3741 {
3742         MonoJumpInfoRgctxEntry *entry;
3743         MonoInst *rgctx;
3744
3745         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);
3746         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3747
3748         return emit_rgctx_fetch (cfg, rgctx, entry);
3749 }
3750
3751 /*
3752  * emit_get_rgctx_method:
3753  *
3754  *   Emit IR to load the property RGCTX_TYPE of CMETHOD. If context_used is 0, emit
3755  * normal constants, else emit a load from the rgctx.
3756  */
3757 static MonoInst*
3758 emit_get_rgctx_method (MonoCompile *cfg, int context_used,
3759                                            MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3760 {
3761         if (!context_used) {
3762                 MonoInst *ins;
3763
3764                 switch (rgctx_type) {
3765                 case MONO_RGCTX_INFO_METHOD:
3766                         EMIT_NEW_METHODCONST (cfg, ins, cmethod);
3767                         return ins;
3768                 case MONO_RGCTX_INFO_METHOD_RGCTX:
3769                         EMIT_NEW_METHOD_RGCTX_CONST (cfg, ins, cmethod);
3770                         return ins;
3771                 default:
3772                         g_assert_not_reached ();
3773                 }
3774         } else {
3775                 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);
3776                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3777
3778                 return emit_rgctx_fetch (cfg, rgctx, entry);
3779         }
3780 }
3781
3782 static MonoInst*
3783 emit_get_rgctx_field (MonoCompile *cfg, int context_used,
3784                                           MonoClassField *field, MonoRgctxInfoType rgctx_type)
3785 {
3786         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);
3787         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3788
3789         return emit_rgctx_fetch (cfg, rgctx, entry);
3790 }
3791
3792 static int
3793 get_gsharedvt_info_slot (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3794 {
3795         MonoGSharedVtMethodInfo *info = cfg->gsharedvt_info;
3796         MonoRuntimeGenericContextInfoTemplate *template_;
3797         int i, idx;
3798
3799         g_assert (info);
3800
3801         for (i = 0; i < info->num_entries; ++i) {
3802                 MonoRuntimeGenericContextInfoTemplate *otemplate = &info->entries [i];
3803
3804                 if (otemplate->info_type == rgctx_type && otemplate->data == data && rgctx_type != MONO_RGCTX_INFO_LOCAL_OFFSET)
3805                         return i;
3806         }
3807
3808         if (info->num_entries == info->count_entries) {
3809                 MonoRuntimeGenericContextInfoTemplate *new_entries;
3810                 int new_count_entries = info->count_entries ? info->count_entries * 2 : 16;
3811
3812                 new_entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * new_count_entries);
3813
3814                 memcpy (new_entries, info->entries, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
3815                 info->entries = new_entries;
3816                 info->count_entries = new_count_entries;
3817         }
3818
3819         idx = info->num_entries;
3820         template_ = &info->entries [idx];
3821         template_->info_type = rgctx_type;
3822         template_->data = data;
3823
3824         info->num_entries ++;
3825
3826         return idx;
3827 }
3828
3829 /*
3830  * emit_get_gsharedvt_info:
3831  *
3832  *   This is similar to emit_get_rgctx_.., but loads the data from the gsharedvt info var instead of calling an rgctx fetch trampoline.
3833  */
3834 static MonoInst*
3835 emit_get_gsharedvt_info (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3836 {
3837         MonoInst *ins;
3838         int idx, dreg;
3839
3840         idx = get_gsharedvt_info_slot (cfg, data, rgctx_type);
3841         /* Load info->entries [idx] */
3842         dreg = alloc_preg (cfg);
3843         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, cfg->gsharedvt_info_var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
3844
3845         return ins;
3846 }
3847
3848 static MonoInst*
3849 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type)
3850 {
3851         return emit_get_gsharedvt_info (cfg, &klass->byval_arg, rgctx_type);
3852 }
3853
3854 /*
3855  * On return the caller must check @klass for load errors.
3856  */
3857 static void
3858 emit_class_init (MonoCompile *cfg, MonoClass *klass)
3859 {
3860         MonoInst *vtable_arg;
3861         int context_used;
3862
3863         context_used = mini_class_check_context_used (cfg, klass);
3864
3865         if (context_used) {
3866                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
3867                                                                                    klass, MONO_RGCTX_INFO_VTABLE);
3868         } else {
3869                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3870
3871                 if (!vtable)
3872                         return;
3873                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
3874         }
3875
3876         if (!COMPILE_LLVM (cfg) && cfg->backend->have_op_generic_class_init) {
3877                 MonoInst *ins;
3878
3879                 /*
3880                  * Using an opcode instead of emitting IR here allows the hiding of the call inside the opcode,
3881                  * so this doesn't have to clobber any regs and it doesn't break basic blocks.
3882                  */
3883                 MONO_INST_NEW (cfg, ins, OP_GENERIC_CLASS_INIT);
3884                 ins->sreg1 = vtable_arg->dreg;
3885                 MONO_ADD_INS (cfg->cbb, ins);
3886         } else {
3887                 static int byte_offset = -1;
3888                 static guint8 bitmask;
3889                 int bits_reg, inited_reg;
3890                 MonoBasicBlock *inited_bb;
3891                 MonoInst *args [16];
3892
3893                 if (byte_offset < 0)
3894                         mono_marshal_find_bitfield_offset (MonoVTable, initialized, &byte_offset, &bitmask);
3895
3896                 bits_reg = alloc_ireg (cfg);
3897                 inited_reg = alloc_ireg (cfg);
3898
3899                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, bits_reg, vtable_arg->dreg, byte_offset);
3900                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, inited_reg, bits_reg, bitmask);
3901
3902                 NEW_BBLOCK (cfg, inited_bb);
3903
3904                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, inited_reg, 0);
3905                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, inited_bb);
3906
3907                 args [0] = vtable_arg;
3908                 mono_emit_jit_icall (cfg, mono_generic_class_init, args);
3909
3910                 MONO_START_BB (cfg, inited_bb);
3911         }
3912 }
3913
3914 static void
3915 emit_seq_point (MonoCompile *cfg, MonoMethod *method, guint8* ip, gboolean intr_loc, gboolean nonempty_stack)
3916 {
3917         MonoInst *ins;
3918
3919         if (cfg->gen_seq_points && cfg->method == method) {
3920                 NEW_SEQ_POINT (cfg, ins, ip - cfg->header->code, intr_loc);
3921                 if (nonempty_stack)
3922                         ins->flags |= MONO_INST_NONEMPTY_STACK;
3923                 MONO_ADD_INS (cfg->cbb, ins);
3924         }
3925 }
3926
3927 static void
3928 save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean null_check)
3929 {
3930         if (mini_get_debug_options ()->better_cast_details) {
3931                 int vtable_reg = alloc_preg (cfg);
3932                 int klass_reg = alloc_preg (cfg);
3933                 MonoBasicBlock *is_null_bb = NULL;
3934                 MonoInst *tls_get;
3935                 int to_klass_reg, context_used;
3936
3937                 if (null_check) {
3938                         NEW_BBLOCK (cfg, is_null_bb);
3939
3940                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3941                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3942                 }
3943
3944                 tls_get = mono_get_jit_tls_intrinsic (cfg);
3945                 if (!tls_get) {
3946                         fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
3947                         exit (1);
3948                 }
3949
3950                 MONO_ADD_INS (cfg->cbb, tls_get);
3951                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3952                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3953
3954                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg);
3955
3956                 context_used = mini_class_check_context_used (cfg, klass);
3957                 if (context_used) {
3958                         MonoInst *class_ins;
3959
3960                         class_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3961                         to_klass_reg = class_ins->dreg;
3962                 } else {
3963                         to_klass_reg = alloc_preg (cfg);
3964                         MONO_EMIT_NEW_CLASSCONST (cfg, to_klass_reg, klass);
3965                 }
3966                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg);
3967
3968                 if (null_check)
3969                         MONO_START_BB (cfg, is_null_bb);
3970         }
3971 }
3972
3973 static void
3974 reset_cast_details (MonoCompile *cfg)
3975 {
3976         /* Reset the variables holding the cast details */
3977         if (mini_get_debug_options ()->better_cast_details) {
3978                 MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
3979
3980                 MONO_ADD_INS (cfg->cbb, tls_get);
3981                 /* It is enough to reset the from field */
3982                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0);
3983         }
3984 }
3985
3986 /*
3987  * On return the caller must check @array_class for load errors
3988  */
3989 static void
3990 mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_class)
3991 {
3992         int vtable_reg = alloc_preg (cfg);
3993         int context_used;
3994
3995         context_used = mini_class_check_context_used (cfg, array_class);
3996
3997         save_cast_details (cfg, array_class, obj->dreg, FALSE);
3998
3999         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4000
4001         if (cfg->opt & MONO_OPT_SHARED) {
4002                 int class_reg = alloc_preg (cfg);
4003                 MonoInst *ins;
4004
4005                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, class_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4006                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, array_class);
4007                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, class_reg, ins->dreg);
4008         } else if (context_used) {
4009                 MonoInst *vtable_ins;
4010
4011                 vtable_ins = emit_get_rgctx_klass (cfg, context_used, array_class, MONO_RGCTX_INFO_VTABLE);
4012                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vtable_ins->dreg);
4013         } else {
4014                 if (cfg->compile_aot) {
4015                         int vt_reg;
4016                         MonoVTable *vtable;
4017
4018                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
4019                                 return;
4020                         vt_reg = alloc_preg (cfg);
4021                         MONO_EMIT_NEW_VTABLECONST (cfg, vt_reg, vtable);
4022                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vt_reg);
4023                 } else {
4024                         MonoVTable *vtable;
4025                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
4026                                 return;
4027                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vtable);
4028                 }
4029         }
4030         
4031         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException");
4032
4033         reset_cast_details (cfg);
4034 }
4035
4036 /**
4037  * Handles unbox of a Nullable<T>. If context_used is non zero, then shared 
4038  * generic code is generated.
4039  */
4040 static MonoInst*
4041 handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int context_used)
4042 {
4043         MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
4044
4045         if (context_used) {
4046                 MonoInst *rgctx, *addr;
4047
4048                 /* FIXME: What if the class is shared?  We might not
4049                    have to get the address of the method from the
4050                    RGCTX. */
4051                 addr = emit_get_rgctx_method (cfg, context_used, method,
4052                                                                           MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4053                 if (cfg->llvm_only) {
4054                         cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, mono_method_signature (method));
4055                         return emit_llvmonly_calli (cfg, mono_method_signature (method), &val, addr);
4056                 } else {
4057                         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
4058
4059                         return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
4060                 }
4061         } else {
4062                 gboolean pass_vtable, pass_mrgctx;
4063                 MonoInst *rgctx_arg = NULL;
4064
4065                 check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
4066                 g_assert (!pass_mrgctx);
4067
4068                 if (pass_vtable) {
4069                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4070
4071                         g_assert (vtable);
4072                         EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
4073                 }
4074
4075                 return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4076         }
4077 }
4078
4079 static MonoInst*
4080 handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_used)
4081 {
4082         MonoInst *add;
4083         int obj_reg;
4084         int vtable_reg = alloc_dreg (cfg ,STACK_PTR);
4085         int klass_reg = alloc_dreg (cfg ,STACK_PTR);
4086         int eclass_reg = alloc_dreg (cfg ,STACK_PTR);
4087         int rank_reg = alloc_dreg (cfg ,STACK_I4);
4088
4089         obj_reg = sp [0]->dreg;
4090         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4091         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
4092
4093         /* FIXME: generics */
4094         g_assert (klass->rank == 0);
4095                         
4096         // Check rank == 0
4097         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, 0);
4098         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4099
4100         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4101         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, element_class));
4102
4103         if (context_used) {
4104                 MonoInst *element_class;
4105
4106                 /* This assertion is from the unboxcast insn */
4107                 g_assert (klass->rank == 0);
4108
4109                 element_class = emit_get_rgctx_klass (cfg, context_used,
4110                                 klass, MONO_RGCTX_INFO_ELEMENT_KLASS);
4111
4112                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, eclass_reg, element_class->dreg);
4113                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4114         } else {
4115                 save_cast_details (cfg, klass->element_class, obj_reg, FALSE);
4116                 mini_emit_class_check (cfg, eclass_reg, klass->element_class);
4117                 reset_cast_details (cfg);
4118         }
4119
4120         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), obj_reg, sizeof (MonoObject));
4121         MONO_ADD_INS (cfg->cbb, add);
4122         add->type = STACK_MP;
4123         add->klass = klass;
4124
4125         return add;
4126 }
4127
4128 static MonoInst*
4129 handle_unbox_gsharedvt (MonoCompile *cfg, MonoClass *klass, MonoInst *obj)
4130 {
4131         MonoInst *addr, *klass_inst, *is_ref, *args[16];
4132         MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4133         MonoInst *ins;
4134         int dreg, addr_reg;
4135
4136         klass_inst = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_KLASS);
4137
4138         /* obj */
4139         args [0] = obj;
4140
4141         /* klass */
4142         args [1] = klass_inst;
4143
4144         /* CASTCLASS */
4145         obj = mono_emit_jit_icall (cfg, mono_object_castclass_unbox, args);
4146
4147         NEW_BBLOCK (cfg, is_ref_bb);
4148         NEW_BBLOCK (cfg, is_nullable_bb);
4149         NEW_BBLOCK (cfg, end_bb);
4150         is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4151         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
4152         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4153
4154         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
4155         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4156
4157         /* This will contain either the address of the unboxed vtype, or an address of the temporary where the ref is stored */
4158         addr_reg = alloc_dreg (cfg, STACK_MP);
4159
4160         /* Non-ref case */
4161         /* UNBOX */
4162         NEW_BIALU_IMM (cfg, addr, OP_ADD_IMM, addr_reg, obj->dreg, sizeof (MonoObject));
4163         MONO_ADD_INS (cfg->cbb, addr);
4164
4165         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4166
4167         /* Ref case */
4168         MONO_START_BB (cfg, is_ref_bb);
4169
4170         /* Save the ref to a temporary */
4171         dreg = alloc_ireg (cfg);
4172         EMIT_NEW_VARLOADA_VREG (cfg, addr, dreg, &klass->byval_arg);
4173         addr->dreg = addr_reg;
4174         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, obj->dreg);
4175         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4176
4177         /* Nullable case */
4178         MONO_START_BB (cfg, is_nullable_bb);
4179
4180         {
4181                 MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX);
4182                 MonoInst *unbox_call;
4183                 MonoMethodSignature *unbox_sig;
4184
4185                 unbox_sig = (MonoMethodSignature *)mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4186                 unbox_sig->ret = &klass->byval_arg;
4187                 unbox_sig->param_count = 1;
4188                 unbox_sig->params [0] = &mono_defaults.object_class->byval_arg;
4189
4190                 if (cfg->llvm_only)
4191                         unbox_call = emit_llvmonly_calli (cfg, unbox_sig, &obj, addr);
4192                 else
4193                         unbox_call = mono_emit_calli (cfg, unbox_sig, &obj, addr, NULL, NULL);
4194
4195                 EMIT_NEW_VARLOADA_VREG (cfg, addr, unbox_call->dreg, &klass->byval_arg);
4196                 addr->dreg = addr_reg;
4197         }
4198
4199         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4200
4201         /* End */
4202         MONO_START_BB (cfg, end_bb);
4203
4204         /* LDOBJ */
4205         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr_reg, 0);
4206
4207         return ins;
4208 }
4209
4210 /*
4211  * Returns NULL and set the cfg exception on error.
4212  */
4213 static MonoInst*
4214 handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_used)
4215 {
4216         MonoInst *iargs [2];
4217         void *alloc_ftn;
4218
4219         if (context_used) {
4220                 MonoInst *data;
4221                 MonoRgctxInfoType rgctx_info;
4222                 MonoInst *iargs [2];
4223                 gboolean known_instance_size = !mini_is_gsharedvt_klass (klass);
4224
4225                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (klass, for_box, known_instance_size);
4226
4227                 if (cfg->opt & MONO_OPT_SHARED)
4228                         rgctx_info = MONO_RGCTX_INFO_KLASS;
4229                 else
4230                         rgctx_info = MONO_RGCTX_INFO_VTABLE;
4231                 data = emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
4232
4233                 if (cfg->opt & MONO_OPT_SHARED) {
4234                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4235                         iargs [1] = data;
4236                         alloc_ftn = ves_icall_object_new;
4237                 } else {
4238                         iargs [0] = data;
4239                         alloc_ftn = ves_icall_object_new_specific;
4240                 }
4241
4242                 if (managed_alloc && !(cfg->opt & MONO_OPT_SHARED)) {
4243                         if (known_instance_size) {
4244                                 int size = mono_class_instance_size (klass);
4245                                 if (size < sizeof (MonoObject))
4246                                         g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4247
4248                                 EMIT_NEW_ICONST (cfg, iargs [1], size);
4249                         }
4250                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4251                 }
4252
4253                 return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4254         }
4255
4256         if (cfg->opt & MONO_OPT_SHARED) {
4257                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4258                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
4259
4260                 alloc_ftn = ves_icall_object_new;
4261         } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !klass->generic_class) {
4262                 /* This happens often in argument checking code, eg. throw new FooException... */
4263                 /* Avoid relocations and save some space by calling a helper function specialized to mscorlib */
4264                 EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
4265                 return mono_emit_jit_icall (cfg, mono_helper_newobj_mscorlib, iargs);
4266         } else {
4267                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
4268                 MonoMethod *managed_alloc = NULL;
4269                 gboolean pass_lw;
4270
4271                 if (!vtable) {
4272                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4273                         cfg->exception_ptr = klass;
4274                         return NULL;
4275                 }
4276
4277                 managed_alloc = mono_gc_get_managed_allocator (klass, for_box, TRUE);
4278
4279                 if (managed_alloc) {
4280                         int size = mono_class_instance_size (klass);
4281                         if (size < sizeof (MonoObject))
4282                                 g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4283
4284                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4285                         EMIT_NEW_ICONST (cfg, iargs [1], size);
4286                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4287                 }
4288                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
4289                 if (pass_lw) {
4290                         guint32 lw = vtable->klass->instance_size;
4291                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
4292                         EMIT_NEW_ICONST (cfg, iargs [0], lw);
4293                         EMIT_NEW_VTABLECONST (cfg, iargs [1], vtable);
4294                 }
4295                 else {
4296                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4297                 }
4298         }
4299
4300         return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4301 }
4302         
4303 /*
4304  * Returns NULL and set the cfg exception on error.
4305  */     
4306 static MonoInst*
4307 handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used)
4308 {
4309         MonoInst *alloc, *ins;
4310
4311         if (mono_class_is_nullable (klass)) {
4312                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
4313
4314                 if (context_used) {
4315                         if (cfg->llvm_only && cfg->gsharedvt) {
4316                                 MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4317                                                                                                                 MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4318                                 return emit_llvmonly_calli (cfg, mono_method_signature (method), &val, addr);
4319                         } else {
4320                                 /* FIXME: What if the class is shared?  We might not
4321                                    have to get the method address from the RGCTX. */
4322                                 MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4323                                                                                                                 MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4324                                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
4325
4326                                 return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
4327                         }
4328                 } else {
4329                         gboolean pass_vtable, pass_mrgctx;
4330                         MonoInst *rgctx_arg = NULL;
4331
4332                         check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
4333                         g_assert (!pass_mrgctx);
4334
4335                         if (pass_vtable) {
4336                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4337
4338                                 g_assert (vtable);
4339                                 EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
4340                         }
4341
4342                         return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4343                 }
4344         }
4345
4346         if (mini_is_gsharedvt_klass (klass)) {
4347                 MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4348                 MonoInst *res, *is_ref, *src_var, *addr;
4349                 int dreg;
4350
4351                 dreg = alloc_ireg (cfg);
4352
4353                 NEW_BBLOCK (cfg, is_ref_bb);
4354                 NEW_BBLOCK (cfg, is_nullable_bb);
4355                 NEW_BBLOCK (cfg, end_bb);
4356                 is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4357                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
4358                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4359
4360                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
4361                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4362
4363                 /* Non-ref case */
4364                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4365                 if (!alloc)
4366                         return NULL;
4367                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4368                 ins->opcode = OP_STOREV_MEMBASE;
4369
4370                 EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, alloc->dreg);
4371                 res->type = STACK_OBJ;
4372                 res->klass = klass;
4373                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4374                 
4375                 /* Ref case */
4376                 MONO_START_BB (cfg, is_ref_bb);
4377
4378                 /* val is a vtype, so has to load the value manually */
4379                 src_var = get_vreg_to_inst (cfg, val->dreg);
4380                 if (!src_var)
4381                         src_var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, val->dreg);
4382                 EMIT_NEW_VARLOADA (cfg, addr, src_var, src_var->inst_vtype);
4383                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, addr->dreg, 0);
4384                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4385
4386                 /* Nullable case */
4387                 MONO_START_BB (cfg, is_nullable_bb);
4388
4389                 {
4390                         MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass,
4391                                                                                                         MONO_RGCTX_INFO_NULLABLE_CLASS_BOX);
4392                         MonoInst *box_call;
4393                         MonoMethodSignature *box_sig;
4394
4395                         /*
4396                          * klass is Nullable<T>, need to call Nullable<T>.Box () using a gsharedvt signature, but we cannot
4397                          * construct that method at JIT time, so have to do things by hand.
4398                          */
4399                         box_sig = (MonoMethodSignature *)mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4400                         box_sig->ret = &mono_defaults.object_class->byval_arg;
4401                         box_sig->param_count = 1;
4402                         box_sig->params [0] = &klass->byval_arg;
4403
4404                         if (cfg->llvm_only)
4405                                 box_call = emit_llvmonly_calli (cfg, box_sig, &val, addr);
4406                         else
4407                                 box_call = mono_emit_calli (cfg, box_sig, &val, addr, NULL, NULL);
4408                         EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, box_call->dreg);
4409                         res->type = STACK_OBJ;
4410                         res->klass = klass;
4411                 }
4412
4413                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4414
4415                 MONO_START_BB (cfg, end_bb);
4416
4417                 return res;
4418         } else {
4419                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4420                 if (!alloc)
4421                         return NULL;
4422
4423                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4424                 return alloc;
4425         }
4426 }
4427
4428 static gboolean
4429 mini_class_has_reference_variant_generic_argument (MonoCompile *cfg, MonoClass *klass, int context_used)
4430 {
4431         int i;
4432         MonoGenericContainer *container;
4433         MonoGenericInst *ginst;
4434
4435         if (klass->generic_class) {
4436                 container = klass->generic_class->container_class->generic_container;
4437                 ginst = klass->generic_class->context.class_inst;
4438         } else if (klass->generic_container && context_used) {
4439                 container = klass->generic_container;
4440                 ginst = container->context.class_inst;
4441         } else {
4442                 return FALSE;
4443         }
4444
4445         for (i = 0; i < container->type_argc; ++i) {
4446                 MonoType *type;
4447                 if (!(mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT)))
4448                         continue;
4449                 type = ginst->type_argv [i];
4450                 if (mini_type_is_reference (type))
4451                         return TRUE;
4452         }
4453         return FALSE;
4454 }
4455
4456 static GHashTable* direct_icall_type_hash;
4457
4458 static gboolean
4459 icall_is_direct_callable (MonoCompile *cfg, MonoMethod *cmethod)
4460 {
4461         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
4462         if (!direct_icalls_enabled (cfg))
4463                 return FALSE;
4464
4465         /*
4466          * An icall is directly callable if it doesn't directly or indirectly call mono_raise_exception ().
4467          * Whitelist a few icalls for now.
4468          */
4469         if (!direct_icall_type_hash) {
4470                 GHashTable *h = g_hash_table_new (g_str_hash, g_str_equal);
4471
4472                 g_hash_table_insert (h, (char*)"Decimal", GUINT_TO_POINTER (1));
4473                 g_hash_table_insert (h, (char*)"Number", GUINT_TO_POINTER (1));
4474                 g_hash_table_insert (h, (char*)"Buffer", GUINT_TO_POINTER (1));
4475                 g_hash_table_insert (h, (char*)"Monitor", GUINT_TO_POINTER (1));
4476                 mono_memory_barrier ();
4477                 direct_icall_type_hash = h;
4478         }
4479
4480         if (cmethod->klass == mono_defaults.math_class)
4481                 return TRUE;
4482         /* No locking needed */
4483         if (cmethod->klass->image == mono_defaults.corlib && g_hash_table_lookup (direct_icall_type_hash, cmethod->klass->name))
4484                 return TRUE;
4485         return FALSE;
4486 }
4487
4488 static gboolean
4489 method_needs_stack_walk (MonoCompile *cfg, MonoMethod *cmethod)
4490 {
4491         if (cmethod->klass == mono_defaults.systemtype_class) {
4492                 if (!strcmp (cmethod->name, "GetType"))
4493                         return TRUE;
4494         }
4495         return FALSE;
4496 }
4497
4498 #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)
4499
4500 static MonoInst*
4501 emit_isinst_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args)
4502 {
4503         MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
4504         return mono_emit_method_call (cfg, mono_isinst, args, NULL);
4505 }
4506
4507 static MonoInst*
4508 emit_castclass_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args)
4509 {
4510         MonoMethod *mono_castclass = mono_marshal_get_castclass_with_cache ();
4511         MonoInst *res;
4512
4513         save_cast_details (cfg, klass, args [0]->dreg, TRUE);
4514         res = mono_emit_method_call (cfg, mono_castclass, args, NULL);
4515         reset_cast_details (cfg);
4516
4517         return res;
4518 }
4519
4520 static int
4521 get_castclass_cache_idx (MonoCompile *cfg)
4522 {
4523         /* Each CASTCLASS_CACHE patch needs a unique index which identifies the call site */
4524         cfg->castclass_cache_index ++;
4525         return (cfg->method_index << 16) | cfg->castclass_cache_index;
4526 }
4527
4528
4529 static MonoInst*
4530 emit_isinst_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass *klass)
4531 {
4532         MonoInst *args [3];
4533         int idx;
4534
4535         args [0] = obj; /* obj */
4536         EMIT_NEW_CLASSCONST (cfg, args [1], klass); /* klass */
4537
4538         idx = get_castclass_cache_idx (cfg); /* inline cache*/
4539         args [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
4540
4541         return emit_isinst_with_cache (cfg, klass, args);
4542 }
4543
4544 static MonoInst*
4545 emit_castclass_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass *klass)
4546 {
4547         MonoInst *args [3];
4548         int idx;
4549
4550         /* obj */
4551         args [0] = obj;
4552
4553         /* klass */
4554         EMIT_NEW_CLASSCONST (cfg, args [1], klass);
4555
4556         /* inline cache*/
4557         idx = get_castclass_cache_idx (cfg);
4558         args [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
4559
4560         /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
4561         return emit_castclass_with_cache (cfg, klass, args);
4562 }
4563
4564 /*
4565  * Returns NULL and set the cfg exception on error.
4566  */
4567 static MonoInst*
4568 handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
4569 {
4570         MonoBasicBlock *is_null_bb;
4571         int obj_reg = src->dreg;
4572         int vtable_reg = alloc_preg (cfg);
4573         MonoInst *klass_inst = NULL;
4574
4575         if (src->opcode == OP_PCONST && src->inst_p0 == 0)
4576                 return src;
4577
4578         if (context_used) {
4579                 MonoInst *args [3];
4580
4581                 if (mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4582                         MonoInst *cache_ins;
4583
4584                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4585
4586                         /* obj */
4587                         args [0] = src;
4588
4589                         /* klass - it's the second element of the cache entry*/
4590                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4591
4592                         /* cache */
4593                         args [2] = cache_ins;
4594
4595                         return emit_castclass_with_cache (cfg, klass, args);
4596                 }
4597
4598                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4599         }
4600
4601         NEW_BBLOCK (cfg, is_null_bb);
4602
4603         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4604         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
4605
4606         save_cast_details (cfg, klass, obj_reg, FALSE);
4607
4608         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4609                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4610                 mini_emit_iface_cast (cfg, vtable_reg, klass, NULL, NULL);
4611         } else {
4612                 int klass_reg = alloc_preg (cfg);
4613
4614                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4615
4616                 if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4617                         /* the remoting code is broken, access the class for now */
4618                         if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4619                                 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4620                                 if (!vt) {
4621                                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4622                                         cfg->exception_ptr = klass;
4623                                         return NULL;
4624                                 }
4625                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4626                         } else {
4627                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4628                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4629                         }
4630                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4631                 } else {
4632                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4633                         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, klass_inst, is_null_bb);
4634                 }
4635         }
4636
4637         MONO_START_BB (cfg, is_null_bb);
4638
4639         reset_cast_details (cfg);
4640
4641         return src;
4642 }
4643
4644 /*
4645  * Returns NULL and set the cfg exception on error.
4646  */
4647 static MonoInst*
4648 handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
4649 {
4650         MonoInst *ins;
4651         MonoBasicBlock *is_null_bb, *false_bb, *end_bb;
4652         int obj_reg = src->dreg;
4653         int vtable_reg = alloc_preg (cfg);
4654         int res_reg = alloc_ireg_ref (cfg);
4655         MonoInst *klass_inst = NULL;
4656
4657         if (context_used) {
4658                 MonoInst *args [3];
4659
4660                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4661                         MonoInst *cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4662
4663                         args [0] = src; /* obj */
4664
4665                         /* klass - it's the second element of the cache entry*/
4666                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4667
4668                         args [2] = cache_ins; /* cache */
4669                         return emit_isinst_with_cache (cfg, klass, args);
4670                 }
4671
4672                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4673         }
4674
4675         NEW_BBLOCK (cfg, is_null_bb);
4676         NEW_BBLOCK (cfg, false_bb);
4677         NEW_BBLOCK (cfg, end_bb);
4678
4679         /* Do the assignment at the beginning, so the other assignment can be if converted */
4680         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, res_reg, obj_reg);
4681         ins->type = STACK_OBJ;
4682         ins->klass = klass;
4683
4684         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4685         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_null_bb);
4686
4687         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4688
4689         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4690                 g_assert (!context_used);
4691                 /* the is_null_bb target simply copies the input register to the output */
4692                 mini_emit_iface_cast (cfg, vtable_reg, klass, false_bb, is_null_bb);
4693         } else {
4694                 int klass_reg = alloc_preg (cfg);
4695
4696                 if (klass->rank) {
4697                         int rank_reg = alloc_preg (cfg);
4698                         int eclass_reg = alloc_preg (cfg);
4699
4700                         g_assert (!context_used);
4701                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
4702                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
4703                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4704                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4705                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
4706                         if (klass->cast_class == mono_defaults.object_class) {
4707                                 int parent_reg = alloc_preg (cfg);
4708                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
4709                                 mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, is_null_bb);
4710                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4711                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4712                         } else if (klass->cast_class == mono_defaults.enum_class->parent) {
4713                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, is_null_bb);
4714                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);                          
4715                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4716                         } else if (klass->cast_class == mono_defaults.enum_class) {
4717                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4718                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4719                         } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
4720                                 mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4721                         } else {
4722                                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY)) {
4723                                         /* Check that the object is a vector too */
4724                                         int bounds_reg = alloc_preg (cfg);
4725                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
4726                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
4727                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4728                                 }
4729
4730                                 /* the is_null_bb target simply copies the input register to the output */
4731                                 mini_emit_isninst_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4732                         }
4733                 } else if (mono_class_is_nullable (klass)) {
4734                         g_assert (!context_used);
4735                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4736                         /* the is_null_bb target simply copies the input register to the output */
4737                         mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb);
4738                 } else {
4739                         if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4740                                 g_assert (!context_used);
4741                                 /* the remoting code is broken, access the class for now */
4742                                 if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4743                                         MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4744                                         if (!vt) {
4745                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4746                                                 cfg->exception_ptr = klass;
4747                                                 return NULL;
4748                                         }
4749                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4750                                 } else {
4751                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4752                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4753                                 }
4754                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4755                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
4756                         } else {
4757                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4758                                 /* the is_null_bb target simply copies the input register to the output */
4759                                 mini_emit_isninst_cast_inst (cfg, klass_reg, klass, klass_inst, false_bb, is_null_bb);
4760                         }
4761                 }
4762         }
4763
4764         MONO_START_BB (cfg, false_bb);
4765
4766         MONO_EMIT_NEW_PCONST (cfg, res_reg, 0);
4767         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4768
4769         MONO_START_BB (cfg, is_null_bb);
4770
4771         MONO_START_BB (cfg, end_bb);
4772
4773         return ins;
4774 }
4775
4776 static MonoInst*
4777 handle_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4778 {
4779         /* This opcode takes as input an object reference and a class, and returns:
4780         0) if the object is an instance of the class,
4781         1) if the object is not instance of the class,
4782         2) if the object is a proxy whose type cannot be determined */
4783
4784         MonoInst *ins;
4785 #ifndef DISABLE_REMOTING
4786         MonoBasicBlock *true_bb, *false_bb, *false2_bb, *end_bb, *no_proxy_bb, *interface_fail_bb;
4787 #else
4788         MonoBasicBlock *true_bb, *false_bb, *end_bb;
4789 #endif
4790         int obj_reg = src->dreg;
4791         int dreg = alloc_ireg (cfg);
4792         int tmp_reg;
4793 #ifndef DISABLE_REMOTING
4794         int klass_reg = alloc_preg (cfg);
4795 #endif
4796
4797         NEW_BBLOCK (cfg, true_bb);
4798         NEW_BBLOCK (cfg, false_bb);
4799         NEW_BBLOCK (cfg, end_bb);
4800 #ifndef DISABLE_REMOTING
4801         NEW_BBLOCK (cfg, false2_bb);
4802         NEW_BBLOCK (cfg, no_proxy_bb);
4803 #endif
4804
4805         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4806         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
4807
4808         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4809 #ifndef DISABLE_REMOTING
4810                 NEW_BBLOCK (cfg, interface_fail_bb);
4811 #endif
4812
4813                 tmp_reg = alloc_preg (cfg);
4814                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4815 #ifndef DISABLE_REMOTING
4816                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, true_bb);
4817                 MONO_START_BB (cfg, interface_fail_bb);
4818                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4819                 
4820                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, false_bb);
4821
4822                 tmp_reg = alloc_preg (cfg);
4823                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4824                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4825                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false2_bb);                
4826 #else
4827                 mini_emit_iface_cast (cfg, tmp_reg, klass, false_bb, true_bb);
4828 #endif
4829         } else {
4830 #ifndef DISABLE_REMOTING
4831                 tmp_reg = alloc_preg (cfg);
4832                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4833                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4834
4835                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4836                 tmp_reg = alloc_preg (cfg);
4837                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4838                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4839
4840                 tmp_reg = alloc_preg (cfg);             
4841                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4842                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4843                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4844                 
4845                 mini_emit_isninst_cast (cfg, klass_reg, klass, false2_bb, true_bb);
4846                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false2_bb);
4847
4848                 MONO_START_BB (cfg, no_proxy_bb);
4849
4850                 mini_emit_isninst_cast (cfg, klass_reg, klass, false_bb, true_bb);
4851 #else
4852                 g_error ("transparent proxy support is disabled while trying to JIT code that uses it");
4853 #endif
4854         }
4855
4856         MONO_START_BB (cfg, false_bb);
4857
4858         MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4859         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4860
4861 #ifndef DISABLE_REMOTING
4862         MONO_START_BB (cfg, false2_bb);
4863
4864         MONO_EMIT_NEW_ICONST (cfg, dreg, 2);
4865         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4866 #endif
4867
4868         MONO_START_BB (cfg, true_bb);
4869
4870         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4871
4872         MONO_START_BB (cfg, end_bb);
4873
4874         /* FIXME: */
4875         MONO_INST_NEW (cfg, ins, OP_ICONST);
4876         ins->dreg = dreg;
4877         ins->type = STACK_I4;
4878
4879         return ins;
4880 }
4881
4882 static MonoInst*
4883 handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4884 {
4885         /* This opcode takes as input an object reference and a class, and returns:
4886         0) if the object is an instance of the class,
4887         1) if the object is a proxy whose type cannot be determined
4888         an InvalidCastException exception is thrown otherwhise*/
4889         
4890         MonoInst *ins;
4891 #ifndef DISABLE_REMOTING
4892         MonoBasicBlock *end_bb, *ok_result_bb, *no_proxy_bb, *interface_fail_bb, *fail_1_bb;
4893 #else
4894         MonoBasicBlock *ok_result_bb;
4895 #endif
4896         int obj_reg = src->dreg;
4897         int dreg = alloc_ireg (cfg);
4898         int tmp_reg = alloc_preg (cfg);
4899
4900 #ifndef DISABLE_REMOTING
4901         int klass_reg = alloc_preg (cfg);
4902         NEW_BBLOCK (cfg, end_bb);
4903 #endif
4904
4905         NEW_BBLOCK (cfg, ok_result_bb);
4906
4907         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4908         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, ok_result_bb);
4909
4910         save_cast_details (cfg, klass, obj_reg, FALSE);
4911
4912         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4913 #ifndef DISABLE_REMOTING
4914                 NEW_BBLOCK (cfg, interface_fail_bb);
4915         
4916                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4917                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, ok_result_bb);
4918                 MONO_START_BB (cfg, interface_fail_bb);
4919                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4920
4921                 mini_emit_class_check (cfg, klass_reg, mono_defaults.transparent_proxy_class);
4922
4923                 tmp_reg = alloc_preg (cfg);             
4924                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4925                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4926                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
4927                 
4928                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4929                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4930 #else
4931                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4932                 mini_emit_iface_cast (cfg, tmp_reg, klass, NULL, NULL);
4933                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, ok_result_bb);
4934 #endif
4935         } else {
4936 #ifndef DISABLE_REMOTING
4937                 NEW_BBLOCK (cfg, no_proxy_bb);
4938
4939                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4940                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4941                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4942
4943                 tmp_reg = alloc_preg (cfg);
4944                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4945                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4946
4947                 tmp_reg = alloc_preg (cfg);
4948                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4949                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4950                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4951
4952                 NEW_BBLOCK (cfg, fail_1_bb);
4953                 
4954                 mini_emit_isninst_cast (cfg, klass_reg, klass, fail_1_bb, ok_result_bb);
4955
4956                 MONO_START_BB (cfg, fail_1_bb);
4957
4958                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4959                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4960
4961                 MONO_START_BB (cfg, no_proxy_bb);
4962
4963                 mini_emit_castclass (cfg, obj_reg, klass_reg, klass, ok_result_bb);
4964 #else
4965                 g_error ("Transparent proxy support is disabled while trying to JIT code that uses it");
4966 #endif
4967         }
4968
4969         MONO_START_BB (cfg, ok_result_bb);
4970
4971         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4972
4973 #ifndef DISABLE_REMOTING
4974         MONO_START_BB (cfg, end_bb);
4975 #endif
4976
4977         /* FIXME: */
4978         MONO_INST_NEW (cfg, ins, OP_ICONST);
4979         ins->dreg = dreg;
4980         ins->type = STACK_I4;
4981
4982         return ins;
4983 }
4984
4985 static G_GNUC_UNUSED MonoInst*
4986 handle_enum_has_flag (MonoCompile *cfg, MonoClass *klass, MonoInst *enum_this, MonoInst *enum_flag)
4987 {
4988         MonoType *enum_type = mono_type_get_underlying_type (&klass->byval_arg);
4989         guint32 load_opc = mono_type_to_load_membase (cfg, enum_type);
4990         gboolean is_i4;
4991
4992         switch (enum_type->type) {
4993         case MONO_TYPE_I8:
4994         case MONO_TYPE_U8:
4995 #if SIZEOF_REGISTER == 8
4996         case MONO_TYPE_I:
4997         case MONO_TYPE_U:
4998 #endif
4999                 is_i4 = FALSE;
5000                 break;
5001         default:
5002                 is_i4 = TRUE;
5003                 break;
5004         }
5005
5006         {
5007                 MonoInst *load, *and_, *cmp, *ceq;
5008                 int enum_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
5009                 int and_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
5010                 int dest_reg = alloc_ireg (cfg);
5011
5012                 EMIT_NEW_LOAD_MEMBASE (cfg, load, load_opc, enum_reg, enum_this->dreg, 0);
5013                 EMIT_NEW_BIALU (cfg, and_, is_i4 ? OP_IAND : OP_LAND, and_reg, enum_reg, enum_flag->dreg);
5014                 EMIT_NEW_BIALU (cfg, cmp, is_i4 ? OP_ICOMPARE : OP_LCOMPARE, -1, and_reg, enum_flag->dreg);
5015                 EMIT_NEW_UNALU (cfg, ceq, is_i4 ? OP_ICEQ : OP_LCEQ, dest_reg, -1);
5016
5017                 ceq->type = STACK_I4;
5018
5019                 if (!is_i4) {
5020                         load = mono_decompose_opcode (cfg, load);
5021                         and_ = mono_decompose_opcode (cfg, and_);
5022                         cmp = mono_decompose_opcode (cfg, cmp);
5023                         ceq = mono_decompose_opcode (cfg, ceq);
5024                 }
5025
5026                 return ceq;
5027         }
5028 }
5029
5030 /*
5031  * Returns NULL and set the cfg exception on error.
5032  */
5033 static G_GNUC_UNUSED MonoInst*
5034 handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method, int context_used, gboolean virtual_)
5035 {
5036         MonoInst *ptr;
5037         int dreg;
5038         gpointer trampoline;
5039         MonoInst *obj, *method_ins, *tramp_ins;
5040         MonoDomain *domain;
5041         guint8 **code_slot;
5042
5043         if (virtual_ && !cfg->llvm_only) {
5044                 MonoMethod *invoke = mono_get_delegate_invoke (klass);
5045                 g_assert (invoke);
5046
5047                 if (!mono_get_delegate_virtual_invoke_impl (mono_method_signature (invoke), context_used ? NULL : method))
5048                         return NULL;
5049         }
5050
5051         obj = handle_alloc (cfg, klass, FALSE, mono_class_check_context_used (klass));
5052         if (!obj)
5053                 return NULL;
5054
5055         /* Inline the contents of mono_delegate_ctor */
5056
5057         /* Set target field */
5058         /* Optimize away setting of NULL target */
5059         if (!(target->opcode == OP_PCONST && target->inst_p0 == 0)) {
5060                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
5061                 if (cfg->gen_write_barriers) {
5062                         dreg = alloc_preg (cfg);
5063                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target));
5064                         emit_write_barrier (cfg, ptr, target);
5065                 }
5066         }
5067
5068         /* Set method field */
5069         method_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
5070         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg);
5071
5072         /* 
5073          * To avoid looking up the compiled code belonging to the target method
5074          * in mono_delegate_trampoline (), we allocate a per-domain memory slot to
5075          * store it, and we fill it after the method has been compiled.
5076          */
5077         if (!method->dynamic && !(cfg->opt & MONO_OPT_SHARED)) {
5078                 MonoInst *code_slot_ins;
5079
5080                 if (context_used) {
5081                         code_slot_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD_DELEGATE_CODE);
5082                 } else {
5083                         domain = mono_domain_get ();
5084                         mono_domain_lock (domain);
5085                         if (!domain_jit_info (domain)->method_code_hash)
5086                                 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
5087                         code_slot = (guint8 **)g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, method);
5088                         if (!code_slot) {
5089                                 code_slot = (guint8 **)mono_domain_alloc0 (domain, sizeof (gpointer));
5090                                 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, method, code_slot);
5091                         }
5092                         mono_domain_unlock (domain);
5093
5094                         code_slot_ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHOD_CODE_SLOT, method);
5095                 }
5096                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);                
5097         }
5098
5099         if (cfg->llvm_only) {
5100                 MonoInst *args [16];
5101
5102                 if (virtual_) {
5103                         args [0] = obj;
5104                         args [1] = target;
5105                         args [2] = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
5106                         mono_emit_jit_icall (cfg, mono_llvmonly_init_delegate_virtual, args);
5107                 } else {
5108                         args [0] = obj;
5109                         mono_emit_jit_icall (cfg, mono_llvmonly_init_delegate, args);
5110                 }
5111
5112                 return obj;
5113         }
5114
5115         if (cfg->compile_aot) {
5116                 MonoDelegateClassMethodPair *del_tramp;
5117
5118                 del_tramp = (MonoDelegateClassMethodPair *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoDelegateClassMethodPair));
5119                 del_tramp->klass = klass;
5120                 del_tramp->method = context_used ? NULL : method;
5121                 del_tramp->is_virtual = virtual_;
5122                 EMIT_NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_DELEGATE_TRAMPOLINE, del_tramp);
5123         } else {
5124                 if (virtual_)
5125                         trampoline = mono_create_delegate_virtual_trampoline (cfg->domain, klass, context_used ? NULL : method);
5126                 else
5127                         trampoline = mono_create_delegate_trampoline_info (cfg->domain, klass, context_used ? NULL : method);
5128                 EMIT_NEW_PCONST (cfg, tramp_ins, trampoline);
5129         }
5130
5131         /* Set invoke_impl field */
5132         if (virtual_) {
5133                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), tramp_ins->dreg);
5134         } else {
5135                 dreg = alloc_preg (cfg);
5136                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, invoke_impl));
5137                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), dreg);
5138
5139                 dreg = alloc_preg (cfg);
5140                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, method_ptr));
5141                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr), dreg);
5142         }
5143
5144         dreg = alloc_preg (cfg);
5145         MONO_EMIT_NEW_ICONST (cfg, dreg, virtual_ ? 1 : 0);
5146         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_is_virtual), dreg);
5147
5148         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
5149
5150         return obj;
5151 }
5152
5153 static MonoInst*
5154 handle_array_new (MonoCompile *cfg, int rank, MonoInst **sp, unsigned char *ip)
5155 {
5156         MonoJitICallInfo *info;
5157
5158         /* Need to register the icall so it gets an icall wrapper */
5159         info = mono_get_array_new_va_icall (rank);
5160
5161         cfg->flags |= MONO_CFG_HAS_VARARGS;
5162
5163         /* mono_array_new_va () needs a vararg calling convention */
5164         cfg->exception_message = g_strdup ("array-new");
5165         cfg->disable_llvm = TRUE;
5166
5167         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
5168         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, sp);
5169 }
5170
5171 /*
5172  * handle_constrained_gsharedvt_call:
5173  *
5174  *   Handle constrained calls where the receiver is a gsharedvt type.
5175  * Return the instruction representing the call. Set the cfg exception on failure.
5176  */
5177 static MonoInst*
5178 handle_constrained_gsharedvt_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp, MonoClass *constrained_class,
5179                                                                    gboolean *ref_emit_widen)
5180 {
5181         MonoInst *ins = NULL;
5182         gboolean emit_widen = *ref_emit_widen;
5183
5184         /*
5185          * Constrained calls need to behave differently at runtime dependending on whenever the receiver is instantiated as ref type or as a vtype.
5186          * 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
5187          * pack the arguments into an array, and do the rest of the work in in an icall.
5188          */
5189         if (((cmethod->klass == mono_defaults.object_class) || (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) &&
5190                 (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)) &&
5191                 (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]))))) {
5192                 MonoInst *args [16];
5193
5194                 /*
5195                  * This case handles calls to
5196                  * - object:ToString()/Equals()/GetHashCode(),
5197                  * - System.IComparable<T>:CompareTo()
5198                  * - System.IEquatable<T>:Equals ()
5199                  * plus some simple interface calls enough to support AsyncTaskMethodBuilder.
5200                  */
5201
5202                 args [0] = sp [0];
5203                 if (mono_method_check_context_used (cmethod))
5204                         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cmethod), cmethod, MONO_RGCTX_INFO_METHOD);
5205                 else
5206                         EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
5207                 args [2] = emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_class), constrained_class, MONO_RGCTX_INFO_KLASS);
5208
5209                 /* !fsig->hasthis is for the wrapper for the Object.GetType () icall */
5210                 if (fsig->hasthis && fsig->param_count) {
5211                         /* Pass the arguments using a localloc-ed array using the format expected by runtime_invoke () */
5212                         MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
5213                         ins->dreg = alloc_preg (cfg);
5214                         ins->inst_imm = fsig->param_count * sizeof (mgreg_t);
5215                         MONO_ADD_INS (cfg->cbb, ins);
5216                         args [4] = ins;
5217
5218                         if (mini_is_gsharedvt_type (fsig->params [0])) {
5219                                 int addr_reg, deref_arg_reg;
5220
5221                                 ins = emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type (fsig->params [0]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
5222                                 deref_arg_reg = alloc_preg (cfg);
5223                                 /* deref_arg = BOX_TYPE != MONO_GSHAREDVT_BOX_TYPE_VTYPE */
5224                                 EMIT_NEW_BIALU_IMM (cfg, args [3], OP_ISUB_IMM, deref_arg_reg, ins->dreg, 1);
5225
5226                                 EMIT_NEW_VARLOADA_VREG (cfg, ins, sp [1]->dreg, fsig->params [0]);
5227                                 addr_reg = ins->dreg;
5228                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, addr_reg);
5229                         } else {
5230                                 EMIT_NEW_ICONST (cfg, args [3], 0);
5231                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, sp [1]->dreg);
5232                         }
5233                 } else {
5234                         EMIT_NEW_ICONST (cfg, args [3], 0);
5235                         EMIT_NEW_ICONST (cfg, args [4], 0);
5236                 }
5237                 ins = mono_emit_jit_icall (cfg, mono_gsharedvt_constrained_call, args);
5238                 emit_widen = FALSE;
5239
5240                 if (mini_is_gsharedvt_type (fsig->ret)) {
5241                         ins = handle_unbox_gsharedvt (cfg, mono_class_from_mono_type (fsig->ret), ins);
5242                 } else if (MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret)) {
5243                         MonoInst *add;
5244
5245                         /* Unbox */
5246                         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), ins->dreg, sizeof (MonoObject));
5247                         MONO_ADD_INS (cfg->cbb, add);
5248                         /* Load value */
5249                         NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, add->dreg, 0);
5250                         MONO_ADD_INS (cfg->cbb, ins);
5251                         /* ins represents the call result */
5252                 }
5253         } else {
5254                 GSHAREDVT_FAILURE (CEE_CALLVIRT);
5255         }
5256
5257         *ref_emit_widen = emit_widen;
5258
5259         return ins;
5260
5261  exception_exit:
5262         return NULL;
5263 }
5264
5265 static void
5266 mono_emit_load_got_addr (MonoCompile *cfg)
5267 {
5268         MonoInst *getaddr, *dummy_use;
5269
5270         if (!cfg->got_var || cfg->got_var_allocated)
5271                 return;
5272
5273         MONO_INST_NEW (cfg, getaddr, OP_LOAD_GOTADDR);
5274         getaddr->cil_code = cfg->header->code;
5275         getaddr->dreg = cfg->got_var->dreg;
5276
5277         /* Add it to the start of the first bblock */
5278         if (cfg->bb_entry->code) {
5279                 getaddr->next = cfg->bb_entry->code;
5280                 cfg->bb_entry->code = getaddr;
5281         }
5282         else
5283                 MONO_ADD_INS (cfg->bb_entry, getaddr);
5284
5285         cfg->got_var_allocated = TRUE;
5286
5287         /* 
5288          * Add a dummy use to keep the got_var alive, since real uses might
5289          * only be generated by the back ends.
5290          * Add it to end_bblock, so the variable's lifetime covers the whole
5291          * method.
5292          * It would be better to make the usage of the got var explicit in all
5293          * cases when the backend needs it (i.e. calls, throw etc.), so this
5294          * wouldn't be needed.
5295          */
5296         NEW_DUMMY_USE (cfg, dummy_use, cfg->got_var);
5297         MONO_ADD_INS (cfg->bb_exit, dummy_use);
5298 }
5299
5300 static int inline_limit;
5301 static gboolean inline_limit_inited;
5302
5303 static gboolean
5304 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
5305 {
5306         MonoMethodHeaderSummary header;
5307         MonoVTable *vtable;
5308 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5309         MonoMethodSignature *sig = mono_method_signature (method);
5310         int i;
5311 #endif
5312
5313         if (cfg->disable_inline)
5314                 return FALSE;
5315         if (cfg->gshared)
5316                 return FALSE;
5317
5318         if (cfg->inline_depth > 10)
5319                 return FALSE;
5320
5321         if (!mono_method_get_header_summary (method, &header))
5322                 return FALSE;
5323
5324         /*runtime, icall and pinvoke are checked by summary call*/
5325         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
5326             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
5327             (mono_class_is_marshalbyref (method->klass)) ||
5328             header.has_clauses)
5329                 return FALSE;
5330
5331         /* also consider num_locals? */
5332         /* Do the size check early to avoid creating vtables */
5333         if (!inline_limit_inited) {
5334                 if (g_getenv ("MONO_INLINELIMIT"))
5335                         inline_limit = atoi (g_getenv ("MONO_INLINELIMIT"));
5336                 else
5337                         inline_limit = INLINE_LENGTH_LIMIT;
5338                 inline_limit_inited = TRUE;
5339         }
5340         if (header.code_size >= inline_limit && !(method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
5341                 return FALSE;
5342
5343         /*
5344          * if we can initialize the class of the method right away, we do,
5345          * otherwise we don't allow inlining if the class needs initialization,
5346          * since it would mean inserting a call to mono_runtime_class_init()
5347          * inside the inlined code
5348          */
5349         if (!(cfg->opt & MONO_OPT_SHARED)) {
5350                 /* The AggressiveInlining hint is a good excuse to force that cctor to run. */
5351                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING) {
5352                         vtable = mono_class_vtable (cfg->domain, method->klass);
5353                         if (!vtable)
5354                                 return FALSE;
5355                         if (!cfg->compile_aot) {
5356                                 MonoError error;
5357                                 if (!mono_runtime_class_init_full (vtable, &error)) {
5358                                         mono_error_cleanup (&error);
5359                                         return FALSE;
5360                                 }
5361                         }
5362                 } else if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5363                         if (cfg->run_cctors && method->klass->has_cctor) {
5364                                 /*FIXME it would easier and lazier to just use mono_class_try_get_vtable */
5365                                 if (!method->klass->runtime_info)
5366                                         /* No vtable created yet */
5367                                         return FALSE;
5368                                 vtable = mono_class_vtable (cfg->domain, method->klass);
5369                                 if (!vtable)
5370                                         return FALSE;
5371                                 /* This makes so that inline cannot trigger */
5372                                 /* .cctors: too many apps depend on them */
5373                                 /* running with a specific order... */
5374                                 if (! vtable->initialized)
5375                                         return FALSE;
5376                                 MonoError error;
5377                                 if (!mono_runtime_class_init_full (vtable, &error)) {
5378                                         mono_error_cleanup (&error);
5379                                         return FALSE;
5380                                 }
5381                         }
5382                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
5383                         if (!method->klass->runtime_info)
5384                                 /* No vtable created yet */
5385                                 return FALSE;
5386                         vtable = mono_class_vtable (cfg->domain, method->klass);
5387                         if (!vtable)
5388                                 return FALSE;
5389                         if (!vtable->initialized)
5390                                 return FALSE;
5391                 }
5392         } else {
5393                 /* 
5394                  * If we're compiling for shared code
5395                  * the cctor will need to be run at aot method load time, for example,
5396                  * or at the end of the compilation of the inlining method.
5397                  */
5398                 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
5399                         return FALSE;
5400         }
5401
5402 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5403         if (mono_arch_is_soft_float ()) {
5404                 /* FIXME: */
5405                 if (sig->ret && sig->ret->type == MONO_TYPE_R4)
5406                         return FALSE;
5407                 for (i = 0; i < sig->param_count; ++i)
5408                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4)
5409                                 return FALSE;
5410         }
5411 #endif
5412
5413         if (g_list_find (cfg->dont_inline, method))
5414                 return FALSE;
5415
5416         return TRUE;
5417 }
5418
5419 static gboolean
5420 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoClass *klass, MonoVTable *vtable)
5421 {
5422         if (!cfg->compile_aot) {
5423                 g_assert (vtable);
5424                 if (vtable->initialized)
5425                         return FALSE;
5426         }
5427
5428         if (klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5429                 if (cfg->method == method)
5430                         return FALSE;
5431         }
5432
5433         if (!mono_class_needs_cctor_run (klass, method))
5434                 return FALSE;
5435
5436         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (klass == method->klass))
5437                 /* The initialization is already done before the method is called */
5438                 return FALSE;
5439
5440         return TRUE;
5441 }
5442
5443 static MonoInst*
5444 mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck)
5445 {
5446         MonoInst *ins;
5447         guint32 size;
5448         int mult_reg, add_reg, array_reg, index_reg, index2_reg;
5449         int context_used;
5450
5451         if (mini_is_gsharedvt_variable_klass (klass)) {
5452                 size = -1;
5453         } else {
5454                 mono_class_init (klass);
5455                 size = mono_class_array_element_size (klass);
5456         }
5457
5458         mult_reg = alloc_preg (cfg);
5459         array_reg = arr->dreg;
5460         index_reg = index->dreg;
5461
5462 #if SIZEOF_REGISTER == 8
5463         /* The array reg is 64 bits but the index reg is only 32 */
5464         if (COMPILE_LLVM (cfg)) {
5465                 /* Not needed */
5466                 index2_reg = index_reg;
5467         } else {
5468                 index2_reg = alloc_preg (cfg);
5469                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
5470         }
5471 #else
5472         if (index->type == STACK_I8) {
5473                 index2_reg = alloc_preg (cfg);
5474                 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I4, index2_reg, index_reg);
5475         } else {
5476                 index2_reg = index_reg;
5477         }
5478 #endif
5479
5480         if (bcheck)
5481                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
5482
5483 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5484         if (size == 1 || size == 2 || size == 4 || size == 8) {
5485                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
5486
5487                 EMIT_NEW_X86_LEA (cfg, ins, array_reg, index2_reg, fast_log2 [size], MONO_STRUCT_OFFSET (MonoArray, vector));
5488                 ins->klass = mono_class_get_element_class (klass);
5489                 ins->type = STACK_MP;
5490
5491                 return ins;
5492         }
5493 #endif          
5494
5495         add_reg = alloc_ireg_mp (cfg);
5496
5497         if (size == -1) {
5498                 MonoInst *rgctx_ins;
5499
5500                 /* gsharedvt */
5501                 g_assert (cfg->gshared);
5502                 context_used = mini_class_check_context_used (cfg, klass);
5503                 g_assert (context_used);
5504                 rgctx_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE);
5505                 MONO_EMIT_NEW_BIALU (cfg, OP_IMUL, mult_reg, index2_reg, rgctx_ins->dreg);
5506         } else {
5507                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
5508         }
5509         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg);
5510         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5511         ins->klass = mono_class_get_element_class (klass);
5512         ins->type = STACK_MP;
5513         MONO_ADD_INS (cfg->cbb, ins);
5514
5515         return ins;
5516 }
5517
5518 static MonoInst*
5519 mini_emit_ldelema_2_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index_ins1, MonoInst *index_ins2)
5520 {
5521         int bounds_reg = alloc_preg (cfg);
5522         int add_reg = alloc_ireg_mp (cfg);
5523         int mult_reg = alloc_preg (cfg);
5524         int mult2_reg = alloc_preg (cfg);
5525         int low1_reg = alloc_preg (cfg);
5526         int low2_reg = alloc_preg (cfg);
5527         int high1_reg = alloc_preg (cfg);
5528         int high2_reg = alloc_preg (cfg);
5529         int realidx1_reg = alloc_preg (cfg);
5530         int realidx2_reg = alloc_preg (cfg);
5531         int sum_reg = alloc_preg (cfg);
5532         int index1, index2, tmpreg;
5533         MonoInst *ins;
5534         guint32 size;
5535
5536         mono_class_init (klass);
5537         size = mono_class_array_element_size (klass);
5538
5539         index1 = index_ins1->dreg;
5540         index2 = index_ins2->dreg;
5541
5542 #if SIZEOF_REGISTER == 8
5543         /* The array reg is 64 bits but the index reg is only 32 */
5544         if (COMPILE_LLVM (cfg)) {
5545                 /* Not needed */
5546         } else {
5547                 tmpreg = alloc_preg (cfg);
5548                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index1);
5549                 index1 = tmpreg;
5550                 tmpreg = alloc_preg (cfg);
5551                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index2);
5552                 index2 = tmpreg;
5553         }
5554 #else
5555         // FIXME: Do we need to do something here for i8 indexes, like in ldelema_1_ins ?
5556         tmpreg = -1;
5557 #endif
5558
5559         /* range checking */
5560         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, 
5561                                        arr->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5562
5563         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low1_reg, 
5564                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5565         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx1_reg, index1, low1_reg);
5566         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high1_reg, 
5567                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5568         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high1_reg, realidx1_reg);
5569         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5570
5571         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low2_reg, 
5572                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5573         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx2_reg, index2, low2_reg);
5574         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high2_reg, 
5575                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5576         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high2_reg, realidx2_reg);
5577         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5578
5579         MONO_EMIT_NEW_BIALU (cfg, OP_PMUL, mult_reg, high2_reg, realidx1_reg);
5580         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, mult_reg, realidx2_reg);
5581         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PMUL_IMM, mult2_reg, sum_reg, size);
5582         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult2_reg, arr->dreg);
5583         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5584
5585         ins->type = STACK_MP;
5586         ins->klass = klass;
5587         MONO_ADD_INS (cfg->cbb, ins);
5588
5589         return ins;
5590 }
5591
5592 static MonoInst*
5593 mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
5594 {
5595         int rank;
5596         MonoInst *addr;
5597         MonoMethod *addr_method;
5598         int element_size;
5599         MonoClass *eclass = cmethod->klass->element_class;
5600
5601         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
5602
5603         if (rank == 1)
5604                 return mini_emit_ldelema_1_ins (cfg, eclass, sp [0], sp [1], TRUE);
5605
5606         /* emit_ldelema_2 depends on OP_LMUL */
5607         if (!cfg->backend->emulate_mul_div && rank == 2 && (cfg->opt & MONO_OPT_INTRINS) && !mini_is_gsharedvt_variable_klass (eclass)) {
5608                 return mini_emit_ldelema_2_ins (cfg, eclass, sp [0], sp [1], sp [2]);
5609         }
5610
5611         if (mini_is_gsharedvt_variable_klass (eclass))
5612                 element_size = 0;
5613         else
5614                 element_size = mono_class_array_element_size (eclass);
5615         addr_method = mono_marshal_get_array_address (rank, element_size);
5616         addr = mono_emit_method_call (cfg, addr_method, sp, NULL);
5617
5618         return addr;
5619 }
5620
5621 static MonoBreakPolicy
5622 always_insert_breakpoint (MonoMethod *method)
5623 {
5624         return MONO_BREAK_POLICY_ALWAYS;
5625 }
5626
5627 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
5628
5629 /**
5630  * mono_set_break_policy:
5631  * policy_callback: the new callback function
5632  *
5633  * Allow embedders to decide wherther to actually obey breakpoint instructions
5634  * (both break IL instructions and Debugger.Break () method calls), for example
5635  * to not allow an app to be aborted by a perfectly valid IL opcode when executing
5636  * untrusted or semi-trusted code.
5637  *
5638  * @policy_callback will be called every time a break point instruction needs to
5639  * be inserted with the method argument being the method that calls Debugger.Break()
5640  * or has the IL break instruction. The callback should return #MONO_BREAK_POLICY_NEVER
5641  * if it wants the breakpoint to not be effective in the given method.
5642  * #MONO_BREAK_POLICY_ALWAYS is the default.
5643  */
5644 void
5645 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
5646 {
5647         if (policy_callback)
5648                 break_policy_func = policy_callback;
5649         else
5650                 break_policy_func = always_insert_breakpoint;
5651 }
5652
5653 static gboolean
5654 should_insert_brekpoint (MonoMethod *method) {
5655         switch (break_policy_func (method)) {
5656         case MONO_BREAK_POLICY_ALWAYS:
5657                 return TRUE;
5658         case MONO_BREAK_POLICY_NEVER:
5659                 return FALSE;
5660         case MONO_BREAK_POLICY_ON_DBG:
5661                 g_warning ("mdb no longer supported");
5662                 return FALSE;
5663         default:
5664                 g_warning ("Incorrect value returned from break policy callback");
5665                 return FALSE;
5666         }
5667 }
5668
5669 /* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */
5670 static MonoInst*
5671 emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5672 {
5673         MonoInst *addr, *store, *load;
5674         MonoClass *eklass = mono_class_from_mono_type (fsig->params [2]);
5675
5676         /* the bounds check is already done by the callers */
5677         addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5678         if (is_set) {
5679                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
5680                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
5681                 if (mini_type_is_reference (&eklass->byval_arg))
5682                         emit_write_barrier (cfg, addr, load);
5683         } else {
5684                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
5685                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
5686         }
5687         return store;
5688 }
5689
5690
5691 static gboolean
5692 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
5693 {
5694         return mini_type_is_reference (&klass->byval_arg);
5695 }
5696
5697 static MonoInst*
5698 emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboolean safety_checks)
5699 {
5700         if (safety_checks && generic_class_is_reference_type (cfg, klass) &&
5701                 !(sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL)) {
5702                 MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
5703                 MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
5704                 MonoInst *iargs [3];
5705
5706                 if (!helper->slot)
5707                         mono_class_setup_vtable (obj_array);
5708                 g_assert (helper->slot);
5709
5710                 if (sp [0]->type != STACK_OBJ)
5711                         return NULL;
5712                 if (sp [2]->type != STACK_OBJ)
5713                         return NULL;
5714
5715                 iargs [2] = sp [2];
5716                 iargs [1] = sp [1];
5717                 iargs [0] = sp [0];
5718
5719                 return mono_emit_method_call (cfg, helper, iargs, sp [0]);
5720         } else {
5721                 MonoInst *ins;
5722
5723                 if (mini_is_gsharedvt_variable_klass (klass)) {
5724                         MonoInst *addr;
5725
5726                         // FIXME-VT: OP_ICONST optimization
5727                         addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
5728                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5729                         ins->opcode = OP_STOREV_MEMBASE;
5730                 } else if (sp [1]->opcode == OP_ICONST) {
5731                         int array_reg = sp [0]->dreg;
5732                         int index_reg = sp [1]->dreg;
5733                         int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
5734
5735                         if (SIZEOF_REGISTER == 8 && COMPILE_LLVM (cfg))
5736                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, index_reg);
5737
5738                         if (safety_checks)
5739                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
5740                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
5741                 } else {
5742                         MonoInst *addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], safety_checks);
5743                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5744                         if (generic_class_is_reference_type (cfg, klass))
5745                                 emit_write_barrier (cfg, addr, sp [2]);
5746                 }
5747                 return ins;
5748         }
5749 }
5750
5751 static MonoInst*
5752 emit_array_unsafe_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5753 {
5754         MonoClass *eklass;
5755         
5756         if (is_set)
5757                 eklass = mono_class_from_mono_type (fsig->params [2]);
5758         else
5759                 eklass = mono_class_from_mono_type (fsig->ret);
5760
5761         if (is_set) {
5762                 return emit_array_store (cfg, eklass, args, FALSE);
5763         } else {
5764                 MonoInst *ins, *addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5765                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &eklass->byval_arg, addr->dreg, 0);
5766                 return ins;
5767         }
5768 }
5769
5770 static gboolean
5771 is_unsafe_mov_compatible (MonoCompile *cfg, MonoClass *param_klass, MonoClass *return_klass)
5772 {
5773         uint32_t align;
5774         int param_size, return_size;
5775
5776         param_klass = mono_class_from_mono_type (mini_get_underlying_type (&param_klass->byval_arg));
5777         return_klass = mono_class_from_mono_type (mini_get_underlying_type (&return_klass->byval_arg));
5778
5779         if (cfg->verbose_level > 3)
5780                 printf ("[UNSAFE-MOV-INTRISIC] %s <- %s\n", return_klass->name, param_klass->name);
5781
5782         //Don't allow mixing reference types with value types
5783         if (param_klass->valuetype != return_klass->valuetype) {
5784                 if (cfg->verbose_level > 3)
5785                         printf ("[UNSAFE-MOV-INTRISIC]\tone of the args is a valuetype and the other is not\n");
5786                 return FALSE;
5787         }
5788
5789         if (!param_klass->valuetype) {
5790                 if (cfg->verbose_level > 3)
5791                         printf ("[UNSAFE-MOV-INTRISIC]\targs are reference types\n");
5792                 return TRUE;
5793         }
5794
5795         //That are blitable
5796         if (param_klass->has_references || return_klass->has_references)
5797                 return FALSE;
5798
5799         /* Avoid mixing structs and primitive types/enums, they need to be handled differently in the JIT */
5800         if ((MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && !MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)) ||
5801                 (!MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && MONO_TYPE_ISSTRUCT (&return_klass->byval_arg))) {
5802                         if (cfg->verbose_level > 3)
5803                                 printf ("[UNSAFE-MOV-INTRISIC]\tmixing structs and scalars\n");
5804                 return FALSE;
5805         }
5806
5807         if (param_klass->byval_arg.type == MONO_TYPE_R4 || param_klass->byval_arg.type == MONO_TYPE_R8 ||
5808                 return_klass->byval_arg.type == MONO_TYPE_R4 || return_klass->byval_arg.type == MONO_TYPE_R8) {
5809                 if (cfg->verbose_level > 3)
5810                         printf ("[UNSAFE-MOV-INTRISIC]\tfloat or double are not supported\n");
5811                 return FALSE;
5812         }
5813
5814         param_size = mono_class_value_size (param_klass, &align);
5815         return_size = mono_class_value_size (return_klass, &align);
5816
5817         //We can do it if sizes match
5818         if (param_size == return_size) {
5819                 if (cfg->verbose_level > 3)
5820                         printf ("[UNSAFE-MOV-INTRISIC]\tsame size\n");
5821                 return TRUE;
5822         }
5823
5824         //No simple way to handle struct if sizes don't match
5825         if (MONO_TYPE_ISSTRUCT (&param_klass->byval_arg)) {
5826                 if (cfg->verbose_level > 3)
5827                         printf ("[UNSAFE-MOV-INTRISIC]\tsize mismatch and type is a struct\n");
5828                 return FALSE;
5829         }
5830
5831         /*
5832          * Same reg size category.
5833          * A quick note on why we don't require widening here.
5834          * The intrinsic is "R Array.UnsafeMov<S,R> (S s)".
5835          *
5836          * Since the source value comes from a function argument, the JIT will already have
5837          * the value in a VREG and performed any widening needed before (say, when loading from a field).
5838          */
5839         if (param_size <= 4 && return_size <= 4) {
5840                 if (cfg->verbose_level > 3)
5841                         printf ("[UNSAFE-MOV-INTRISIC]\tsize mismatch but both are of the same reg class\n");
5842                 return TRUE;
5843         }
5844
5845         return FALSE;
5846 }
5847
5848 static MonoInst*
5849 emit_array_unsafe_mov (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args)
5850 {
5851         MonoClass *param_klass = mono_class_from_mono_type (fsig->params [0]);
5852         MonoClass *return_klass = mono_class_from_mono_type (fsig->ret);
5853
5854         if (mini_is_gsharedvt_variable_type (fsig->ret))
5855                 return NULL;
5856
5857         //Valuetypes that are semantically equivalent or numbers than can be widened to
5858         if (is_unsafe_mov_compatible (cfg, param_klass, return_klass))
5859                 return args [0];
5860
5861         //Arrays of valuetypes that are semantically equivalent
5862         if (param_klass->rank == 1 && return_klass->rank == 1 && is_unsafe_mov_compatible (cfg, param_klass->element_class, return_klass->element_class))
5863                 return args [0];
5864
5865         return NULL;
5866 }
5867
5868 static MonoInst*
5869 mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5870 {
5871 #ifdef MONO_ARCH_SIMD_INTRINSICS
5872         MonoInst *ins = NULL;
5873
5874         if (cfg->opt & MONO_OPT_SIMD) {
5875                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5876                 if (ins)
5877                         return ins;
5878         }
5879 #endif
5880
5881         return mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
5882 }
5883
5884 static MonoInst*
5885 emit_memory_barrier (MonoCompile *cfg, int kind)
5886 {
5887         MonoInst *ins = NULL;
5888         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
5889         MONO_ADD_INS (cfg->cbb, ins);
5890         ins->backend.memory_barrier_kind = kind;
5891
5892         return ins;
5893 }
5894
5895 static MonoInst*
5896 llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5897 {
5898         MonoInst *ins = NULL;
5899         int opcode = 0;
5900
5901         /* The LLVM backend supports these intrinsics */
5902         if (cmethod->klass == mono_defaults.math_class) {
5903                 if (strcmp (cmethod->name, "Sin") == 0) {
5904                         opcode = OP_SIN;
5905                 } else if (strcmp (cmethod->name, "Cos") == 0) {
5906                         opcode = OP_COS;
5907                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
5908                         opcode = OP_SQRT;
5909                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
5910                         opcode = OP_ABS;
5911                 }
5912
5913                 if (opcode && fsig->param_count == 1) {
5914                         MONO_INST_NEW (cfg, ins, opcode);
5915                         ins->type = STACK_R8;
5916                         ins->dreg = mono_alloc_dreg (cfg, ins->type);
5917                         ins->sreg1 = args [0]->dreg;
5918                         MONO_ADD_INS (cfg->cbb, ins);
5919                 }
5920
5921                 opcode = 0;
5922                 if (cfg->opt & MONO_OPT_CMOV) {
5923                         if (strcmp (cmethod->name, "Min") == 0) {
5924                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5925                                         opcode = OP_IMIN;
5926                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5927                                         opcode = OP_IMIN_UN;
5928                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5929                                         opcode = OP_LMIN;
5930                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5931                                         opcode = OP_LMIN_UN;
5932                         } else if (strcmp (cmethod->name, "Max") == 0) {
5933                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5934                                         opcode = OP_IMAX;
5935                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5936                                         opcode = OP_IMAX_UN;
5937                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5938                                         opcode = OP_LMAX;
5939                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5940                                         opcode = OP_LMAX_UN;
5941                         }
5942                 }
5943
5944                 if (opcode && fsig->param_count == 2) {
5945                         MONO_INST_NEW (cfg, ins, opcode);
5946                         ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
5947                         ins->dreg = mono_alloc_dreg (cfg, ins->type);
5948                         ins->sreg1 = args [0]->dreg;
5949                         ins->sreg2 = args [1]->dreg;
5950                         MONO_ADD_INS (cfg->cbb, ins);
5951                 }
5952         }
5953
5954         return ins;
5955 }
5956
5957 static MonoInst*
5958 mini_emit_inst_for_sharable_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5959 {
5960         if (cmethod->klass == mono_defaults.array_class) {
5961                 if (strcmp (cmethod->name, "UnsafeStore") == 0)
5962                         return emit_array_unsafe_access (cfg, fsig, args, TRUE);
5963                 else if (strcmp (cmethod->name, "UnsafeLoad") == 0)
5964                         return emit_array_unsafe_access (cfg, fsig, args, FALSE);
5965                 else if (strcmp (cmethod->name, "UnsafeMov") == 0)
5966                         return emit_array_unsafe_mov (cfg, fsig, args);
5967         }
5968
5969         return NULL;
5970 }
5971
5972 static MonoInst*
5973 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5974 {
5975         MonoInst *ins = NULL;
5976
5977          MonoClass *runtime_helpers_class = mono_class_get_runtime_helpers_class ();
5978
5979         if (cmethod->klass == mono_defaults.string_class) {
5980                 if (strcmp (cmethod->name, "get_Chars") == 0 && fsig->param_count + fsig->hasthis == 2) {
5981                         int dreg = alloc_ireg (cfg);
5982                         int index_reg = alloc_preg (cfg);
5983                         int add_reg = alloc_preg (cfg);
5984
5985 #if SIZEOF_REGISTER == 8
5986                         if (COMPILE_LLVM (cfg)) {
5987                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, args [1]->dreg);
5988                         } else {
5989                                 /* The array reg is 64 bits but the index reg is only 32 */
5990                                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index_reg, args [1]->dreg);
5991                         }
5992 #else
5993                         index_reg = args [1]->dreg;
5994 #endif  
5995                         MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
5996
5997 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5998                         EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, MONO_STRUCT_OFFSET (MonoString, chars));
5999                         add_reg = ins->dreg;
6000                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
6001                                                                    add_reg, 0);
6002 #else
6003                         int mult_reg = alloc_preg (cfg);
6004                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1);
6005                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
6006                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
6007                                                                    add_reg, MONO_STRUCT_OFFSET (MonoString, chars));
6008 #endif
6009                         type_from_op (cfg, ins, NULL, NULL);
6010                         return ins;
6011                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
6012                         int dreg = alloc_ireg (cfg);
6013                         /* Decompose later to allow more optimizations */
6014                         EMIT_NEW_UNALU (cfg, ins, OP_STRLEN, dreg, args [0]->dreg);
6015                         ins->type = STACK_I4;
6016                         ins->flags |= MONO_INST_FAULT;
6017                         cfg->cbb->has_array_access = TRUE;
6018                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
6019
6020                         return ins;
6021                 } else 
6022                         return NULL;
6023         } else if (cmethod->klass == mono_defaults.object_class) {
6024                 if (strcmp (cmethod->name, "GetType") == 0 && fsig->param_count + fsig->hasthis == 1) {
6025                         int dreg = alloc_ireg_ref (cfg);
6026                         int vt_reg = alloc_preg (cfg);
6027                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
6028                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, MONO_STRUCT_OFFSET (MonoVTable, type));
6029                         type_from_op (cfg, ins, NULL, NULL);
6030
6031                         return ins;
6032                 } else if (!cfg->backend->emulate_mul_div && strcmp (cmethod->name, "InternalGetHashCode") == 0 && fsig->param_count == 1 && !mono_gc_is_moving ()) {
6033                         int dreg = alloc_ireg (cfg);
6034                         int t1 = alloc_ireg (cfg);
6035         
6036                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, t1, args [0]->dreg, 3);
6037                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_MUL_IMM, dreg, t1, 2654435761u);
6038                         ins->type = STACK_I4;
6039
6040                         return ins;
6041                 } else if (strcmp (cmethod->name, ".ctor") == 0 && fsig->param_count == 0) {
6042                         MONO_INST_NEW (cfg, ins, OP_NOP);
6043                         MONO_ADD_INS (cfg->cbb, ins);
6044                         return ins;
6045                 } else
6046                         return NULL;
6047         } else if (cmethod->klass == mono_defaults.array_class) {
6048                 if (strcmp (cmethod->name, "GetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
6049                         return emit_array_generic_access (cfg, fsig, args, FALSE);
6050                 else if (strcmp (cmethod->name, "SetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
6051                         return emit_array_generic_access (cfg, fsig, args, TRUE);
6052
6053 #ifndef MONO_BIG_ARRAYS
6054                 /*
6055                  * This is an inline version of GetLength/GetLowerBound(0) used frequently in
6056                  * Array methods.
6057                  */
6058                 else if (((strcmp (cmethod->name, "GetLength") == 0 && fsig->param_count + fsig->hasthis == 2) ||
6059                          (strcmp (cmethod->name, "GetLowerBound") == 0 && fsig->param_count + fsig->hasthis == 2)) &&
6060                          args [1]->opcode == OP_ICONST && args [1]->inst_c0 == 0) {
6061                         int dreg = alloc_ireg (cfg);
6062                         int bounds_reg = alloc_ireg_mp (cfg);
6063                         MonoBasicBlock *end_bb, *szarray_bb;
6064                         gboolean get_length = strcmp (cmethod->name, "GetLength") == 0;
6065
6066                         NEW_BBLOCK (cfg, end_bb);
6067                         NEW_BBLOCK (cfg, szarray_bb);
6068
6069                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOAD_MEMBASE, bounds_reg,
6070                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
6071                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
6072                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, szarray_bb);
6073                         /* Non-szarray case */
6074                         if (get_length)
6075                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
6076                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
6077                         else
6078                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
6079                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
6080                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
6081                         MONO_START_BB (cfg, szarray_bb);
6082                         /* Szarray case */
6083                         if (get_length)
6084                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
6085                                                                            args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
6086                         else
6087                                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
6088                         MONO_START_BB (cfg, end_bb);
6089
6090                         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, dreg, dreg);
6091                         ins->type = STACK_I4;
6092                         
6093                         return ins;
6094                 }
6095 #endif
6096
6097                 if (cmethod->name [0] != 'g')
6098                         return NULL;
6099
6100                 if (strcmp (cmethod->name, "get_Rank") == 0 && fsig->param_count + fsig->hasthis == 1) {
6101                         int dreg = alloc_ireg (cfg);
6102                         int vtable_reg = alloc_preg (cfg);
6103                         MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, 
6104                                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
6105                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
6106                                                                    vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
6107                         type_from_op (cfg, ins, NULL, NULL);
6108
6109                         return ins;
6110                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
6111                         int dreg = alloc_ireg (cfg);
6112
6113                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
6114                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
6115                         type_from_op (cfg, ins, NULL, NULL);
6116
6117                         return ins;
6118                 } else
6119                         return NULL;
6120         } else if (cmethod->klass == runtime_helpers_class) {
6121                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0 && fsig->param_count == 0) {
6122                         EMIT_NEW_ICONST (cfg, ins, MONO_STRUCT_OFFSET (MonoString, chars));
6123                         return ins;
6124                 } else
6125                         return NULL;
6126         } else if (cmethod->klass == mono_defaults.monitor_class) {
6127                 gboolean is_enter = FALSE;
6128
6129                 if (!strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1)
6130                         is_enter = TRUE;
6131
6132                 if (is_enter) {
6133                         /*
6134                          * To make async stack traces work, icalls which can block should have a wrapper.
6135                          * For Monitor.Enter, emit two calls: a fastpath which doesn't have a wrapper, and a slowpath, which does.
6136                          */
6137                         MonoBasicBlock *end_bb;
6138
6139                         NEW_BBLOCK (cfg, end_bb);
6140
6141                         ins = mono_emit_jit_icall (cfg, (gpointer)mono_monitor_enter_fast, args);
6142                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, ins->dreg, 0);
6143                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, end_bb);
6144                         ins = mono_emit_jit_icall (cfg, (gpointer)mono_monitor_enter, args);
6145                         MONO_START_BB (cfg, end_bb);
6146                         return ins;
6147                 }
6148         } else if (cmethod->klass == mono_defaults.thread_class) {
6149                 if (strcmp (cmethod->name, "SpinWait_nop") == 0 && fsig->param_count == 0) {
6150                         MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
6151                         MONO_ADD_INS (cfg->cbb, ins);
6152                         return ins;
6153                 } else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0) {
6154                         return emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6155                 } else if (!strcmp (cmethod->name, "VolatileRead") && fsig->param_count == 1) {
6156                         guint32 opcode = 0;
6157                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6158
6159                         if (fsig->params [0]->type == MONO_TYPE_I1)
6160                                 opcode = OP_LOADI1_MEMBASE;
6161                         else if (fsig->params [0]->type == MONO_TYPE_U1)
6162                                 opcode = OP_LOADU1_MEMBASE;
6163                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6164                                 opcode = OP_LOADI2_MEMBASE;
6165                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6166                                 opcode = OP_LOADU2_MEMBASE;
6167                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6168                                 opcode = OP_LOADI4_MEMBASE;
6169                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6170                                 opcode = OP_LOADU4_MEMBASE;
6171                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
6172                                 opcode = OP_LOADI8_MEMBASE;
6173                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6174                                 opcode = OP_LOADR4_MEMBASE;
6175                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6176                                 opcode = OP_LOADR8_MEMBASE;
6177                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
6178                                 opcode = OP_LOAD_MEMBASE;
6179
6180                         if (opcode) {
6181                                 MONO_INST_NEW (cfg, ins, opcode);
6182                                 ins->inst_basereg = args [0]->dreg;
6183                                 ins->inst_offset = 0;
6184                                 MONO_ADD_INS (cfg->cbb, ins);
6185
6186                                 switch (fsig->params [0]->type) {
6187                                 case MONO_TYPE_I1:
6188                                 case MONO_TYPE_U1:
6189                                 case MONO_TYPE_I2:
6190                                 case MONO_TYPE_U2:
6191                                 case MONO_TYPE_I4:
6192                                 case MONO_TYPE_U4:
6193                                         ins->dreg = mono_alloc_ireg (cfg);
6194                                         ins->type = STACK_I4;
6195                                         break;
6196                                 case MONO_TYPE_I8:
6197                                 case MONO_TYPE_U8:
6198                                         ins->dreg = mono_alloc_lreg (cfg);
6199                                         ins->type = STACK_I8;
6200                                         break;
6201                                 case MONO_TYPE_I:
6202                                 case MONO_TYPE_U:
6203                                         ins->dreg = mono_alloc_ireg (cfg);
6204 #if SIZEOF_REGISTER == 8
6205                                         ins->type = STACK_I8;
6206 #else
6207                                         ins->type = STACK_I4;
6208 #endif
6209                                         break;
6210                                 case MONO_TYPE_R4:
6211                                 case MONO_TYPE_R8:
6212                                         ins->dreg = mono_alloc_freg (cfg);
6213                                         ins->type = STACK_R8;
6214                                         break;
6215                                 default:
6216                                         g_assert (mini_type_is_reference (fsig->params [0]));
6217                                         ins->dreg = mono_alloc_ireg_ref (cfg);
6218                                         ins->type = STACK_OBJ;
6219                                         break;
6220                                 }
6221
6222                                 if (opcode == OP_LOADI8_MEMBASE)
6223                                         ins = mono_decompose_opcode (cfg, ins);
6224
6225                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6226
6227                                 return ins;
6228                         }
6229                 } else if (!strcmp (cmethod->name, "VolatileWrite") && fsig->param_count == 2) {
6230                         guint32 opcode = 0;
6231                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6232
6233                         if (fsig->params [0]->type == MONO_TYPE_I1 || fsig->params [0]->type == MONO_TYPE_U1)
6234                                 opcode = OP_STOREI1_MEMBASE_REG;
6235                         else if (fsig->params [0]->type == MONO_TYPE_I2 || fsig->params [0]->type == MONO_TYPE_U2)
6236                                 opcode = OP_STOREI2_MEMBASE_REG;
6237                         else if (fsig->params [0]->type == MONO_TYPE_I4 || fsig->params [0]->type == MONO_TYPE_U4)
6238                                 opcode = OP_STOREI4_MEMBASE_REG;
6239                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
6240                                 opcode = OP_STOREI8_MEMBASE_REG;
6241                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6242                                 opcode = OP_STORER4_MEMBASE_REG;
6243                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6244                                 opcode = OP_STORER8_MEMBASE_REG;
6245                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
6246                                 opcode = OP_STORE_MEMBASE_REG;
6247
6248                         if (opcode) {
6249                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6250
6251                                 MONO_INST_NEW (cfg, ins, opcode);
6252                                 ins->sreg1 = args [1]->dreg;
6253                                 ins->inst_destbasereg = args [0]->dreg;
6254                                 ins->inst_offset = 0;
6255                                 MONO_ADD_INS (cfg->cbb, ins);
6256
6257                                 if (opcode == OP_STOREI8_MEMBASE_REG)
6258                                         ins = mono_decompose_opcode (cfg, ins);
6259
6260                                 return ins;
6261                         }
6262                 }
6263         } else if (cmethod->klass->image == mono_defaults.corlib &&
6264                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6265                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
6266                 ins = NULL;
6267
6268 #if SIZEOF_REGISTER == 8
6269                 if (!cfg->llvm_only && strcmp (cmethod->name, "Read") == 0 && fsig->param_count == 1 && (fsig->params [0]->type == MONO_TYPE_I8)) {
6270                         if (!cfg->llvm_only && mono_arch_opcode_supported (OP_ATOMIC_LOAD_I8)) {
6271                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_LOAD_I8);
6272                                 ins->dreg = mono_alloc_preg (cfg);
6273                                 ins->sreg1 = args [0]->dreg;
6274                                 ins->type = STACK_I8;
6275                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_SEQ;
6276                                 MONO_ADD_INS (cfg->cbb, ins);
6277                         } else {
6278                                 MonoInst *load_ins;
6279
6280                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6281
6282                                 /* 64 bit reads are already atomic */
6283                                 MONO_INST_NEW (cfg, load_ins, OP_LOADI8_MEMBASE);
6284                                 load_ins->dreg = mono_alloc_preg (cfg);
6285                                 load_ins->inst_basereg = args [0]->dreg;
6286                                 load_ins->inst_offset = 0;
6287                                 load_ins->type = STACK_I8;
6288                                 MONO_ADD_INS (cfg->cbb, load_ins);
6289
6290                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6291
6292                                 ins = load_ins;
6293                         }
6294                 }
6295 #endif
6296
6297                 if (strcmp (cmethod->name, "Increment") == 0 && fsig->param_count == 1) {
6298                         MonoInst *ins_iconst;
6299                         guint32 opcode = 0;
6300
6301                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6302                                 opcode = OP_ATOMIC_ADD_I4;
6303                                 cfg->has_atomic_add_i4 = TRUE;
6304                         }
6305 #if SIZEOF_REGISTER == 8
6306                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6307                                 opcode = OP_ATOMIC_ADD_I8;
6308 #endif
6309                         if (opcode) {
6310                                 if (!mono_arch_opcode_supported (opcode))
6311                                         return NULL;
6312                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6313                                 ins_iconst->inst_c0 = 1;
6314                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6315                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6316
6317                                 MONO_INST_NEW (cfg, ins, opcode);
6318                                 ins->dreg = mono_alloc_ireg (cfg);
6319                                 ins->inst_basereg = args [0]->dreg;
6320                                 ins->inst_offset = 0;
6321                                 ins->sreg2 = ins_iconst->dreg;
6322                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6323                                 MONO_ADD_INS (cfg->cbb, ins);
6324                         }
6325                 } else if (strcmp (cmethod->name, "Decrement") == 0 && fsig->param_count == 1) {
6326                         MonoInst *ins_iconst;
6327                         guint32 opcode = 0;
6328
6329                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6330                                 opcode = OP_ATOMIC_ADD_I4;
6331                                 cfg->has_atomic_add_i4 = TRUE;
6332                         }
6333 #if SIZEOF_REGISTER == 8
6334                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6335                                 opcode = OP_ATOMIC_ADD_I8;
6336 #endif
6337                         if (opcode) {
6338                                 if (!mono_arch_opcode_supported (opcode))
6339                                         return NULL;
6340                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6341                                 ins_iconst->inst_c0 = -1;
6342                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6343                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6344
6345                                 MONO_INST_NEW (cfg, ins, opcode);
6346                                 ins->dreg = mono_alloc_ireg (cfg);
6347                                 ins->inst_basereg = args [0]->dreg;
6348                                 ins->inst_offset = 0;
6349                                 ins->sreg2 = ins_iconst->dreg;
6350                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6351                                 MONO_ADD_INS (cfg->cbb, ins);
6352                         }
6353                 } else if (strcmp (cmethod->name, "Add") == 0 && fsig->param_count == 2) {
6354                         guint32 opcode = 0;
6355
6356                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6357                                 opcode = OP_ATOMIC_ADD_I4;
6358                                 cfg->has_atomic_add_i4 = TRUE;
6359                         }
6360 #if SIZEOF_REGISTER == 8
6361                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6362                                 opcode = OP_ATOMIC_ADD_I8;
6363 #endif
6364                         if (opcode) {
6365                                 if (!mono_arch_opcode_supported (opcode))
6366                                         return NULL;
6367                                 MONO_INST_NEW (cfg, ins, opcode);
6368                                 ins->dreg = mono_alloc_ireg (cfg);
6369                                 ins->inst_basereg = args [0]->dreg;
6370                                 ins->inst_offset = 0;
6371                                 ins->sreg2 = args [1]->dreg;
6372                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6373                                 MONO_ADD_INS (cfg->cbb, ins);
6374                         }
6375                 }
6376                 else if (strcmp (cmethod->name, "Exchange") == 0 && fsig->param_count == 2) {
6377                         MonoInst *f2i = NULL, *i2f;
6378                         guint32 opcode, f2i_opcode, i2f_opcode;
6379                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6380                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
6381
6382                         if (fsig->params [0]->type == MONO_TYPE_I4 ||
6383                             fsig->params [0]->type == MONO_TYPE_R4) {
6384                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6385                                 f2i_opcode = OP_MOVE_F_TO_I4;
6386                                 i2f_opcode = OP_MOVE_I4_TO_F;
6387                                 cfg->has_atomic_exchange_i4 = TRUE;
6388                         }
6389 #if SIZEOF_REGISTER == 8
6390                         else if (is_ref ||
6391                                  fsig->params [0]->type == MONO_TYPE_I8 ||
6392                                  fsig->params [0]->type == MONO_TYPE_R8 ||
6393                                  fsig->params [0]->type == MONO_TYPE_I) {
6394                                 opcode = OP_ATOMIC_EXCHANGE_I8;
6395                                 f2i_opcode = OP_MOVE_F_TO_I8;
6396                                 i2f_opcode = OP_MOVE_I8_TO_F;
6397                         }
6398 #else
6399                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I) {
6400                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6401                                 cfg->has_atomic_exchange_i4 = TRUE;
6402                         }
6403 #endif
6404                         else
6405                                 return NULL;
6406
6407                         if (!mono_arch_opcode_supported (opcode))
6408                                 return NULL;
6409
6410                         if (is_float) {
6411                                 /* TODO: Decompose these opcodes instead of bailing here. */
6412                                 if (COMPILE_SOFT_FLOAT (cfg))
6413                                         return NULL;
6414
6415                                 MONO_INST_NEW (cfg, f2i, f2i_opcode);
6416                                 f2i->dreg = mono_alloc_ireg (cfg);
6417                                 f2i->sreg1 = args [1]->dreg;
6418                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6419                                         f2i->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6420                                 MONO_ADD_INS (cfg->cbb, f2i);
6421                         }
6422
6423                         MONO_INST_NEW (cfg, ins, opcode);
6424                         ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : mono_alloc_ireg (cfg);
6425                         ins->inst_basereg = args [0]->dreg;
6426                         ins->inst_offset = 0;
6427                         ins->sreg2 = is_float ? f2i->dreg : args [1]->dreg;
6428                         MONO_ADD_INS (cfg->cbb, ins);
6429
6430                         switch (fsig->params [0]->type) {
6431                         case MONO_TYPE_I4:
6432                                 ins->type = STACK_I4;
6433                                 break;
6434                         case MONO_TYPE_I8:
6435                                 ins->type = STACK_I8;
6436                                 break;
6437                         case MONO_TYPE_I:
6438 #if SIZEOF_REGISTER == 8
6439                                 ins->type = STACK_I8;
6440 #else
6441                                 ins->type = STACK_I4;
6442 #endif
6443                                 break;
6444                         case MONO_TYPE_R4:
6445                         case MONO_TYPE_R8:
6446                                 ins->type = STACK_R8;
6447                                 break;
6448                         default:
6449                                 g_assert (mini_type_is_reference (fsig->params [0]));
6450                                 ins->type = STACK_OBJ;
6451                                 break;
6452                         }
6453
6454                         if (is_float) {
6455                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6456                                 i2f->dreg = mono_alloc_freg (cfg);
6457                                 i2f->sreg1 = ins->dreg;
6458                                 i2f->type = STACK_R8;
6459                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6460                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6461                                 MONO_ADD_INS (cfg->cbb, i2f);
6462
6463                                 ins = i2f;
6464                         }
6465
6466                         if (cfg->gen_write_barriers && is_ref)
6467                                 emit_write_barrier (cfg, args [0], args [1]);
6468                 }
6469                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 3) {
6470                         MonoInst *f2i_new = NULL, *f2i_cmp = NULL, *i2f;
6471                         guint32 opcode, f2i_opcode, i2f_opcode;
6472                         gboolean is_ref = mini_type_is_reference (fsig->params [1]);
6473                         gboolean is_float = fsig->params [1]->type == MONO_TYPE_R4 || fsig->params [1]->type == MONO_TYPE_R8;
6474
6475                         if (fsig->params [1]->type == MONO_TYPE_I4 ||
6476                             fsig->params [1]->type == MONO_TYPE_R4) {
6477                                 opcode = OP_ATOMIC_CAS_I4;
6478                                 f2i_opcode = OP_MOVE_F_TO_I4;
6479                                 i2f_opcode = OP_MOVE_I4_TO_F;
6480                                 cfg->has_atomic_cas_i4 = TRUE;
6481                         }
6482 #if SIZEOF_REGISTER == 8
6483                         else if (is_ref ||
6484                                  fsig->params [1]->type == MONO_TYPE_I8 ||
6485                                  fsig->params [1]->type == MONO_TYPE_R8 ||
6486                                  fsig->params [1]->type == MONO_TYPE_I) {
6487                                 opcode = OP_ATOMIC_CAS_I8;
6488                                 f2i_opcode = OP_MOVE_F_TO_I8;
6489                                 i2f_opcode = OP_MOVE_I8_TO_F;
6490                         }
6491 #else
6492                         else if (is_ref || fsig->params [1]->type == MONO_TYPE_I) {
6493                                 opcode = OP_ATOMIC_CAS_I4;
6494                                 cfg->has_atomic_cas_i4 = TRUE;
6495                         }
6496 #endif
6497                         else
6498                                 return NULL;
6499
6500                         if (!mono_arch_opcode_supported (opcode))
6501                                 return NULL;
6502
6503                         if (is_float) {
6504                                 /* TODO: Decompose these opcodes instead of bailing here. */
6505                                 if (COMPILE_SOFT_FLOAT (cfg))
6506                                         return NULL;
6507
6508                                 MONO_INST_NEW (cfg, f2i_new, f2i_opcode);
6509                                 f2i_new->dreg = mono_alloc_ireg (cfg);
6510                                 f2i_new->sreg1 = args [1]->dreg;
6511                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6512                                         f2i_new->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6513                                 MONO_ADD_INS (cfg->cbb, f2i_new);
6514
6515                                 MONO_INST_NEW (cfg, f2i_cmp, f2i_opcode);
6516                                 f2i_cmp->dreg = mono_alloc_ireg (cfg);
6517                                 f2i_cmp->sreg1 = args [2]->dreg;
6518                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6519                                         f2i_cmp->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6520                                 MONO_ADD_INS (cfg->cbb, f2i_cmp);
6521                         }
6522
6523                         MONO_INST_NEW (cfg, ins, opcode);
6524                         ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
6525                         ins->sreg1 = args [0]->dreg;
6526                         ins->sreg2 = is_float ? f2i_new->dreg : args [1]->dreg;
6527                         ins->sreg3 = is_float ? f2i_cmp->dreg : args [2]->dreg;
6528                         MONO_ADD_INS (cfg->cbb, ins);
6529
6530                         switch (fsig->params [1]->type) {
6531                         case MONO_TYPE_I4:
6532                                 ins->type = STACK_I4;
6533                                 break;
6534                         case MONO_TYPE_I8:
6535                                 ins->type = STACK_I8;
6536                                 break;
6537                         case MONO_TYPE_I:
6538 #if SIZEOF_REGISTER == 8
6539                                 ins->type = STACK_I8;
6540 #else
6541                                 ins->type = STACK_I4;
6542 #endif
6543                                 break;
6544                         case MONO_TYPE_R4:
6545                                 ins->type = cfg->r4_stack_type;
6546                                 break;
6547                         case MONO_TYPE_R8:
6548                                 ins->type = STACK_R8;
6549                                 break;
6550                         default:
6551                                 g_assert (mini_type_is_reference (fsig->params [1]));
6552                                 ins->type = STACK_OBJ;
6553                                 break;
6554                         }
6555
6556                         if (is_float) {
6557                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6558                                 i2f->dreg = mono_alloc_freg (cfg);
6559                                 i2f->sreg1 = ins->dreg;
6560                                 i2f->type = STACK_R8;
6561                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6562                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6563                                 MONO_ADD_INS (cfg->cbb, i2f);
6564
6565                                 ins = i2f;
6566                         }
6567
6568                         if (cfg->gen_write_barriers && is_ref)
6569                                 emit_write_barrier (cfg, args [0], args [1]);
6570                 }
6571                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 4 &&
6572                          fsig->params [1]->type == MONO_TYPE_I4) {
6573                         MonoInst *cmp, *ceq;
6574
6575                         if (!mono_arch_opcode_supported (OP_ATOMIC_CAS_I4))
6576                                 return NULL;
6577
6578                         /* int32 r = CAS (location, value, comparand); */
6579                         MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
6580                         ins->dreg = alloc_ireg (cfg);
6581                         ins->sreg1 = args [0]->dreg;
6582                         ins->sreg2 = args [1]->dreg;
6583                         ins->sreg3 = args [2]->dreg;
6584                         ins->type = STACK_I4;
6585                         MONO_ADD_INS (cfg->cbb, ins);
6586
6587                         /* bool result = r == comparand; */
6588                         MONO_INST_NEW (cfg, cmp, OP_ICOMPARE);
6589                         cmp->sreg1 = ins->dreg;
6590                         cmp->sreg2 = args [2]->dreg;
6591                         cmp->type = STACK_I4;
6592                         MONO_ADD_INS (cfg->cbb, cmp);
6593
6594                         MONO_INST_NEW (cfg, ceq, OP_ICEQ);
6595                         ceq->dreg = alloc_ireg (cfg);
6596                         ceq->type = STACK_I4;
6597                         MONO_ADD_INS (cfg->cbb, ceq);
6598
6599                         /* *success = result; */
6600                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, args [3]->dreg, 0, ceq->dreg);
6601
6602                         cfg->has_atomic_cas_i4 = TRUE;
6603                 }
6604                 else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0)
6605                         ins = emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6606
6607                 if (ins)
6608                         return ins;
6609         } else if (cmethod->klass->image == mono_defaults.corlib &&
6610                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6611                            (strcmp (cmethod->klass->name, "Volatile") == 0)) {
6612                 ins = NULL;
6613
6614                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Read") && fsig->param_count == 1) {
6615                         guint32 opcode = 0;
6616                         MonoType *t = fsig->params [0];
6617                         gboolean is_ref;
6618                         gboolean is_float = t->type == MONO_TYPE_R4 || t->type == MONO_TYPE_R8;
6619
6620                         g_assert (t->byref);
6621                         /* t is a byref type, so the reference check is more complicated */
6622                         is_ref = mini_type_is_reference (&mono_class_from_mono_type (t)->byval_arg);
6623                         if (t->type == MONO_TYPE_I1)
6624                                 opcode = OP_ATOMIC_LOAD_I1;
6625                         else if (t->type == MONO_TYPE_U1 || t->type == MONO_TYPE_BOOLEAN)
6626                                 opcode = OP_ATOMIC_LOAD_U1;
6627                         else if (t->type == MONO_TYPE_I2)
6628                                 opcode = OP_ATOMIC_LOAD_I2;
6629                         else if (t->type == MONO_TYPE_U2)
6630                                 opcode = OP_ATOMIC_LOAD_U2;
6631                         else if (t->type == MONO_TYPE_I4)
6632                                 opcode = OP_ATOMIC_LOAD_I4;
6633                         else if (t->type == MONO_TYPE_U4)
6634                                 opcode = OP_ATOMIC_LOAD_U4;
6635                         else if (t->type == MONO_TYPE_R4)
6636                                 opcode = OP_ATOMIC_LOAD_R4;
6637                         else if (t->type == MONO_TYPE_R8)
6638                                 opcode = OP_ATOMIC_LOAD_R8;
6639 #if SIZEOF_REGISTER == 8
6640                         else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_I)
6641                                 opcode = OP_ATOMIC_LOAD_I8;
6642                         else if (is_ref || t->type == MONO_TYPE_U8 || t->type == MONO_TYPE_U)
6643                                 opcode = OP_ATOMIC_LOAD_U8;
6644 #else
6645                         else if (t->type == MONO_TYPE_I)
6646                                 opcode = OP_ATOMIC_LOAD_I4;
6647                         else if (is_ref || t->type == MONO_TYPE_U)
6648                                 opcode = OP_ATOMIC_LOAD_U4;
6649 #endif
6650
6651                         if (opcode) {
6652                                 if (!mono_arch_opcode_supported (opcode))
6653                                         return NULL;
6654
6655                                 MONO_INST_NEW (cfg, ins, opcode);
6656                                 ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : (is_float ? mono_alloc_freg (cfg) : mono_alloc_ireg (cfg));
6657                                 ins->sreg1 = args [0]->dreg;
6658                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_ACQ;
6659                                 MONO_ADD_INS (cfg->cbb, ins);
6660
6661                                 switch (t->type) {
6662                                 case MONO_TYPE_BOOLEAN:
6663                                 case MONO_TYPE_I1:
6664                                 case MONO_TYPE_U1:
6665                                 case MONO_TYPE_I2:
6666                                 case MONO_TYPE_U2:
6667                                 case MONO_TYPE_I4:
6668                                 case MONO_TYPE_U4:
6669                                         ins->type = STACK_I4;
6670                                         break;
6671                                 case MONO_TYPE_I8:
6672                                 case MONO_TYPE_U8:
6673                                         ins->type = STACK_I8;
6674                                         break;
6675                                 case MONO_TYPE_I:
6676                                 case MONO_TYPE_U:
6677 #if SIZEOF_REGISTER == 8
6678                                         ins->type = STACK_I8;
6679 #else
6680                                         ins->type = STACK_I4;
6681 #endif
6682                                         break;
6683                                 case MONO_TYPE_R4:
6684                                         ins->type = cfg->r4_stack_type;
6685                                         break;
6686                                 case MONO_TYPE_R8:
6687                                         ins->type = STACK_R8;
6688                                         break;
6689                                 default:
6690                                         g_assert (is_ref);
6691                                         ins->type = STACK_OBJ;
6692                                         break;
6693                                 }
6694                         }
6695                 }
6696
6697                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Write") && fsig->param_count == 2) {
6698                         guint32 opcode = 0;
6699                         MonoType *t = fsig->params [0];
6700                         gboolean is_ref;
6701
6702                         g_assert (t->byref);
6703                         is_ref = mini_type_is_reference (&mono_class_from_mono_type (t)->byval_arg);
6704                         if (t->type == MONO_TYPE_I1)
6705                                 opcode = OP_ATOMIC_STORE_I1;
6706                         else if (t->type == MONO_TYPE_U1 || t->type == MONO_TYPE_BOOLEAN)
6707                                 opcode = OP_ATOMIC_STORE_U1;
6708                         else if (t->type == MONO_TYPE_I2)
6709                                 opcode = OP_ATOMIC_STORE_I2;
6710                         else if (t->type == MONO_TYPE_U2)
6711                                 opcode = OP_ATOMIC_STORE_U2;
6712                         else if (t->type == MONO_TYPE_I4)
6713                                 opcode = OP_ATOMIC_STORE_I4;
6714                         else if (t->type == MONO_TYPE_U4)
6715                                 opcode = OP_ATOMIC_STORE_U4;
6716                         else if (t->type == MONO_TYPE_R4)
6717                                 opcode = OP_ATOMIC_STORE_R4;
6718                         else if (t->type == MONO_TYPE_R8)
6719                                 opcode = OP_ATOMIC_STORE_R8;
6720 #if SIZEOF_REGISTER == 8
6721                         else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_I)
6722                                 opcode = OP_ATOMIC_STORE_I8;
6723                         else if (is_ref || t->type == MONO_TYPE_U8 || t->type == MONO_TYPE_U)
6724                                 opcode = OP_ATOMIC_STORE_U8;
6725 #else
6726                         else if (t->type == MONO_TYPE_I)
6727                                 opcode = OP_ATOMIC_STORE_I4;
6728                         else if (is_ref || t->type == MONO_TYPE_U)
6729                                 opcode = OP_ATOMIC_STORE_U4;
6730 #endif
6731
6732                         if (opcode) {
6733                                 if (!mono_arch_opcode_supported (opcode))
6734                                         return NULL;
6735
6736                                 MONO_INST_NEW (cfg, ins, opcode);
6737                                 ins->dreg = args [0]->dreg;
6738                                 ins->sreg1 = args [1]->dreg;
6739                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_REL;
6740                                 MONO_ADD_INS (cfg->cbb, ins);
6741
6742                                 if (cfg->gen_write_barriers && is_ref)
6743                                         emit_write_barrier (cfg, args [0], args [1]);
6744                         }
6745                 }
6746
6747                 if (ins)
6748                         return ins;
6749         } else if (cmethod->klass->image == mono_defaults.corlib &&
6750                            (strcmp (cmethod->klass->name_space, "System.Diagnostics") == 0) &&
6751                            (strcmp (cmethod->klass->name, "Debugger") == 0)) {
6752                 if (!strcmp (cmethod->name, "Break") && fsig->param_count == 0) {
6753                         if (should_insert_brekpoint (cfg->method)) {
6754                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
6755                         } else {
6756                                 MONO_INST_NEW (cfg, ins, OP_NOP);
6757                                 MONO_ADD_INS (cfg->cbb, ins);
6758                         }
6759                         return ins;
6760                 }
6761         } else if (cmethod->klass->image == mono_defaults.corlib &&
6762                    (strcmp (cmethod->klass->name_space, "System") == 0) &&
6763                    (strcmp (cmethod->klass->name, "Environment") == 0)) {
6764                 if (!strcmp (cmethod->name, "get_IsRunningOnWindows") && fsig->param_count == 0) {
6765 #ifdef TARGET_WIN32
6766                         EMIT_NEW_ICONST (cfg, ins, 1);
6767 #else
6768                         EMIT_NEW_ICONST (cfg, ins, 0);
6769 #endif
6770                 }
6771         } else if (cmethod->klass->image == mono_defaults.corlib &&
6772                            (strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
6773                            (strcmp (cmethod->klass->name, "Assembly") == 0)) {
6774                 if (cfg->llvm_only && !strcmp (cmethod->name, "GetExecutingAssembly")) {
6775                         /* No stack walks are currently available, so implement this as an intrinsic */
6776                         MonoInst *assembly_ins;
6777
6778                         EMIT_NEW_AOTCONST (cfg, assembly_ins, MONO_PATCH_INFO_IMAGE, cfg->method->klass->image);
6779                         ins = mono_emit_jit_icall (cfg, mono_get_assembly_object, &assembly_ins);
6780                         return ins;
6781                 }
6782         } else if (cmethod->klass->image == mono_defaults.corlib &&
6783                            (strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
6784                            (strcmp (cmethod->klass->name, "MethodBase") == 0)) {
6785                 if (cfg->llvm_only && !strcmp (cmethod->name, "GetCurrentMethod")) {
6786                         /* No stack walks are currently available, so implement this as an intrinsic */
6787                         MonoInst *method_ins;
6788                         MonoMethod *declaring = cfg->method;
6789
6790                         /* This returns the declaring generic method */
6791                         if (declaring->is_inflated)
6792                                 declaring = ((MonoMethodInflated*)cfg->method)->declaring;
6793                         EMIT_NEW_AOTCONST (cfg, method_ins, MONO_PATCH_INFO_METHODCONST, declaring);
6794                         ins = mono_emit_jit_icall (cfg, mono_get_method_object, &method_ins);
6795                         cfg->no_inline = TRUE;
6796                         if (cfg->method != cfg->current_method)
6797                                 inline_failure (cfg, "MethodBase:GetCurrentMethod ()");
6798                         return ins;
6799                 }
6800         } else if (cmethod->klass == mono_defaults.math_class) {
6801                 /* 
6802                  * There is general branchless code for Min/Max, but it does not work for 
6803                  * all inputs:
6804                  * http://everything2.com/?node_id=1051618
6805                  */
6806         } else if (((!strcmp (cmethod->klass->image->assembly->aname.name, "MonoMac") ||
6807                     !strcmp (cmethod->klass->image->assembly->aname.name, "monotouch")) &&
6808                                 !strcmp (cmethod->klass->name_space, "XamCore.ObjCRuntime") &&
6809                                 !strcmp (cmethod->klass->name, "Selector")) ||
6810                            ((!strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.iOS") ||
6811                                  !strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.Mac")) &&
6812                                 !strcmp (cmethod->klass->name_space, "ObjCRuntime") &&
6813                                 !strcmp (cmethod->klass->name, "Selector"))
6814                            ) {
6815                 if ((cfg->backend->have_objc_get_selector || cfg->compile_llvm) &&
6816                         !strcmp (cmethod->name, "GetHandle") && fsig->param_count == 1 &&
6817                     (args [0]->opcode == OP_GOT_ENTRY || args [0]->opcode == OP_AOTCONST) &&
6818                     cfg->compile_aot) {
6819                         MonoInst *pi;
6820                         MonoJumpInfoToken *ji;
6821                         char *s;
6822
6823                         if (args [0]->opcode == OP_GOT_ENTRY) {
6824                                 pi = (MonoInst *)args [0]->inst_p1;
6825                                 g_assert (pi->opcode == OP_PATCH_INFO);
6826                                 g_assert (GPOINTER_TO_INT (pi->inst_p1) == MONO_PATCH_INFO_LDSTR);
6827                                 ji = (MonoJumpInfoToken *)pi->inst_p0;
6828                         } else {
6829                                 g_assert (GPOINTER_TO_INT (args [0]->inst_p1) == MONO_PATCH_INFO_LDSTR);
6830                                 ji = (MonoJumpInfoToken *)args [0]->inst_p0;
6831                         }
6832
6833                         NULLIFY_INS (args [0]);
6834
6835                         s = mono_ldstr_utf8 (ji->image, mono_metadata_token_index (ji->token), &cfg->error);
6836                         return_val_if_nok (&cfg->error, NULL);
6837
6838                         MONO_INST_NEW (cfg, ins, OP_OBJC_GET_SELECTOR);
6839                         ins->dreg = mono_alloc_ireg (cfg);
6840                         // FIXME: Leaks
6841                         ins->inst_p0 = s;
6842                         MONO_ADD_INS (cfg->cbb, ins);
6843                         return ins;
6844                 }
6845         }
6846
6847 #ifdef MONO_ARCH_SIMD_INTRINSICS
6848         if (cfg->opt & MONO_OPT_SIMD) {
6849                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
6850                 if (ins)
6851                         return ins;
6852         }
6853 #endif
6854
6855         ins = mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
6856         if (ins)
6857                 return ins;
6858
6859         if (COMPILE_LLVM (cfg)) {
6860                 ins = llvm_emit_inst_for_method (cfg, cmethod, fsig, args);
6861                 if (ins)
6862                         return ins;
6863         }
6864
6865         return mono_arch_emit_inst_for_method (cfg, cmethod, fsig, args);
6866 }
6867
6868 /*
6869  * This entry point could be used later for arbitrary method
6870  * redirection.
6871  */
6872 inline static MonoInst*
6873 mini_redirect_call (MonoCompile *cfg, MonoMethod *method,  
6874                                         MonoMethodSignature *signature, MonoInst **args, MonoInst *this_ins)
6875 {
6876         if (method->klass == mono_defaults.string_class) {
6877                 /* managed string allocation support */
6878                 if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && !(cfg->opt & MONO_OPT_SHARED)) {
6879                         MonoInst *iargs [2];
6880                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
6881                         MonoMethod *managed_alloc = NULL;
6882
6883                         g_assert (vtable); /*Should not fail since it System.String*/
6884 #ifndef MONO_CROSS_COMPILE
6885                         managed_alloc = mono_gc_get_managed_allocator (method->klass, FALSE, FALSE);
6886 #endif
6887                         if (!managed_alloc)
6888                                 return NULL;
6889                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
6890                         iargs [1] = args [0];
6891                         return mono_emit_method_call (cfg, managed_alloc, iargs, this_ins);
6892                 }
6893         }
6894         return NULL;
6895 }
6896
6897 static void
6898 mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp)
6899 {
6900         MonoInst *store, *temp;
6901         int i;
6902
6903         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
6904                 MonoType *argtype = (sig->hasthis && (i == 0)) ? type_from_stack_type (*sp) : sig->params [i - sig->hasthis];
6905
6906                 /*
6907                  * FIXME: We should use *args++ = sp [0], but that would mean the arg
6908                  * would be different than the MonoInst's used to represent arguments, and
6909                  * the ldelema implementation can't deal with that.
6910                  * Solution: When ldelema is used on an inline argument, create a var for 
6911                  * it, emit ldelema on that var, and emit the saving code below in
6912                  * inline_method () if needed.
6913                  */
6914                 temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
6915                 cfg->args [i] = temp;
6916                 /* This uses cfg->args [i] which is set by the preceeding line */
6917                 EMIT_NEW_ARGSTORE (cfg, store, i, *sp);
6918                 store->cil_code = sp [0]->cil_code;
6919                 sp++;
6920         }
6921 }
6922
6923 #define MONO_INLINE_CALLED_LIMITED_METHODS 1
6924 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
6925
6926 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6927 static gboolean
6928 check_inline_called_method_name_limit (MonoMethod *called_method)
6929 {
6930         int strncmp_result;
6931         static const char *limit = NULL;
6932         
6933         if (limit == NULL) {
6934                 const char *limit_string = g_getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
6935
6936                 if (limit_string != NULL)
6937                         limit = limit_string;
6938                 else
6939                         limit = "";
6940         }
6941
6942         if (limit [0] != '\0') {
6943                 char *called_method_name = mono_method_full_name (called_method, TRUE);
6944
6945                 strncmp_result = strncmp (called_method_name, limit, strlen (limit));
6946                 g_free (called_method_name);
6947         
6948                 //return (strncmp_result <= 0);
6949                 return (strncmp_result == 0);
6950         } else {
6951                 return TRUE;
6952         }
6953 }
6954 #endif
6955
6956 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6957 static gboolean
6958 check_inline_caller_method_name_limit (MonoMethod *caller_method)
6959 {
6960         int strncmp_result;
6961         static const char *limit = NULL;
6962         
6963         if (limit == NULL) {
6964                 const char *limit_string = g_getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
6965                 if (limit_string != NULL) {
6966                         limit = limit_string;
6967                 } else {
6968                         limit = "";
6969                 }
6970         }
6971
6972         if (limit [0] != '\0') {
6973                 char *caller_method_name = mono_method_full_name (caller_method, TRUE);
6974
6975                 strncmp_result = strncmp (caller_method_name, limit, strlen (limit));
6976                 g_free (caller_method_name);
6977         
6978                 //return (strncmp_result <= 0);
6979                 return (strncmp_result == 0);
6980         } else {
6981                 return TRUE;
6982         }
6983 }
6984 #endif
6985
6986 static void
6987 emit_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6988 {
6989         static double r8_0 = 0.0;
6990         static float r4_0 = 0.0;
6991         MonoInst *ins;
6992         int t;
6993
6994         rtype = mini_get_underlying_type (rtype);
6995         t = rtype->type;
6996
6997         if (rtype->byref) {
6998                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6999         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
7000                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
7001         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
7002                 MONO_EMIT_NEW_I8CONST (cfg, dreg, 0);
7003         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
7004                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
7005                 ins->type = STACK_R4;
7006                 ins->inst_p0 = (void*)&r4_0;
7007                 ins->dreg = dreg;
7008                 MONO_ADD_INS (cfg->cbb, ins);
7009         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
7010                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
7011                 ins->type = STACK_R8;
7012                 ins->inst_p0 = (void*)&r8_0;
7013                 ins->dreg = dreg;
7014                 MONO_ADD_INS (cfg->cbb, ins);
7015         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
7016                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
7017                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
7018         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
7019                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
7020         } else {
7021                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
7022         }
7023 }
7024
7025 static void
7026 emit_dummy_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
7027 {
7028         int t;
7029
7030         rtype = mini_get_underlying_type (rtype);
7031         t = rtype->type;
7032
7033         if (rtype->byref) {
7034                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_PCONST);
7035         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
7036                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_ICONST);
7037         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
7038                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_I8CONST);
7039         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
7040                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R4CONST);
7041         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
7042                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R8CONST);
7043         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
7044                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
7045                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
7046         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
7047                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
7048         } else {
7049                 emit_init_rvar (cfg, dreg, rtype);
7050         }
7051 }
7052
7053 /* If INIT is FALSE, emit dummy initialization statements to keep the IR valid */
7054 static void
7055 emit_init_local (MonoCompile *cfg, int local, MonoType *type, gboolean init)
7056 {
7057         MonoInst *var = cfg->locals [local];
7058         if (COMPILE_SOFT_FLOAT (cfg)) {
7059                 MonoInst *store;
7060                 int reg = alloc_dreg (cfg, (MonoStackType)var->type);
7061                 emit_init_rvar (cfg, reg, type);
7062                 EMIT_NEW_LOCSTORE (cfg, store, local, cfg->cbb->last_ins);
7063         } else {
7064                 if (init)
7065                         emit_init_rvar (cfg, var->dreg, type);
7066                 else
7067                         emit_dummy_init_rvar (cfg, var->dreg, type);
7068         }
7069 }
7070
7071 /*
7072  * inline_method:
7073  *
7074  *   Return the cost of inlining CMETHOD.
7075  */
7076 static int
7077 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
7078                            guchar *ip, guint real_offset, gboolean inline_always)
7079 {
7080         MonoError error;
7081         MonoInst *ins, *rvar = NULL;
7082         MonoMethodHeader *cheader;
7083         MonoBasicBlock *ebblock, *sbblock;
7084         int i, costs;
7085         MonoMethod *prev_inlined_method;
7086         MonoInst **prev_locals, **prev_args;
7087         MonoType **prev_arg_types;
7088         guint prev_real_offset;
7089         GHashTable *prev_cbb_hash;
7090         MonoBasicBlock **prev_cil_offset_to_bb;
7091         MonoBasicBlock *prev_cbb;
7092         const unsigned char *prev_ip;
7093         unsigned char *prev_cil_start;
7094         guint32 prev_cil_offset_to_bb_len;
7095         MonoMethod *prev_current_method;
7096         MonoGenericContext *prev_generic_context;
7097         gboolean ret_var_set, prev_ret_var_set, prev_disable_inline, virtual_ = FALSE;
7098
7099         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
7100
7101 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
7102         if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod))
7103                 return 0;
7104 #endif
7105 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
7106         if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method))
7107                 return 0;
7108 #endif
7109
7110         if (!fsig)
7111                 fsig = mono_method_signature (cmethod);
7112
7113         if (cfg->verbose_level > 2)
7114                 printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
7115
7116         if (!cmethod->inline_info) {
7117                 cfg->stat_inlineable_methods++;
7118                 cmethod->inline_info = 1;
7119         }
7120
7121         /* allocate local variables */
7122         cheader = mono_method_get_header_checked (cmethod, &error);
7123         if (!cheader) {
7124                 if (inline_always) {
7125                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
7126                         mono_error_move (&cfg->error, &error);
7127                 } else {
7128                         mono_error_cleanup (&error);
7129                 }
7130                 return 0;
7131         }
7132
7133         /*Must verify before creating locals as it can cause the JIT to assert.*/
7134         if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
7135                 mono_metadata_free_mh (cheader);
7136                 return 0;
7137         }
7138
7139         /* allocate space to store the return value */
7140         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
7141                 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
7142         }
7143
7144         prev_locals = cfg->locals;
7145         cfg->locals = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));
7146         for (i = 0; i < cheader->num_locals; ++i)
7147                 cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
7148
7149         /* allocate start and end blocks */
7150         /* This is needed so if the inline is aborted, we can clean up */
7151         NEW_BBLOCK (cfg, sbblock);
7152         sbblock->real_offset = real_offset;
7153
7154         NEW_BBLOCK (cfg, ebblock);
7155         ebblock->block_num = cfg->num_bblocks++;
7156         ebblock->real_offset = real_offset;
7157
7158         prev_args = cfg->args;
7159         prev_arg_types = cfg->arg_types;
7160         prev_inlined_method = cfg->inlined_method;
7161         cfg->inlined_method = cmethod;
7162         cfg->ret_var_set = FALSE;
7163         cfg->inline_depth ++;
7164         prev_real_offset = cfg->real_offset;
7165         prev_cbb_hash = cfg->cbb_hash;
7166         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
7167         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
7168         prev_cil_start = cfg->cil_start;
7169         prev_ip = cfg->ip;
7170         prev_cbb = cfg->cbb;
7171         prev_current_method = cfg->current_method;
7172         prev_generic_context = cfg->generic_context;
7173         prev_ret_var_set = cfg->ret_var_set;
7174         prev_disable_inline = cfg->disable_inline;
7175
7176         if (ip && *ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
7177                 virtual_ = TRUE;
7178
7179         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, sp, real_offset, virtual_);
7180
7181         ret_var_set = cfg->ret_var_set;
7182
7183         cfg->inlined_method = prev_inlined_method;
7184         cfg->real_offset = prev_real_offset;
7185         cfg->cbb_hash = prev_cbb_hash;
7186         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
7187         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
7188         cfg->cil_start = prev_cil_start;
7189         cfg->ip = prev_ip;
7190         cfg->locals = prev_locals;
7191         cfg->args = prev_args;
7192         cfg->arg_types = prev_arg_types;
7193         cfg->current_method = prev_current_method;
7194         cfg->generic_context = prev_generic_context;
7195         cfg->ret_var_set = prev_ret_var_set;
7196         cfg->disable_inline = prev_disable_inline;
7197         cfg->inline_depth --;
7198
7199         if ((costs >= 0 && costs < 60) || inline_always || (costs >= 0 && (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))) {
7200                 if (cfg->verbose_level > 2)
7201                         printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
7202                 
7203                 cfg->stat_inlined_methods++;
7204
7205                 /* always add some code to avoid block split failures */
7206                 MONO_INST_NEW (cfg, ins, OP_NOP);
7207                 MONO_ADD_INS (prev_cbb, ins);
7208
7209                 prev_cbb->next_bb = sbblock;
7210                 link_bblock (cfg, prev_cbb, sbblock);
7211
7212                 /* 
7213                  * Get rid of the begin and end bblocks if possible to aid local
7214                  * optimizations.
7215                  */
7216                 mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
7217
7218                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
7219                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
7220
7221                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
7222                         MonoBasicBlock *prev = ebblock->in_bb [0];
7223
7224                         if (prev->next_bb == ebblock) {
7225                                 mono_merge_basic_blocks (cfg, prev, ebblock);
7226                                 cfg->cbb = prev;
7227                                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
7228                                         mono_merge_basic_blocks (cfg, prev_cbb, prev);
7229                                         cfg->cbb = prev_cbb;
7230                                 }
7231                         } else {
7232                                 /* There could be a bblock after 'prev', and making 'prev' the current bb could cause problems */
7233                                 cfg->cbb = ebblock;
7234                         }
7235                 } else {
7236                         /* 
7237                          * Its possible that the rvar is set in some prev bblock, but not in others.
7238                          * (#1835).
7239                          */
7240                         if (rvar) {
7241                                 MonoBasicBlock *bb;
7242
7243                                 for (i = 0; i < ebblock->in_count; ++i) {
7244                                         bb = ebblock->in_bb [i];
7245
7246                                         if (bb->last_ins && bb->last_ins->opcode == OP_NOT_REACHED) {
7247                                                 cfg->cbb = bb;
7248
7249                                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
7250                                         }
7251                                 }
7252                         }
7253
7254                         cfg->cbb = ebblock;
7255                 }
7256
7257                 if (rvar) {
7258                         /*
7259                          * If the inlined method contains only a throw, then the ret var is not 
7260                          * set, so set it to a dummy value.
7261                          */
7262                         if (!ret_var_set)
7263                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
7264
7265                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
7266                         *sp++ = ins;
7267                 }
7268                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
7269                 return costs + 1;
7270         } else {
7271                 if (cfg->verbose_level > 2)
7272                         printf ("INLINE ABORTED %s (cost %d)\n", mono_method_full_name (cmethod, TRUE), costs);
7273                 cfg->exception_type = MONO_EXCEPTION_NONE;
7274
7275                 /* This gets rid of the newly added bblocks */
7276                 cfg->cbb = prev_cbb;
7277         }
7278         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
7279         return 0;
7280 }
7281
7282 /*
7283  * Some of these comments may well be out-of-date.
7284  * Design decisions: we do a single pass over the IL code (and we do bblock 
7285  * splitting/merging in the few cases when it's required: a back jump to an IL
7286  * address that was not already seen as bblock starting point).
7287  * Code is validated as we go (full verification is still better left to metadata/verify.c).
7288  * Complex operations are decomposed in simpler ones right away. We need to let the 
7289  * arch-specific code peek and poke inside this process somehow (except when the 
7290  * optimizations can take advantage of the full semantic info of coarse opcodes).
7291  * All the opcodes of the form opcode.s are 'normalized' to opcode.
7292  * MonoInst->opcode initially is the IL opcode or some simplification of that 
7293  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
7294  * opcode with value bigger than OP_LAST.
7295  * At this point the IR can be handed over to an interpreter, a dumb code generator
7296  * or to the optimizing code generator that will translate it to SSA form.
7297  *
7298  * Profiling directed optimizations.
7299  * We may compile by default with few or no optimizations and instrument the code
7300  * or the user may indicate what methods to optimize the most either in a config file
7301  * or through repeated runs where the compiler applies offline the optimizations to 
7302  * each method and then decides if it was worth it.
7303  */
7304
7305 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
7306 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
7307 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
7308 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
7309 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
7310 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
7311 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
7312 #define CHECK_TYPELOAD(klass) if (!(klass) || mono_class_has_failure (klass)) TYPE_LOAD_ERROR ((klass))
7313
7314 /* offset from br.s -> br like opcodes */
7315 #define BIG_BRANCH_OFFSET 13
7316
7317 static gboolean
7318 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
7319 {
7320         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
7321
7322         return b == NULL || b == bb;
7323 }
7324
7325 static int
7326 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
7327 {
7328         unsigned char *ip = start;
7329         unsigned char *target;
7330         int i;
7331         guint cli_addr;
7332         MonoBasicBlock *bblock;
7333         const MonoOpcode *opcode;
7334
7335         while (ip < end) {
7336                 cli_addr = ip - start;
7337                 i = mono_opcode_value ((const guint8 **)&ip, end);
7338                 if (i < 0)
7339                         UNVERIFIED;
7340                 opcode = &mono_opcodes [i];
7341                 switch (opcode->argument) {
7342                 case MonoInlineNone:
7343                         ip++; 
7344                         break;
7345                 case MonoInlineString:
7346                 case MonoInlineType:
7347                 case MonoInlineField:
7348                 case MonoInlineMethod:
7349                 case MonoInlineTok:
7350                 case MonoInlineSig:
7351                 case MonoShortInlineR:
7352                 case MonoInlineI:
7353                         ip += 5;
7354                         break;
7355                 case MonoInlineVar:
7356                         ip += 3;
7357                         break;
7358                 case MonoShortInlineVar:
7359                 case MonoShortInlineI:
7360                         ip += 2;
7361                         break;
7362                 case MonoShortInlineBrTarget:
7363                         target = start + cli_addr + 2 + (signed char)ip [1];
7364                         GET_BBLOCK (cfg, bblock, target);
7365                         ip += 2;
7366                         if (ip < end)
7367                                 GET_BBLOCK (cfg, bblock, ip);
7368                         break;
7369                 case MonoInlineBrTarget:
7370                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
7371                         GET_BBLOCK (cfg, bblock, target);
7372                         ip += 5;
7373                         if (ip < end)
7374                                 GET_BBLOCK (cfg, bblock, ip);
7375                         break;
7376                 case MonoInlineSwitch: {
7377                         guint32 n = read32 (ip + 1);
7378                         guint32 j;
7379                         ip += 5;
7380                         cli_addr += 5 + 4 * n;
7381                         target = start + cli_addr;
7382                         GET_BBLOCK (cfg, bblock, target);
7383                         
7384                         for (j = 0; j < n; ++j) {
7385                                 target = start + cli_addr + (gint32)read32 (ip);
7386                                 GET_BBLOCK (cfg, bblock, target);
7387                                 ip += 4;
7388                         }
7389                         break;
7390                 }
7391                 case MonoInlineR:
7392                 case MonoInlineI8:
7393                         ip += 9;
7394                         break;
7395                 default:
7396                         g_assert_not_reached ();
7397                 }
7398
7399                 if (i == CEE_THROW) {
7400                         unsigned char *bb_start = ip - 1;
7401                         
7402                         /* Find the start of the bblock containing the throw */
7403                         bblock = NULL;
7404                         while ((bb_start >= start) && !bblock) {
7405                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
7406                                 bb_start --;
7407                         }
7408                         if (bblock)
7409                                 bblock->out_of_line = 1;
7410                 }
7411         }
7412         return 0;
7413 unverified:
7414 exception_exit:
7415         *pos = ip;
7416         return 1;
7417 }
7418
7419 static inline MonoMethod *
7420 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context, MonoError *error)
7421 {
7422         MonoMethod *method;
7423
7424         mono_error_init (error);
7425
7426         if (m->wrapper_type != MONO_WRAPPER_NONE) {
7427                 method = (MonoMethod *)mono_method_get_wrapper_data (m, token);
7428                 if (context) {
7429                         method = mono_class_inflate_generic_method_checked (method, context, error);
7430                 }
7431         } else {
7432                 method = mono_get_method_checked (m->klass->image, token, klass, context, error);
7433         }
7434
7435         return method;
7436 }
7437
7438 static inline MonoMethod *
7439 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
7440 {
7441         MonoError error;
7442         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context, cfg ? &cfg->error : &error);
7443
7444         if (method && cfg && !cfg->gshared && mono_class_is_open_constructed_type (&method->klass->byval_arg)) {
7445                 mono_error_set_bad_image (&cfg->error, cfg->method->klass->image, "Method with open type while not compiling gshared");
7446                 method = NULL;
7447         }
7448
7449         if (!method && !cfg)
7450                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
7451
7452         return method;
7453 }
7454
7455 static inline MonoClass*
7456 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
7457 {
7458         MonoError error;
7459         MonoClass *klass;
7460
7461         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7462                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
7463                 if (context) {
7464                         klass = mono_class_inflate_generic_class_checked (klass, context, &error);
7465                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7466                 }
7467         } else {
7468                 klass = mono_class_get_and_inflate_typespec_checked (method->klass->image, token, context, &error);
7469                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
7470         }
7471         if (klass)
7472                 mono_class_init (klass);
7473         return klass;
7474 }
7475
7476 static inline MonoMethodSignature*
7477 mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context, MonoError *error)
7478 {
7479         MonoMethodSignature *fsig;
7480
7481         mono_error_init (error);
7482         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7483                 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
7484         } else {
7485                 fsig = mono_metadata_parse_signature_checked (method->klass->image, token, error);
7486                 return_val_if_nok (error, NULL);
7487         }
7488         if (context) {
7489                 fsig = mono_inflate_generic_signature(fsig, context, error);
7490         }
7491         return fsig;
7492 }
7493
7494 static MonoMethod*
7495 throw_exception (void)
7496 {
7497         static MonoMethod *method = NULL;
7498
7499         if (!method) {
7500                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
7501                 method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
7502         }
7503         g_assert (method);
7504         return method;
7505 }
7506
7507 static void
7508 emit_throw_exception (MonoCompile *cfg, MonoException *ex)
7509 {
7510         MonoMethod *thrower = throw_exception ();
7511         MonoInst *args [1];
7512
7513         EMIT_NEW_PCONST (cfg, args [0], ex);
7514         mono_emit_method_call (cfg, thrower, args, NULL);
7515 }
7516
7517 /*
7518  * Return the original method is a wrapper is specified. We can only access 
7519  * the custom attributes from the original method.
7520  */
7521 static MonoMethod*
7522 get_original_method (MonoMethod *method)
7523 {
7524         if (method->wrapper_type == MONO_WRAPPER_NONE)
7525                 return method;
7526
7527         /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
7528         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
7529                 return NULL;
7530
7531         /* in other cases we need to find the original method */
7532         return mono_marshal_method_from_wrapper (method);
7533 }
7534
7535 static void
7536 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field)
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_field_access_allowed (get_original_method (caller), field);
7540         if (ex)
7541                 emit_throw_exception (cfg, ex);
7542 }
7543
7544 static void
7545 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
7546 {
7547         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7548         MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
7549         if (ex)
7550                 emit_throw_exception (cfg, ex);
7551 }
7552
7553 /*
7554  * Check that the IL instructions at ip are the array initialization
7555  * sequence and return the pointer to the data and the size.
7556  */
7557 static const char*
7558 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
7559 {
7560         /*
7561          * newarr[System.Int32]
7562          * dup
7563          * ldtoken field valuetype ...
7564          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
7565          */
7566         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
7567                 MonoError error;
7568                 guint32 token = read32 (ip + 7);
7569                 guint32 field_token = read32 (ip + 2);
7570                 guint32 field_index = field_token & 0xffffff;
7571                 guint32 rva;
7572                 const char *data_ptr;
7573                 int size = 0;
7574                 MonoMethod *cmethod;
7575                 MonoClass *dummy_class;
7576                 MonoClassField *field = mono_field_from_token_checked (method->klass->image, field_token, &dummy_class, NULL, &error);
7577                 int dummy_align;
7578
7579                 if (!field) {
7580                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7581                         return NULL;
7582                 }
7583
7584                 *out_field_token = field_token;
7585
7586                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
7587                 if (!cmethod)
7588                         return NULL;
7589                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
7590                         return NULL;
7591                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
7592                 case MONO_TYPE_BOOLEAN:
7593                 case MONO_TYPE_I1:
7594                 case MONO_TYPE_U1:
7595                         size = 1; break;
7596                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
7597 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
7598                 case MONO_TYPE_CHAR:
7599                 case MONO_TYPE_I2:
7600                 case MONO_TYPE_U2:
7601                         size = 2; break;
7602                 case MONO_TYPE_I4:
7603                 case MONO_TYPE_U4:
7604                 case MONO_TYPE_R4:
7605                         size = 4; break;
7606                 case MONO_TYPE_R8:
7607                 case MONO_TYPE_I8:
7608                 case MONO_TYPE_U8:
7609                         size = 8; break;
7610 #endif
7611                 default:
7612                         return NULL;
7613                 }
7614                 size *= len;
7615                 if (size > mono_type_size (field->type, &dummy_align))
7616                     return NULL;
7617                 *out_size = size;
7618                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
7619                 if (!image_is_dynamic (method->klass->image)) {
7620                         field_index = read32 (ip + 2) & 0xffffff;
7621                         mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
7622                         data_ptr = mono_image_rva_map (method->klass->image, rva);
7623                         /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
7624                         /* for aot code we do the lookup on load */
7625                         if (aot && data_ptr)
7626                                 return (const char *)GUINT_TO_POINTER (rva);
7627                 } else {
7628                         /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
7629                         g_assert (!aot);
7630                         data_ptr = mono_field_get_data (field);
7631                 }
7632                 return data_ptr;
7633         }
7634         return NULL;
7635 }
7636
7637 static void
7638 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
7639 {
7640         MonoError error;
7641         char *method_fname = mono_method_full_name (method, TRUE);
7642         char *method_code;
7643         MonoMethodHeader *header = mono_method_get_header_checked (method, &error);
7644
7645         if (!header) {
7646                 method_code = g_strdup_printf ("could not parse method body due to %s", mono_error_get_message (&error));
7647                 mono_error_cleanup (&error);
7648         } else if (header->code_size == 0)
7649                 method_code = g_strdup ("method body is empty.");
7650         else
7651                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
7652         mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code));
7653         g_free (method_fname);
7654         g_free (method_code);
7655         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
7656 }
7657
7658 static void
7659 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
7660 {
7661         MonoInst *ins;
7662         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
7663         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
7664                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
7665                 /* Optimize reg-reg moves away */
7666                 /* 
7667                  * Can't optimize other opcodes, since sp[0] might point to
7668                  * the last ins of a decomposed opcode.
7669                  */
7670                 sp [0]->dreg = (cfg)->locals [n]->dreg;
7671         } else {
7672                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
7673         }
7674 }
7675
7676 /*
7677  * ldloca inhibits many optimizations so try to get rid of it in common
7678  * cases.
7679  */
7680 static inline unsigned char *
7681 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
7682 {
7683         int local, token;
7684         MonoClass *klass;
7685         MonoType *type;
7686
7687         if (size == 1) {
7688                 local = ip [1];
7689                 ip += 2;
7690         } else {
7691                 local = read16 (ip + 2);
7692                 ip += 4;
7693         }
7694         
7695         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
7696                 /* From the INITOBJ case */
7697                 token = read32 (ip + 2);
7698                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
7699                 CHECK_TYPELOAD (klass);
7700                 type = mini_get_underlying_type (&klass->byval_arg);
7701                 emit_init_local (cfg, local, type, TRUE);
7702                 return ip + 6;
7703         }
7704  exception_exit:
7705         return NULL;
7706 }
7707
7708 static MonoInst*
7709 emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used, MonoInst **sp)
7710 {
7711         MonoInst *icall_args [16];
7712         MonoInst *call_target, *ins, *vtable_ins;
7713         int arg_reg, this_reg, vtable_reg;
7714         gboolean is_iface = cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE;
7715         gboolean is_gsharedvt = cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig);
7716         gboolean variant_iface = FALSE;
7717         guint32 slot;
7718         int offset;
7719
7720         /*
7721          * In llvm-only mode, vtables contain function descriptors instead of
7722          * method addresses/trampolines.
7723          */
7724         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
7725
7726         if (is_iface)
7727                 slot = mono_method_get_imt_slot (cmethod);
7728         else
7729                 slot = mono_method_get_vtable_index (cmethod);
7730
7731         this_reg = sp [0]->dreg;
7732
7733         if (is_iface && mono_class_has_variant_generic_params (cmethod->klass))
7734                 variant_iface = TRUE;
7735
7736         if (!fsig->generic_param_count && !is_iface && !is_gsharedvt) {
7737                 /*
7738                  * The simplest case, a normal virtual call.
7739                  */
7740                 int slot_reg = alloc_preg (cfg);
7741                 int addr_reg = alloc_preg (cfg);
7742                 int arg_reg = alloc_preg (cfg);
7743                 MonoBasicBlock *non_null_bb;
7744
7745                 vtable_reg = alloc_preg (cfg);
7746                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7747                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) + (slot * SIZEOF_VOID_P);
7748
7749                 /* Load the vtable slot, which contains a function descriptor. */
7750                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7751
7752                 NEW_BBLOCK (cfg, non_null_bb);
7753
7754                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, slot_reg, 0);
7755                 cfg->cbb->last_ins->flags |= MONO_INST_LIKELY;
7756                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, non_null_bb);
7757
7758                 /* Slow path */
7759                 // FIXME: Make the wrapper use the preserveall cconv
7760                 // FIXME: Use one icall per slot for small slot numbers ?
7761                 icall_args [0] = vtable_ins;
7762                 EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7763                 /* Make the icall return the vtable slot value to save some code space */
7764                 ins = mono_emit_jit_icall (cfg, mono_init_vtable_slot, icall_args);
7765                 ins->dreg = slot_reg;
7766                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, non_null_bb);
7767
7768                 /* Fastpath */
7769                 MONO_START_BB (cfg, non_null_bb);
7770                 /* Load the address + arg from the vtable slot */
7771                 EMIT_NEW_LOAD_MEMBASE (cfg, call_target, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7772                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, arg_reg, slot_reg, SIZEOF_VOID_P);
7773
7774                 return emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
7775         }
7776
7777         if (!fsig->generic_param_count && is_iface && !variant_iface && !is_gsharedvt) {
7778                 /*
7779                  * A simple interface call
7780                  *
7781                  * We make a call through an imt slot to obtain the function descriptor we need to call.
7782                  * The imt slot contains a function descriptor for a runtime function + arg.
7783                  */
7784                 int slot_reg = alloc_preg (cfg);
7785                 int addr_reg = alloc_preg (cfg);
7786                 int arg_reg = alloc_preg (cfg);
7787                 MonoInst *thunk_addr_ins, *thunk_arg_ins, *ftndesc_ins;
7788
7789                 vtable_reg = alloc_preg (cfg);
7790                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7791                 offset = ((gint32)slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
7792
7793                 /*
7794                  * The slot is already initialized when the vtable is created so there is no need
7795                  * to check it here.
7796                  */
7797
7798                 /* Load the imt slot, which contains a function descriptor. */
7799                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7800
7801                 /* Load the address + arg of the imt thunk from the imt slot */
7802                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_addr_ins, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7803                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_arg_ins, OP_LOAD_MEMBASE, arg_reg, slot_reg, SIZEOF_VOID_P);
7804                 /*
7805                  * IMT thunks in llvm-only mode are C functions which take an info argument
7806                  * plus the imt method and return the ftndesc to call.
7807                  */
7808                 icall_args [0] = thunk_arg_ins;
7809                 icall_args [1] = emit_get_rgctx_method (cfg, context_used,
7810                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7811                 ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_trampoline, icall_args, thunk_addr_ins, NULL, NULL);
7812
7813                 return emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
7814         }
7815
7816         if ((fsig->generic_param_count || variant_iface) && !is_gsharedvt) {
7817                 /*
7818                  * This is similar to the interface case, the vtable slot points to an imt thunk which is
7819                  * dynamically extended as more instantiations are discovered.
7820                  * This handles generic virtual methods both on classes and interfaces.
7821                  */
7822                 int slot_reg = alloc_preg (cfg);
7823                 int addr_reg = alloc_preg (cfg);
7824                 int arg_reg = alloc_preg (cfg);
7825                 int ftndesc_reg = alloc_preg (cfg);
7826                 MonoInst *thunk_addr_ins, *thunk_arg_ins, *ftndesc_ins;
7827                 MonoBasicBlock *slowpath_bb, *end_bb;
7828
7829                 NEW_BBLOCK (cfg, slowpath_bb);
7830                 NEW_BBLOCK (cfg, end_bb);
7831
7832                 vtable_reg = alloc_preg (cfg);
7833                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7834                 if (is_iface)
7835                         offset = ((gint32)slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
7836                 else
7837                         offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) + (slot * SIZEOF_VOID_P);
7838
7839                 /* Load the slot, which contains a function descriptor. */
7840                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7841
7842                 /* These slots are not initialized, so fall back to the slow path until they are initialized */
7843                 /* That happens when mono_method_add_generic_virtual_invocation () creates an IMT thunk */
7844                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, slot_reg, 0);
7845                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, slowpath_bb);
7846
7847                 /* Fastpath */
7848                 /* Same as with iface calls */
7849                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_addr_ins, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7850                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_arg_ins, OP_LOAD_MEMBASE, arg_reg, slot_reg, SIZEOF_VOID_P);
7851                 icall_args [0] = thunk_arg_ins;
7852                 icall_args [1] = emit_get_rgctx_method (cfg, context_used,
7853                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7854                 ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_trampoline, icall_args, thunk_addr_ins, NULL, NULL);
7855                 ftndesc_ins->dreg = ftndesc_reg;
7856                 /*
7857                  * Unlike normal iface calls, these imt thunks can return NULL, i.e. when they are passed an instantiation
7858                  * they don't know about yet. Fall back to the slowpath in that case.
7859                  */
7860                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ftndesc_reg, 0);
7861                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, slowpath_bb);
7862
7863                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
7864
7865                 /* Slowpath */
7866                 MONO_START_BB (cfg, slowpath_bb);
7867                 icall_args [0] = vtable_ins;
7868                 EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7869                 icall_args [2] = emit_get_rgctx_method (cfg, context_used,
7870                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7871                 if (is_iface)
7872                         ftndesc_ins = mono_emit_jit_icall (cfg, mono_resolve_generic_virtual_iface_call, icall_args);
7873                 else
7874                         ftndesc_ins = mono_emit_jit_icall (cfg, mono_resolve_generic_virtual_call, icall_args);
7875                 ftndesc_ins->dreg = ftndesc_reg;
7876                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
7877
7878                 /* Common case */
7879                 MONO_START_BB (cfg, end_bb);
7880                 return emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
7881         }
7882
7883         /*
7884          * Non-optimized cases
7885          */
7886         icall_args [0] = sp [0];
7887         EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7888
7889         icall_args [2] = emit_get_rgctx_method (cfg, context_used,
7890                                                                                         cmethod, MONO_RGCTX_INFO_METHOD);
7891
7892         arg_reg = alloc_preg (cfg);
7893         MONO_EMIT_NEW_PCONST (cfg, arg_reg, NULL);
7894         EMIT_NEW_VARLOADA_VREG (cfg, icall_args [3], arg_reg, &mono_defaults.int_class->byval_arg);
7895
7896         g_assert (is_gsharedvt);
7897         if (is_iface)
7898                 call_target = mono_emit_jit_icall (cfg, mono_resolve_iface_call_gsharedvt, icall_args);
7899         else
7900                 call_target = mono_emit_jit_icall (cfg, mono_resolve_vcall_gsharedvt, icall_args);
7901
7902         /*
7903          * Pass the extra argument even if the callee doesn't receive it, most
7904          * calling conventions allow this.
7905          */
7906         return emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
7907 }
7908
7909 static gboolean
7910 is_exception_class (MonoClass *klass)
7911 {
7912         while (klass) {
7913                 if (klass == mono_defaults.exception_class)
7914                         return TRUE;
7915                 klass = klass->parent;
7916         }
7917         return FALSE;
7918 }
7919
7920 /*
7921  * is_jit_optimizer_disabled:
7922  *
7923  *   Determine whenever M's assembly has a DebuggableAttribute with the
7924  * IsJITOptimizerDisabled flag set.
7925  */
7926 static gboolean
7927 is_jit_optimizer_disabled (MonoMethod *m)
7928 {
7929         MonoError error;
7930         MonoAssembly *ass = m->klass->image->assembly;
7931         MonoCustomAttrInfo* attrs;
7932         MonoClass *klass;
7933         int i;
7934         gboolean val = FALSE;
7935
7936         g_assert (ass);
7937         if (ass->jit_optimizer_disabled_inited)
7938                 return ass->jit_optimizer_disabled;
7939
7940         klass = mono_class_try_get_debuggable_attribute_class ();
7941
7942         if (!klass) {
7943                 /* Linked away */
7944                 ass->jit_optimizer_disabled = FALSE;
7945                 mono_memory_barrier ();
7946                 ass->jit_optimizer_disabled_inited = TRUE;
7947                 return FALSE;
7948         }
7949
7950         attrs = mono_custom_attrs_from_assembly_checked (ass, &error);
7951         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7952         if (attrs) {
7953                 for (i = 0; i < attrs->num_attrs; ++i) {
7954                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
7955                         const gchar *p;
7956                         MonoMethodSignature *sig;
7957
7958                         if (!attr->ctor || attr->ctor->klass != klass)
7959                                 continue;
7960                         /* Decode the attribute. See reflection.c */
7961                         p = (const char*)attr->data;
7962                         g_assert (read16 (p) == 0x0001);
7963                         p += 2;
7964
7965                         // FIXME: Support named parameters
7966                         sig = mono_method_signature (attr->ctor);
7967                         if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
7968                                 continue;
7969                         /* Two boolean arguments */
7970                         p ++;
7971                         val = *p;
7972                 }
7973                 mono_custom_attrs_free (attrs);
7974         }
7975
7976         ass->jit_optimizer_disabled = val;
7977         mono_memory_barrier ();
7978         ass->jit_optimizer_disabled_inited = TRUE;
7979
7980         return val;
7981 }
7982
7983 static gboolean
7984 is_supported_tail_call (MonoCompile *cfg, MonoMethod *method, MonoMethod *cmethod, MonoMethodSignature *fsig, int call_opcode)
7985 {
7986         gboolean supported_tail_call;
7987         int i;
7988
7989         supported_tail_call = mono_arch_tail_call_supported (cfg, mono_method_signature (method), mono_method_signature (cmethod));
7990
7991         for (i = 0; i < fsig->param_count; ++i) {
7992                 if (fsig->params [i]->byref || fsig->params [i]->type == MONO_TYPE_PTR || fsig->params [i]->type == MONO_TYPE_FNPTR)
7993                         /* These can point to the current method's stack */
7994                         supported_tail_call = FALSE;
7995         }
7996         if (fsig->hasthis && cmethod->klass->valuetype)
7997                 /* this might point to the current method's stack */
7998                 supported_tail_call = FALSE;
7999         if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
8000                 supported_tail_call = FALSE;
8001         if (cfg->method->save_lmf)
8002                 supported_tail_call = FALSE;
8003         if (cmethod->wrapper_type && cmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
8004                 supported_tail_call = FALSE;
8005         if (call_opcode != CEE_CALL)
8006                 supported_tail_call = FALSE;
8007
8008         /* Debugging support */
8009 #if 0
8010         if (supported_tail_call) {
8011                 if (!mono_debug_count ())
8012                         supported_tail_call = FALSE;
8013         }
8014 #endif
8015
8016         return supported_tail_call;
8017 }
8018
8019 /*
8020  * handle_ctor_call:
8021  *
8022  *   Handle calls made to ctors from NEWOBJ opcodes.
8023  */
8024 static void
8025 handle_ctor_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used,
8026                                   MonoInst **sp, guint8 *ip, int *inline_costs)
8027 {
8028         MonoInst *vtable_arg = NULL, *callvirt_this_arg = NULL, *ins;
8029
8030         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
8031                                         mono_method_is_generic_sharable (cmethod, TRUE)) {
8032                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
8033                         mono_class_vtable (cfg->domain, cmethod->klass);
8034                         CHECK_TYPELOAD (cmethod->klass);
8035
8036                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
8037                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
8038                 } else {
8039                         if (context_used) {
8040                                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
8041                                                                                                    cmethod->klass, MONO_RGCTX_INFO_VTABLE);
8042                         } else {
8043                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
8044
8045                                 CHECK_TYPELOAD (cmethod->klass);
8046                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
8047                         }
8048                 }
8049         }
8050
8051         /* Avoid virtual calls to ctors if possible */
8052         if (mono_class_is_marshalbyref (cmethod->klass))
8053                 callvirt_this_arg = sp [0];
8054
8055         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
8056                 g_assert (MONO_TYPE_IS_VOID (fsig->ret));
8057                 CHECK_CFG_EXCEPTION;
8058         } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
8059                            mono_method_check_inlining (cfg, cmethod) &&
8060                            !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE)) {
8061                 int costs;
8062
8063                 if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, FALSE))) {
8064                         cfg->real_offset += 5;
8065
8066                         *inline_costs += costs - 5;
8067                 } else {
8068                         INLINE_FAILURE ("inline failure");
8069                         // FIXME-VT: Clean this up
8070                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
8071                                 GSHAREDVT_FAILURE(*ip);
8072                         mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, callvirt_this_arg, NULL, NULL);
8073                 }
8074         } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
8075                 MonoInst *addr;
8076
8077                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
8078
8079                 if (cfg->llvm_only) {
8080                         // FIXME: Avoid initializing vtable_arg
8081                         emit_llvmonly_calli (cfg, fsig, sp, addr);
8082                 } else {
8083                         mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
8084                 }
8085         } else if (context_used &&
8086                            ((!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
8087                                  !mono_class_generic_sharing_enabled (cmethod->klass)) || cfg->gsharedvt)) {
8088                 MonoInst *cmethod_addr;
8089
8090                 /* Generic calls made out of gsharedvt methods cannot be patched, so use an indirect call */
8091
8092                 if (cfg->llvm_only) {
8093                         MonoInst *addr = emit_get_rgctx_method (cfg, context_used, cmethod,
8094                                                                                                         MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
8095                         emit_llvmonly_calli (cfg, fsig, sp, addr);
8096                 } else {
8097                         cmethod_addr = emit_get_rgctx_method (cfg, context_used,
8098                                                                                                   cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
8099
8100                         mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
8101                 }
8102         } else {
8103                 INLINE_FAILURE ("ctor call");
8104                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
8105                                                                                   callvirt_this_arg, NULL, vtable_arg);
8106         }
8107  exception_exit:
8108         return;
8109 }
8110
8111 static void
8112 emit_setret (MonoCompile *cfg, MonoInst *val)
8113 {
8114         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (cfg->method)->ret);
8115         MonoInst *ins;
8116
8117         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
8118                 MonoInst *ret_addr;
8119
8120                 if (!cfg->vret_addr) {
8121                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, val);
8122                 } else {
8123                         EMIT_NEW_RETLOADA (cfg, ret_addr);
8124
8125                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, val->dreg);
8126                         ins->klass = mono_class_from_mono_type (ret_type);
8127                 }
8128         } else {
8129 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
8130                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
8131                         MonoInst *iargs [1];
8132                         MonoInst *conv;
8133
8134                         iargs [0] = val;
8135                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
8136                         mono_arch_emit_setret (cfg, cfg->method, conv);
8137                 } else {
8138                         mono_arch_emit_setret (cfg, cfg->method, val);
8139                 }
8140 #else
8141                 mono_arch_emit_setret (cfg, cfg->method, val);
8142 #endif
8143         }
8144 }
8145
8146 /*
8147  * mono_method_to_ir:
8148  *
8149  *   Translate the .net IL into linear IR.
8150  */
8151 int
8152 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
8153                    MonoInst *return_var, MonoInst **inline_args, 
8154                    guint inline_offset, gboolean is_virtual_call)
8155 {
8156         MonoError error;
8157         MonoInst *ins, **sp, **stack_start;
8158         MonoBasicBlock *tblock = NULL, *init_localsbb = NULL;
8159         MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
8160         MonoMethod *cmethod, *method_definition;
8161         MonoInst **arg_array;
8162         MonoMethodHeader *header;
8163         MonoImage *image;
8164         guint32 token, ins_flag;
8165         MonoClass *klass;
8166         MonoClass *constrained_class = NULL;
8167         unsigned char *ip, *end, *target, *err_pos;
8168         MonoMethodSignature *sig;
8169         MonoGenericContext *generic_context = NULL;
8170         MonoGenericContainer *generic_container = NULL;
8171         MonoType **param_types;
8172         int i, n, start_new_bblock, dreg;
8173         int num_calls = 0, inline_costs = 0;
8174         int breakpoint_id = 0;
8175         guint num_args;
8176         GSList *class_inits = NULL;
8177         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
8178         int context_used;
8179         gboolean init_locals, seq_points, skip_dead_blocks;
8180         gboolean sym_seq_points = FALSE;
8181         MonoDebugMethodInfo *minfo;
8182         MonoBitSet *seq_point_locs = NULL;
8183         MonoBitSet *seq_point_set_locs = NULL;
8184
8185         cfg->disable_inline = is_jit_optimizer_disabled (method);
8186
8187         /* serialization and xdomain stuff may need access to private fields and methods */
8188         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
8189         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
8190         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
8191         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
8192         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
8193         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
8194
8195         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
8196         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
8197         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
8198         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
8199         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF;
8200
8201         image = method->klass->image;
8202         header = mono_method_get_header_checked (method, &cfg->error);
8203         if (!header) {
8204                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
8205                 goto exception_exit;
8206         } else {
8207                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
8208         }
8209
8210         generic_container = mono_method_get_generic_container (method);
8211         sig = mono_method_signature (method);
8212         num_args = sig->hasthis + sig->param_count;
8213         ip = (unsigned char*)header->code;
8214         cfg->cil_start = ip;
8215         end = ip + header->code_size;
8216         cfg->stat_cil_code_size += header->code_size;
8217
8218         seq_points = cfg->gen_seq_points && cfg->method == method;
8219
8220         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
8221                 /* We could hit a seq point before attaching to the JIT (#8338) */
8222                 seq_points = FALSE;
8223         }
8224
8225         if (cfg->gen_sdb_seq_points && cfg->method == method) {
8226                 minfo = mono_debug_lookup_method (method);
8227                 if (minfo) {
8228                         MonoSymSeqPoint *sps;
8229                         int i, n_il_offsets;
8230
8231                         mono_debug_get_seq_points (minfo, NULL, NULL, NULL, &sps, &n_il_offsets);
8232                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
8233                         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);
8234                         sym_seq_points = TRUE;
8235                         for (i = 0; i < n_il_offsets; ++i) {
8236                                 if (sps [i].il_offset < header->code_size)
8237                                         mono_bitset_set_fast (seq_point_locs, sps [i].il_offset);
8238                         }
8239                         g_free (sps);
8240                 } else if (!method->wrapper_type && !method->dynamic && mono_debug_image_has_debug_info (method->klass->image)) {
8241                         /* Methods without line number info like auto-generated property accessors */
8242                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
8243                         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);
8244                         sym_seq_points = TRUE;
8245                 }
8246         }
8247
8248         /* 
8249          * Methods without init_locals set could cause asserts in various passes
8250          * (#497220). To work around this, we emit dummy initialization opcodes
8251          * (OP_DUMMY_ICONST etc.) which generate no code. These are only supported
8252          * on some platforms.
8253          */
8254         if ((cfg->opt & MONO_OPT_UNSAFE) && cfg->backend->have_dummy_init)
8255                 init_locals = header->init_locals;
8256         else
8257                 init_locals = TRUE;
8258
8259         method_definition = method;
8260         while (method_definition->is_inflated) {
8261                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
8262                 method_definition = imethod->declaring;
8263         }
8264
8265         /* SkipVerification is not allowed if core-clr is enabled */
8266         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
8267                 dont_verify = TRUE;
8268                 dont_verify_stloc = TRUE;
8269         }
8270
8271         if (sig->is_inflated)
8272                 generic_context = mono_method_get_context (method);
8273         else if (generic_container)
8274                 generic_context = &generic_container->context;
8275         cfg->generic_context = generic_context;
8276
8277         if (!cfg->gshared)
8278                 g_assert (!sig->has_type_parameters);
8279
8280         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
8281                 g_assert (method->is_inflated);
8282                 g_assert (mono_method_get_context (method)->method_inst);
8283         }
8284         if (method->is_inflated && mono_method_get_context (method)->method_inst)
8285                 g_assert (sig->generic_param_count);
8286
8287         if (cfg->method == method) {
8288                 cfg->real_offset = 0;
8289         } else {
8290                 cfg->real_offset = inline_offset;
8291         }
8292
8293         cfg->cil_offset_to_bb = (MonoBasicBlock **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
8294         cfg->cil_offset_to_bb_len = header->code_size;
8295
8296         cfg->current_method = method;
8297
8298         if (cfg->verbose_level > 2)
8299                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
8300
8301         param_types = (MonoType **)mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
8302         if (sig->hasthis)
8303                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
8304         for (n = 0; n < sig->param_count; ++n)
8305                 param_types [n + sig->hasthis] = sig->params [n];
8306         cfg->arg_types = param_types;
8307
8308         cfg->dont_inline = g_list_prepend (cfg->dont_inline, method);
8309         if (cfg->method == method) {
8310
8311                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
8312                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
8313
8314                 /* ENTRY BLOCK */
8315                 NEW_BBLOCK (cfg, start_bblock);
8316                 cfg->bb_entry = start_bblock;
8317                 start_bblock->cil_code = NULL;
8318                 start_bblock->cil_length = 0;
8319
8320                 /* EXIT BLOCK */
8321                 NEW_BBLOCK (cfg, end_bblock);
8322                 cfg->bb_exit = end_bblock;
8323                 end_bblock->cil_code = NULL;
8324                 end_bblock->cil_length = 0;
8325                 end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
8326                 g_assert (cfg->num_bblocks == 2);
8327
8328                 arg_array = cfg->args;
8329
8330                 if (header->num_clauses) {
8331                         cfg->spvars = g_hash_table_new (NULL, NULL);
8332                         cfg->exvars = g_hash_table_new (NULL, NULL);
8333                 }
8334                 /* handle exception clauses */
8335                 for (i = 0; i < header->num_clauses; ++i) {
8336                         MonoBasicBlock *try_bb;
8337                         MonoExceptionClause *clause = &header->clauses [i];
8338                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
8339
8340                         try_bb->real_offset = clause->try_offset;
8341                         try_bb->try_start = TRUE;
8342                         try_bb->region = ((i + 1) << 8) | clause->flags;
8343                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
8344                         tblock->real_offset = clause->handler_offset;
8345                         tblock->flags |= BB_EXCEPTION_HANDLER;
8346
8347                         /*
8348                          * Linking the try block with the EH block hinders inlining as we won't be able to 
8349                          * merge the bblocks from inlining and produce an artificial hole for no good reason.
8350                          */
8351                         if (COMPILE_LLVM (cfg))
8352                                 link_bblock (cfg, try_bb, tblock);
8353
8354                         if (*(ip + clause->handler_offset) == CEE_POP)
8355                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
8356
8357                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
8358                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
8359                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
8360                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
8361                                 MONO_ADD_INS (tblock, ins);
8362
8363                                 if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FILTER) {
8364                                         /* finally clauses already have a seq point */
8365                                         /* seq points for filter clauses are emitted below */
8366                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
8367                                         MONO_ADD_INS (tblock, ins);
8368                                 }
8369
8370                                 /* todo: is a fault block unsafe to optimize? */
8371                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
8372                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
8373                         }
8374
8375                         /*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);
8376                           while (p < end) {
8377                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
8378                           }*/
8379                         /* catch and filter blocks get the exception object on the stack */
8380                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
8381                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8382
8383                                 /* mostly like handle_stack_args (), but just sets the input args */
8384                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
8385                                 tblock->in_scount = 1;
8386                                 tblock->in_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
8387                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
8388
8389                                 cfg->cbb = tblock;
8390
8391 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
8392                                 /* The EH code passes in the exception in a register to both JITted and LLVM compiled code */
8393                                 if (!cfg->compile_llvm) {
8394                                         MONO_INST_NEW (cfg, ins, OP_GET_EX_OBJ);
8395                                         ins->dreg = tblock->in_stack [0]->dreg;
8396                                         MONO_ADD_INS (tblock, ins);
8397                                 }
8398 #else
8399                                 MonoInst *dummy_use;
8400
8401                                 /* 
8402                                  * Add a dummy use for the exvar so its liveness info will be
8403                                  * correct.
8404                                  */
8405                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
8406 #endif
8407
8408                                 if (seq_points && clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8409                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
8410                                         MONO_ADD_INS (tblock, ins);
8411                                 }
8412                                 
8413                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8414                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
8415                                         tblock->flags |= BB_EXCEPTION_HANDLER;
8416                                         tblock->real_offset = clause->data.filter_offset;
8417                                         tblock->in_scount = 1;
8418                                         tblock->in_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
8419                                         /* The filter block shares the exvar with the handler block */
8420                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
8421                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
8422                                         MONO_ADD_INS (tblock, ins);
8423                                 }
8424                         }
8425
8426                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
8427                                         clause->data.catch_class &&
8428                                         cfg->gshared &&
8429                                         mono_class_check_context_used (clause->data.catch_class)) {
8430                                 /*
8431                                  * In shared generic code with catch
8432                                  * clauses containing type variables
8433                                  * the exception handling code has to
8434                                  * be able to get to the rgctx.
8435                                  * Therefore we have to make sure that
8436                                  * the vtable/mrgctx argument (for
8437                                  * static or generic methods) or the
8438                                  * "this" argument (for non-static
8439                                  * methods) are live.
8440                                  */
8441                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8442                                                 mini_method_get_context (method)->method_inst ||
8443                                                 method->klass->valuetype) {
8444                                         mono_get_vtable_var (cfg);
8445                                 } else {
8446                                         MonoInst *dummy_use;
8447
8448                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
8449                                 }
8450                         }
8451                 }
8452         } else {
8453                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
8454                 cfg->cbb = start_bblock;
8455                 cfg->args = arg_array;
8456                 mono_save_args (cfg, sig, inline_args);
8457         }
8458
8459         /* FIRST CODE BLOCK */
8460         NEW_BBLOCK (cfg, tblock);
8461         tblock->cil_code = ip;
8462         cfg->cbb = tblock;
8463         cfg->ip = ip;
8464
8465         ADD_BBLOCK (cfg, tblock);
8466
8467         if (cfg->method == method) {
8468                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
8469                 if (breakpoint_id) {
8470                         MONO_INST_NEW (cfg, ins, OP_BREAK);
8471                         MONO_ADD_INS (cfg->cbb, ins);
8472                 }
8473         }
8474
8475         /* we use a separate basic block for the initialization code */
8476         NEW_BBLOCK (cfg, init_localsbb);
8477         cfg->bb_init = init_localsbb;
8478         init_localsbb->real_offset = cfg->real_offset;
8479         start_bblock->next_bb = init_localsbb;
8480         init_localsbb->next_bb = cfg->cbb;
8481         link_bblock (cfg, start_bblock, init_localsbb);
8482         link_bblock (cfg, init_localsbb, cfg->cbb);
8483                 
8484         cfg->cbb = init_localsbb;
8485
8486         if (cfg->gsharedvt && cfg->method == method) {
8487                 MonoGSharedVtMethodInfo *info;
8488                 MonoInst *var, *locals_var;
8489                 int dreg;
8490
8491                 info = (MonoGSharedVtMethodInfo *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoGSharedVtMethodInfo));
8492                 info->method = cfg->method;
8493                 info->count_entries = 16;
8494                 info->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
8495                 cfg->gsharedvt_info = info;
8496
8497                 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8498                 /* prevent it from being register allocated */
8499                 //var->flags |= MONO_INST_VOLATILE;
8500                 cfg->gsharedvt_info_var = var;
8501
8502                 ins = emit_get_rgctx_gsharedvt_method (cfg, mini_method_check_context_used (cfg, method), method, info);
8503                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, var->dreg, ins->dreg);
8504
8505                 /* Allocate locals */
8506                 locals_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8507                 /* prevent it from being register allocated */
8508                 //locals_var->flags |= MONO_INST_VOLATILE;
8509                 cfg->gsharedvt_locals_var = locals_var;
8510
8511                 dreg = alloc_ireg (cfg);
8512                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, dreg, var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, locals_size));
8513
8514                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
8515                 ins->dreg = locals_var->dreg;
8516                 ins->sreg1 = dreg;
8517                 MONO_ADD_INS (cfg->cbb, ins);
8518                 cfg->gsharedvt_locals_var_ins = ins;
8519                 
8520                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
8521                 /*
8522                 if (init_locals)
8523                         ins->flags |= MONO_INST_INIT;
8524                 */
8525         }
8526
8527         if (mono_security_core_clr_enabled ()) {
8528                 /* check if this is native code, e.g. an icall or a p/invoke */
8529                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
8530                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
8531                         if (wrapped) {
8532                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
8533                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
8534
8535                                 /* if this ia a native call then it can only be JITted from platform code */
8536                                 if ((icall || pinvk) && method->klass && method->klass->image) {
8537                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
8538                                                 MonoException *ex = icall ? mono_get_exception_security () : 
8539                                                         mono_get_exception_method_access ();
8540                                                 emit_throw_exception (cfg, ex);
8541                                         }
8542                                 }
8543                         }
8544                 }
8545         }
8546
8547         CHECK_CFG_EXCEPTION;
8548
8549         if (header->code_size == 0)
8550                 UNVERIFIED;
8551
8552         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
8553                 ip = err_pos;
8554                 UNVERIFIED;
8555         }
8556
8557         if (cfg->method == method)
8558                 mono_debug_init_method (cfg, cfg->cbb, breakpoint_id);
8559
8560         for (n = 0; n < header->num_locals; ++n) {
8561                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
8562                         UNVERIFIED;
8563         }
8564         class_inits = NULL;
8565
8566         /* We force the vtable variable here for all shared methods
8567            for the possibility that they might show up in a stack
8568            trace where their exact instantiation is needed. */
8569         if (cfg->gshared && method == cfg->method) {
8570                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8571                                 mini_method_get_context (method)->method_inst ||
8572                                 method->klass->valuetype) {
8573                         mono_get_vtable_var (cfg);
8574                 } else {
8575                         /* FIXME: Is there a better way to do this?
8576                            We need the variable live for the duration
8577                            of the whole method. */
8578                         cfg->args [0]->flags |= MONO_INST_VOLATILE;
8579                 }
8580         }
8581
8582         /* add a check for this != NULL to inlined methods */
8583         if (is_virtual_call) {
8584                 MonoInst *arg_ins;
8585
8586                 NEW_ARGLOAD (cfg, arg_ins, 0);
8587                 MONO_ADD_INS (cfg->cbb, arg_ins);
8588                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
8589         }
8590
8591         skip_dead_blocks = !dont_verify;
8592         if (skip_dead_blocks) {
8593                 original_bb = bb = mono_basic_block_split (method, &cfg->error, header);
8594                 CHECK_CFG_ERROR;
8595                 g_assert (bb);
8596         }
8597
8598         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
8599         stack_start = sp = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
8600
8601         ins_flag = 0;
8602         start_new_bblock = 0;
8603         while (ip < end) {
8604                 if (cfg->method == method)
8605                         cfg->real_offset = ip - header->code;
8606                 else
8607                         cfg->real_offset = inline_offset;
8608                 cfg->ip = ip;
8609
8610                 context_used = 0;
8611
8612                 if (start_new_bblock) {
8613                         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
8614                         if (start_new_bblock == 2) {
8615                                 g_assert (ip == tblock->cil_code);
8616                         } else {
8617                                 GET_BBLOCK (cfg, tblock, ip);
8618                         }
8619                         cfg->cbb->next_bb = tblock;
8620                         cfg->cbb = tblock;
8621                         start_new_bblock = 0;
8622                         for (i = 0; i < cfg->cbb->in_scount; ++i) {
8623                                 if (cfg->verbose_level > 3)
8624                                         printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8625                                 EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8626                                 *sp++ = ins;
8627                         }
8628                         if (class_inits)
8629                                 g_slist_free (class_inits);
8630                         class_inits = NULL;
8631                 } else {
8632                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != cfg->cbb)) {
8633                                 link_bblock (cfg, cfg->cbb, tblock);
8634                                 if (sp != stack_start) {
8635                                         handle_stack_args (cfg, stack_start, sp - stack_start);
8636                                         sp = stack_start;
8637                                         CHECK_UNVERIFIABLE (cfg);
8638                                 }
8639                                 cfg->cbb->next_bb = tblock;
8640                                 cfg->cbb = tblock;
8641                                 for (i = 0; i < cfg->cbb->in_scount; ++i) {
8642                                         if (cfg->verbose_level > 3)
8643                                                 printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8644                                         EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8645                                         *sp++ = ins;
8646                                 }
8647                                 g_slist_free (class_inits);
8648                                 class_inits = NULL;
8649                         }
8650                 }
8651
8652                 if (skip_dead_blocks) {
8653                         int ip_offset = ip - header->code;
8654
8655                         if (ip_offset == bb->end)
8656                                 bb = bb->next;
8657
8658                         if (bb->dead) {
8659                                 int op_size = mono_opcode_size (ip, end);
8660                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
8661
8662                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
8663
8664                                 if (ip_offset + op_size == bb->end) {
8665                                         MONO_INST_NEW (cfg, ins, OP_NOP);
8666                                         MONO_ADD_INS (cfg->cbb, ins);
8667                                         start_new_bblock = 1;
8668                                 }
8669
8670                                 ip += op_size;
8671                                 continue;
8672                         }
8673                 }
8674                 /*
8675                  * Sequence points are points where the debugger can place a breakpoint.
8676                  * Currently, we generate these automatically at points where the IL
8677                  * stack is empty.
8678                  */
8679                 if (seq_points && ((!sym_seq_points && (sp == stack_start)) || (sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code)))) {
8680                         /*
8681                          * Make methods interruptable at the beginning, and at the targets of
8682                          * backward branches.
8683                          * Also, do this at the start of every bblock in methods with clauses too,
8684                          * to be able to handle instructions with inprecise control flow like
8685                          * throw/endfinally.
8686                          * Backward branches are handled at the end of method-to-ir ().
8687                          */
8688                         gboolean intr_loc = ip == header->code || (!cfg->cbb->last_ins && cfg->header->num_clauses);
8689                         gboolean sym_seq_point = sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code);
8690
8691                         /* Avoid sequence points on empty IL like .volatile */
8692                         // FIXME: Enable this
8693                         //if (!(cfg->cbb->last_ins && cfg->cbb->last_ins->opcode == OP_SEQ_POINT)) {
8694                         NEW_SEQ_POINT (cfg, ins, ip - header->code, intr_loc);
8695                         if ((sp != stack_start) && !sym_seq_point)
8696                                 ins->flags |= MONO_INST_NONEMPTY_STACK;
8697                         MONO_ADD_INS (cfg->cbb, ins);
8698
8699                         if (sym_seq_points)
8700                                 mono_bitset_set_fast (seq_point_set_locs, ip - header->code);
8701                 }
8702
8703                 cfg->cbb->real_offset = cfg->real_offset;
8704
8705                 if ((cfg->method == method) && cfg->coverage_info) {
8706                         guint32 cil_offset = ip - header->code;
8707                         cfg->coverage_info->data [cil_offset].cil_code = ip;
8708
8709                         /* TODO: Use an increment here */
8710 #if defined(TARGET_X86)
8711                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
8712                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
8713                         ins->inst_imm = 1;
8714                         MONO_ADD_INS (cfg->cbb, ins);
8715 #else
8716                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
8717                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
8718 #endif
8719                 }
8720
8721                 if (cfg->verbose_level > 3)
8722                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
8723
8724                 switch (*ip) {
8725                 case CEE_NOP:
8726                         if (seq_points && !sym_seq_points && sp != stack_start) {
8727                                 /*
8728                                  * The C# compiler uses these nops to notify the JIT that it should
8729                                  * insert seq points.
8730                                  */
8731                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, FALSE);
8732                                 MONO_ADD_INS (cfg->cbb, ins);
8733                         }
8734                         if (cfg->keep_cil_nops)
8735                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
8736                         else
8737                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8738                         ip++;
8739                         MONO_ADD_INS (cfg->cbb, ins);
8740                         break;
8741                 case CEE_BREAK:
8742                         if (should_insert_brekpoint (cfg->method)) {
8743                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
8744                         } else {
8745                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8746                         }
8747                         ip++;
8748                         MONO_ADD_INS (cfg->cbb, ins);
8749                         break;
8750                 case CEE_LDARG_0:
8751                 case CEE_LDARG_1:
8752                 case CEE_LDARG_2:
8753                 case CEE_LDARG_3:
8754                         CHECK_STACK_OVF (1);
8755                         n = (*ip)-CEE_LDARG_0;
8756                         CHECK_ARG (n);
8757                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8758                         ip++;
8759                         *sp++ = ins;
8760                         break;
8761                 case CEE_LDLOC_0:
8762                 case CEE_LDLOC_1:
8763                 case CEE_LDLOC_2:
8764                 case CEE_LDLOC_3:
8765                         CHECK_STACK_OVF (1);
8766                         n = (*ip)-CEE_LDLOC_0;
8767                         CHECK_LOCAL (n);
8768                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8769                         ip++;
8770                         *sp++ = ins;
8771                         break;
8772                 case CEE_STLOC_0:
8773                 case CEE_STLOC_1:
8774                 case CEE_STLOC_2:
8775                 case CEE_STLOC_3: {
8776                         CHECK_STACK (1);
8777                         n = (*ip)-CEE_STLOC_0;
8778                         CHECK_LOCAL (n);
8779                         --sp;
8780                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
8781                                 UNVERIFIED;
8782                         emit_stloc_ir (cfg, sp, header, n);
8783                         ++ip;
8784                         inline_costs += 1;
8785                         break;
8786                         }
8787                 case CEE_LDARG_S:
8788                         CHECK_OPSIZE (2);
8789                         CHECK_STACK_OVF (1);
8790                         n = ip [1];
8791                         CHECK_ARG (n);
8792                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8793                         *sp++ = ins;
8794                         ip += 2;
8795                         break;
8796                 case CEE_LDARGA_S:
8797                         CHECK_OPSIZE (2);
8798                         CHECK_STACK_OVF (1);
8799                         n = ip [1];
8800                         CHECK_ARG (n);
8801                         NEW_ARGLOADA (cfg, ins, n);
8802                         MONO_ADD_INS (cfg->cbb, ins);
8803                         *sp++ = ins;
8804                         ip += 2;
8805                         break;
8806                 case CEE_STARG_S:
8807                         CHECK_OPSIZE (2);
8808                         CHECK_STACK (1);
8809                         --sp;
8810                         n = ip [1];
8811                         CHECK_ARG (n);
8812                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
8813                                 UNVERIFIED;
8814                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
8815                         ip += 2;
8816                         break;
8817                 case CEE_LDLOC_S:
8818                         CHECK_OPSIZE (2);
8819                         CHECK_STACK_OVF (1);
8820                         n = ip [1];
8821                         CHECK_LOCAL (n);
8822                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8823                         *sp++ = ins;
8824                         ip += 2;
8825                         break;
8826                 case CEE_LDLOCA_S: {
8827                         unsigned char *tmp_ip;
8828                         CHECK_OPSIZE (2);
8829                         CHECK_STACK_OVF (1);
8830                         CHECK_LOCAL (ip [1]);
8831
8832                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
8833                                 ip = tmp_ip;
8834                                 inline_costs += 1;
8835                                 break;
8836                         }
8837
8838                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
8839                         *sp++ = ins;
8840                         ip += 2;
8841                         break;
8842                 }
8843                 case CEE_STLOC_S:
8844                         CHECK_OPSIZE (2);
8845                         CHECK_STACK (1);
8846                         --sp;
8847                         CHECK_LOCAL (ip [1]);
8848                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
8849                                 UNVERIFIED;
8850                         emit_stloc_ir (cfg, sp, header, ip [1]);
8851                         ip += 2;
8852                         inline_costs += 1;
8853                         break;
8854                 case CEE_LDNULL:
8855                         CHECK_STACK_OVF (1);
8856                         EMIT_NEW_PCONST (cfg, ins, NULL);
8857                         ins->type = STACK_OBJ;
8858                         ++ip;
8859                         *sp++ = ins;
8860                         break;
8861                 case CEE_LDC_I4_M1:
8862                         CHECK_STACK_OVF (1);
8863                         EMIT_NEW_ICONST (cfg, ins, -1);
8864                         ++ip;
8865                         *sp++ = ins;
8866                         break;
8867                 case CEE_LDC_I4_0:
8868                 case CEE_LDC_I4_1:
8869                 case CEE_LDC_I4_2:
8870                 case CEE_LDC_I4_3:
8871                 case CEE_LDC_I4_4:
8872                 case CEE_LDC_I4_5:
8873                 case CEE_LDC_I4_6:
8874                 case CEE_LDC_I4_7:
8875                 case CEE_LDC_I4_8:
8876                         CHECK_STACK_OVF (1);
8877                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
8878                         ++ip;
8879                         *sp++ = ins;
8880                         break;
8881                 case CEE_LDC_I4_S:
8882                         CHECK_OPSIZE (2);
8883                         CHECK_STACK_OVF (1);
8884                         ++ip;
8885                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
8886                         ++ip;
8887                         *sp++ = ins;
8888                         break;
8889                 case CEE_LDC_I4:
8890                         CHECK_OPSIZE (5);
8891                         CHECK_STACK_OVF (1);
8892                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
8893                         ip += 5;
8894                         *sp++ = ins;
8895                         break;
8896                 case CEE_LDC_I8:
8897                         CHECK_OPSIZE (9);
8898                         CHECK_STACK_OVF (1);
8899                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
8900                         ins->type = STACK_I8;
8901                         ins->dreg = alloc_dreg (cfg, STACK_I8);
8902                         ++ip;
8903                         ins->inst_l = (gint64)read64 (ip);
8904                         MONO_ADD_INS (cfg->cbb, ins);
8905                         ip += 8;
8906                         *sp++ = ins;
8907                         break;
8908                 case CEE_LDC_R4: {
8909                         float *f;
8910                         gboolean use_aotconst = FALSE;
8911
8912 #ifdef TARGET_POWERPC
8913                         /* FIXME: Clean this up */
8914                         if (cfg->compile_aot)
8915                                 use_aotconst = TRUE;
8916 #endif
8917
8918                         /* FIXME: we should really allocate this only late in the compilation process */
8919                         f = (float *)mono_domain_alloc (cfg->domain, sizeof (float));
8920                         CHECK_OPSIZE (5);
8921                         CHECK_STACK_OVF (1);
8922
8923                         if (use_aotconst) {
8924                                 MonoInst *cons;
8925                                 int dreg;
8926
8927                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
8928
8929                                 dreg = alloc_freg (cfg);
8930                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
8931                                 ins->type = cfg->r4_stack_type;
8932                         } else {
8933                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
8934                                 ins->type = cfg->r4_stack_type;
8935                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8936                                 ins->inst_p0 = f;
8937                                 MONO_ADD_INS (cfg->cbb, ins);
8938                         }
8939                         ++ip;
8940                         readr4 (ip, f);
8941                         ip += 4;
8942                         *sp++ = ins;                    
8943                         break;
8944                 }
8945                 case CEE_LDC_R8: {
8946                         double *d;
8947                         gboolean use_aotconst = FALSE;
8948
8949 #ifdef TARGET_POWERPC
8950                         /* FIXME: Clean this up */
8951                         if (cfg->compile_aot)
8952                                 use_aotconst = TRUE;
8953 #endif
8954
8955                         /* FIXME: we should really allocate this only late in the compilation process */
8956                         d = (double *)mono_domain_alloc (cfg->domain, sizeof (double));
8957                         CHECK_OPSIZE (9);
8958                         CHECK_STACK_OVF (1);
8959
8960                         if (use_aotconst) {
8961                                 MonoInst *cons;
8962                                 int dreg;
8963
8964                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
8965
8966                                 dreg = alloc_freg (cfg);
8967                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
8968                                 ins->type = STACK_R8;
8969                         } else {
8970                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
8971                                 ins->type = STACK_R8;
8972                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8973                                 ins->inst_p0 = d;
8974                                 MONO_ADD_INS (cfg->cbb, ins);
8975                         }
8976                         ++ip;
8977                         readr8 (ip, d);
8978                         ip += 8;
8979                         *sp++ = ins;
8980                         break;
8981                 }
8982                 case CEE_DUP: {
8983                         MonoInst *temp, *store;
8984                         CHECK_STACK (1);
8985                         CHECK_STACK_OVF (1);
8986                         sp--;
8987                         ins = *sp;
8988
8989                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
8990                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
8991
8992                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8993                         *sp++ = ins;
8994
8995                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8996                         *sp++ = ins;
8997
8998                         ++ip;
8999                         inline_costs += 2;
9000                         break;
9001                 }
9002                 case CEE_POP:
9003                         CHECK_STACK (1);
9004                         ip++;
9005                         --sp;
9006
9007 #ifdef TARGET_X86
9008                         if (sp [0]->type == STACK_R8)
9009                                 /* we need to pop the value from the x86 FP stack */
9010                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
9011 #endif
9012                         break;
9013                 case CEE_JMP: {
9014                         MonoCallInst *call;
9015                         MonoMethodSignature *fsig;
9016                         int i, n;
9017
9018                         INLINE_FAILURE ("jmp");
9019                         GSHAREDVT_FAILURE (*ip);
9020
9021                         CHECK_OPSIZE (5);
9022                         if (stack_start != sp)
9023                                 UNVERIFIED;
9024                         token = read32 (ip + 1);
9025                         /* FIXME: check the signature matches */
9026                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
9027                         CHECK_CFG_ERROR;
9028  
9029                         if (cfg->gshared && mono_method_check_context_used (cmethod))
9030                                 GENERIC_SHARING_FAILURE (CEE_JMP);
9031
9032                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
9033
9034                         fsig = mono_method_signature (cmethod);
9035                         n = fsig->param_count + fsig->hasthis;
9036                         if (cfg->llvm_only) {
9037                                 MonoInst **args;
9038
9039                                 args = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
9040                                 for (i = 0; i < n; ++i)
9041                                         EMIT_NEW_ARGLOAD (cfg, args [i], i);
9042                                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, TRUE, args, NULL, NULL, NULL);
9043                                 /*
9044                                  * The code in mono-basic-block.c treats the rest of the code as dead, but we
9045                                  * have to emit a normal return since llvm expects it.
9046                                  */
9047                                 if (cfg->ret)
9048                                         emit_setret (cfg, ins);
9049                                 MONO_INST_NEW (cfg, ins, OP_BR);
9050                                 ins->inst_target_bb = end_bblock;
9051                                 MONO_ADD_INS (cfg->cbb, ins);
9052                                 link_bblock (cfg, cfg->cbb, end_bblock);
9053                                 ip += 5;
9054                                 break;
9055                         } else if (cfg->backend->have_op_tail_call) {
9056                                 /* Handle tail calls similarly to calls */
9057                                 DISABLE_AOT (cfg);
9058
9059                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
9060                                 call->method = cmethod;
9061                                 call->tail_call = TRUE;
9062                                 call->signature = mono_method_signature (cmethod);
9063                                 call->args = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
9064                                 call->inst.inst_p0 = cmethod;
9065                                 for (i = 0; i < n; ++i)
9066                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
9067
9068                                 if (mini_type_is_vtype (mini_get_underlying_type (call->signature->ret)))
9069                                         call->vret_var = cfg->vret_addr;
9070
9071                                 mono_arch_emit_call (cfg, call);
9072                                 cfg->param_area = MAX(cfg->param_area, call->stack_usage);
9073                                 MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
9074                         } else {
9075                                 for (i = 0; i < num_args; ++i)
9076                                         /* Prevent arguments from being optimized away */
9077                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
9078
9079                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9080                                 ins = (MonoInst*)call;
9081                                 ins->inst_p0 = cmethod;
9082                                 MONO_ADD_INS (cfg->cbb, ins);
9083                         }
9084
9085                         ip += 5;
9086                         start_new_bblock = 1;
9087                         break;
9088                 }
9089                 case CEE_CALLI: {
9090                         MonoInst *addr;
9091                         MonoMethodSignature *fsig;
9092
9093                         CHECK_OPSIZE (5);
9094                         token = read32 (ip + 1);
9095
9096                         ins = NULL;
9097
9098                         //GSHAREDVT_FAILURE (*ip);
9099                         cmethod = NULL;
9100                         CHECK_STACK (1);
9101                         --sp;
9102                         addr = *sp;
9103                         fsig = mini_get_signature (method, token, generic_context, &cfg->error);
9104                         CHECK_CFG_ERROR;
9105
9106                         if (method->dynamic && fsig->pinvoke) {
9107                                 MonoInst *args [3];
9108
9109                                 /*
9110                                  * This is a call through a function pointer using a pinvoke
9111                                  * signature. Have to create a wrapper and call that instead.
9112                                  * FIXME: This is very slow, need to create a wrapper at JIT time
9113                                  * instead based on the signature.
9114                                  */
9115                                 EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
9116                                 EMIT_NEW_PCONST (cfg, args [1], fsig);
9117                                 args [2] = addr;
9118                                 addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
9119                         }
9120
9121                         n = fsig->param_count + fsig->hasthis;
9122
9123                         CHECK_STACK (n);
9124
9125                         //g_assert (!virtual_ || fsig->hasthis);
9126
9127                         sp -= n;
9128
9129                         inline_costs += 10 * num_calls++;
9130
9131                         /*
9132                          * Making generic calls out of gsharedvt methods.
9133                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9134                          * patching gshared method addresses into a gsharedvt method.
9135                          */
9136                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
9137                                 /*
9138                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
9139                                  */
9140                                 MonoInst *callee = addr;
9141
9142                                 if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
9143                                         /* Not tested */
9144                                         GSHAREDVT_FAILURE (*ip);
9145
9146                                 if (cfg->llvm_only)
9147                                         // FIXME:
9148                                         GSHAREDVT_FAILURE (*ip);
9149
9150                                 addr = emit_get_rgctx_sig (cfg, context_used,
9151                                                                                           fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
9152                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
9153                                 goto calli_end;
9154                         }
9155
9156                         /* Prevent inlining of methods with indirect calls */
9157                         INLINE_FAILURE ("indirect call");
9158
9159                         if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
9160                                 MonoJumpInfoType info_type;
9161                                 gpointer info_data;
9162
9163                                 /*
9164                                  * Instead of emitting an indirect call, emit a direct call
9165                                  * with the contents of the aotconst as the patch info.
9166                                  */
9167                                 if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
9168                                         info_type = (MonoJumpInfoType)addr->inst_c1;
9169                                         info_data = addr->inst_p0;
9170                                 } else {
9171                                         info_type = (MonoJumpInfoType)addr->inst_right->inst_c1;
9172                                         info_data = addr->inst_right->inst_left;
9173                                 }
9174
9175                                 if (info_type == MONO_PATCH_INFO_ICALL_ADDR) {
9176                                         ins = (MonoInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_ICALL_ADDR_CALL, info_data, fsig, sp);
9177                                         NULLIFY_INS (addr);
9178                                         goto calli_end;
9179                                 } else if (info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
9180                                         ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
9181                                         NULLIFY_INS (addr);
9182                                         goto calli_end;
9183                                 }
9184                         }
9185                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9186
9187                         calli_end:
9188
9189                         /* End of call, INS should contain the result of the call, if any */
9190
9191                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9192                                 g_assert (ins);
9193                                 *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
9194                         }
9195
9196                         CHECK_CFG_EXCEPTION;
9197
9198                         ip += 5;
9199                         ins_flag = 0;
9200                         constrained_class = NULL;
9201                         break;
9202                 }
9203                 case CEE_CALL:
9204                 case CEE_CALLVIRT: {
9205                         MonoInst *addr = NULL;
9206                         MonoMethodSignature *fsig = NULL;
9207                         int array_rank = 0;
9208                         int virtual_ = *ip == CEE_CALLVIRT;
9209                         gboolean pass_imt_from_rgctx = FALSE;
9210                         MonoInst *imt_arg = NULL;
9211                         MonoInst *keep_this_alive = NULL;
9212                         gboolean pass_vtable = FALSE;
9213                         gboolean pass_mrgctx = FALSE;
9214                         MonoInst *vtable_arg = NULL;
9215                         gboolean check_this = FALSE;
9216                         gboolean supported_tail_call = FALSE;
9217                         gboolean tail_call = FALSE;
9218                         gboolean need_seq_point = FALSE;
9219                         guint32 call_opcode = *ip;
9220                         gboolean emit_widen = TRUE;
9221                         gboolean push_res = TRUE;
9222                         gboolean skip_ret = FALSE;
9223                         gboolean delegate_invoke = FALSE;
9224                         gboolean direct_icall = FALSE;
9225                         gboolean constrained_partial_call = FALSE;
9226                         MonoMethod *cil_method;
9227
9228                         CHECK_OPSIZE (5);
9229                         token = read32 (ip + 1);
9230
9231                         ins = NULL;
9232
9233                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
9234                         CHECK_CFG_ERROR;
9235
9236                         cil_method = cmethod;
9237                                 
9238                         if (constrained_class) {
9239                                 if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
9240                                         if (!mini_is_gsharedvt_klass (constrained_class)) {
9241                                                 g_assert (!cmethod->klass->valuetype);
9242                                                 if (!mini_type_is_reference (&constrained_class->byval_arg))
9243                                                         constrained_partial_call = TRUE;
9244                                         }
9245                                 }
9246
9247                                 if (method->wrapper_type != MONO_WRAPPER_NONE) {
9248                                         if (cfg->verbose_level > 2)
9249                                                 printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_class));
9250                                         if (!((constrained_class->byval_arg.type == MONO_TYPE_VAR ||
9251                                                    constrained_class->byval_arg.type == MONO_TYPE_MVAR) &&
9252                                                   cfg->gshared)) {
9253                                                 cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_class, generic_context, &cfg->error);
9254                                                 CHECK_CFG_ERROR;
9255                                         }
9256                                 } else {
9257                                         if (cfg->verbose_level > 2)
9258                                                 printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_class));
9259
9260                                         if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
9261                                                 /* 
9262                                                  * This is needed since get_method_constrained can't find 
9263                                                  * the method in klass representing a type var.
9264                                                  * The type var is guaranteed to be a reference type in this
9265                                                  * case.
9266                                                  */
9267                                                 if (!mini_is_gsharedvt_klass (constrained_class))
9268                                                         g_assert (!cmethod->klass->valuetype);
9269                                         } else {
9270                                                 cmethod = mono_get_method_constrained_checked (image, token, constrained_class, generic_context, &cil_method, &cfg->error);
9271                                                 CHECK_CFG_ERROR;
9272                                         }
9273                                 }
9274                         }
9275                                         
9276                         if (!dont_verify && !cfg->skip_visibility) {
9277                                 MonoMethod *target_method = cil_method;
9278                                 if (method->is_inflated) {
9279                                         target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context), &cfg->error);
9280                                         CHECK_CFG_ERROR;
9281                                 }
9282                                 if (!mono_method_can_access_method (method_definition, target_method) &&
9283                                         !mono_method_can_access_method (method, cil_method))
9284                                         emit_method_access_failure (cfg, method, cil_method);
9285                         }
9286
9287                         if (mono_security_core_clr_enabled ())
9288                                 ensure_method_is_allowed_to_call_method (cfg, method, cil_method);
9289
9290                         if (!virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
9291                                 /* MS.NET seems to silently convert this to a callvirt */
9292                                 virtual_ = 1;
9293
9294                         {
9295                                 /*
9296                                  * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
9297                                  * converts to a callvirt.
9298                                  *
9299                                  * tests/bug-515884.il is an example of this behavior
9300                                  */
9301                                 const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
9302                                 const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
9303                                 if (!virtual_ && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
9304                                         virtual_ = 1;
9305                         }
9306
9307                         if (!cmethod->klass->inited)
9308                                 if (!mono_class_init (cmethod->klass))
9309                                         TYPE_LOAD_ERROR (cmethod->klass);
9310
9311                         fsig = mono_method_signature (cmethod);
9312                         if (!fsig)
9313                                 LOAD_ERROR;
9314                         if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
9315                                 mini_class_is_system_array (cmethod->klass)) {
9316                                 array_rank = cmethod->klass->rank;
9317                         } else if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && icall_is_direct_callable (cfg, cmethod)) {
9318                                 direct_icall = TRUE;
9319                         } else if (fsig->pinvoke) {
9320                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
9321                                 fsig = mono_method_signature (wrapper);
9322                         } else if (constrained_class) {
9323                         } else {
9324                                 fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
9325                                 CHECK_CFG_ERROR;
9326                         }
9327
9328                         if (cfg->llvm_only && !cfg->method->wrapper_type && (!cmethod || cmethod->is_inflated))
9329                                 cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, fsig);
9330
9331                         /* See code below */
9332                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
9333                                 MonoBasicBlock *tbb;
9334
9335                                 GET_BBLOCK (cfg, tbb, ip + 5);
9336                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
9337                                         /*
9338                                          * We want to extend the try block to cover the call, but we can't do it if the
9339                                          * call is made directly since its followed by an exception check.
9340                                          */
9341                                         direct_icall = FALSE;
9342                                 }
9343                         }
9344
9345                         mono_save_token_info (cfg, image, token, cil_method);
9346
9347                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip + 5 - header->code)))
9348                                 need_seq_point = TRUE;
9349
9350                         /* Don't support calls made using type arguments for now */
9351                         /*
9352                           if (cfg->gsharedvt) {
9353                           if (mini_is_gsharedvt_signature (fsig))
9354                           GSHAREDVT_FAILURE (*ip);
9355                           }
9356                         */
9357
9358                         if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
9359                                 g_assert_not_reached ();
9360
9361                         n = fsig->param_count + fsig->hasthis;
9362
9363                         if (!cfg->gshared && cmethod->klass->generic_container)
9364                                 UNVERIFIED;
9365
9366                         if (!cfg->gshared)
9367                                 g_assert (!mono_method_check_context_used (cmethod));
9368
9369                         CHECK_STACK (n);
9370
9371                         //g_assert (!virtual_ || fsig->hasthis);
9372
9373                         sp -= n;
9374
9375                         /*
9376                          * We have the `constrained.' prefix opcode.
9377                          */
9378                         if (constrained_class) {
9379                                 if (mini_is_gsharedvt_klass (constrained_class)) {
9380                                         if ((cmethod->klass != mono_defaults.object_class) && constrained_class->valuetype && cmethod->klass->valuetype) {
9381                                                 /* The 'Own method' case below */
9382                                         } else if (cmethod->klass->image != mono_defaults.corlib && !(cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !cmethod->klass->valuetype) {
9383                                                 /* 'The type parameter is instantiated as a reference type' case below. */
9384                                         } else {
9385                                                 ins = handle_constrained_gsharedvt_call (cfg, cmethod, fsig, sp, constrained_class, &emit_widen);
9386                                                 CHECK_CFG_EXCEPTION;
9387                                                 g_assert (ins);
9388                                                 goto call_end;
9389                                         }
9390                                 }
9391
9392                                 if (constrained_partial_call) {
9393                                         gboolean need_box = TRUE;
9394
9395                                         /*
9396                                          * The receiver is a valuetype, but the exact type is not known at compile time. This means the
9397                                          * called method is not known at compile time either. The called method could end up being
9398                                          * one of the methods on the parent classes (object/valuetype/enum), in which case we need
9399                                          * to box the receiver.
9400                                          * A simple solution would be to box always and make a normal virtual call, but that would
9401                                          * be bad performance wise.
9402                                          */
9403                                         if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE && cmethod->klass->generic_class) {
9404                                                 /*
9405                                                  * The parent classes implement no generic interfaces, so the called method will be a vtype method, so no boxing neccessary.
9406                                                  */
9407                                                 need_box = FALSE;
9408                                         }
9409
9410                                         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)) {
9411                                                 /* The called method is not virtual, i.e. Object:GetType (), the receiver is a vtype, has to box */
9412                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9413                                                 ins->klass = constrained_class;
9414                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9415                                                 CHECK_CFG_EXCEPTION;
9416                                         } else if (need_box) {
9417                                                 MonoInst *box_type;
9418                                                 MonoBasicBlock *is_ref_bb, *end_bb;
9419                                                 MonoInst *nonbox_call;
9420
9421                                                 /*
9422                                                  * Determine at runtime whenever the called method is defined on object/valuetype/enum, and emit a boxing call
9423                                                  * if needed.
9424                                                  * FIXME: It is possible to inline the called method in a lot of cases, i.e. for T_INT,
9425                                                  * the no-box case goes to a method in Int32, while the box case goes to a method in Enum.
9426                                                  */
9427                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
9428
9429                                                 NEW_BBLOCK (cfg, is_ref_bb);
9430                                                 NEW_BBLOCK (cfg, end_bb);
9431
9432                                                 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);
9433                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, box_type->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
9434                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
9435
9436                                                 /* Non-ref case */
9437                                                 nonbox_call = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9438
9439                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9440
9441                                                 /* Ref case */
9442                                                 MONO_START_BB (cfg, is_ref_bb);
9443                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9444                                                 ins->klass = constrained_class;
9445                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9446                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9447
9448                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9449
9450                                                 MONO_START_BB (cfg, end_bb);
9451                                                 cfg->cbb = end_bb;
9452
9453                                                 nonbox_call->dreg = ins->dreg;
9454                                                 goto call_end;
9455                                         } else {
9456                                                 g_assert (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
9457                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
9458                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9459                                                 goto call_end;
9460                                         }
9461                                 } else if (constrained_class->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
9462                                         /*
9463                                          * The type parameter is instantiated as a valuetype,
9464                                          * but that type doesn't override the method we're
9465                                          * calling, so we need to box `this'.
9466                                          */
9467                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9468                                         ins->klass = constrained_class;
9469                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9470                                         CHECK_CFG_EXCEPTION;
9471                                 } else if (!constrained_class->valuetype) {
9472                                         int dreg = alloc_ireg_ref (cfg);
9473
9474                                         /*
9475                                          * The type parameter is instantiated as a reference
9476                                          * type.  We have a managed pointer on the stack, so
9477                                          * we need to dereference it here.
9478                                          */
9479                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
9480                                         ins->type = STACK_OBJ;
9481                                         sp [0] = ins;
9482                                 } else {
9483                                         if (cmethod->klass->valuetype) {
9484                                                 /* Own method */
9485                                         } else {
9486                                                 /* Interface method */
9487                                                 int ioffset, slot;
9488
9489                                                 mono_class_setup_vtable (constrained_class);
9490                                                 CHECK_TYPELOAD (constrained_class);
9491                                                 ioffset = mono_class_interface_offset (constrained_class, cmethod->klass);
9492                                                 if (ioffset == -1)
9493                                                         TYPE_LOAD_ERROR (constrained_class);
9494                                                 slot = mono_method_get_vtable_slot (cmethod);
9495                                                 if (slot == -1)
9496                                                         TYPE_LOAD_ERROR (cmethod->klass);
9497                                                 cmethod = constrained_class->vtable [ioffset + slot];
9498
9499                                                 if (cmethod->klass == mono_defaults.enum_class) {
9500                                                         /* Enum implements some interfaces, so treat this as the first case */
9501                                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9502                                                         ins->klass = constrained_class;
9503                                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9504                                                         CHECK_CFG_EXCEPTION;
9505                                                 }
9506                                         }
9507                                         virtual_ = 0;
9508                                 }
9509                                 constrained_class = NULL;
9510                         }
9511
9512                         if (check_call_signature (cfg, fsig, sp))
9513                                 UNVERIFIED;
9514
9515                         if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
9516                                 delegate_invoke = TRUE;
9517
9518                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
9519                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9520                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9521                                         emit_widen = FALSE;
9522                                 }
9523
9524                                 goto call_end;
9525                         }
9526
9527                         /* 
9528                          * If the callee is a shared method, then its static cctor
9529                          * might not get called after the call was patched.
9530                          */
9531                         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)) {
9532                                 emit_class_init (cfg, cmethod->klass);
9533                                 CHECK_TYPELOAD (cmethod->klass);
9534                         }
9535
9536                         check_method_sharing (cfg, cmethod, &pass_vtable, &pass_mrgctx);
9537
9538                         if (cfg->gshared) {
9539                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
9540
9541                                 context_used = mini_method_check_context_used (cfg, cmethod);
9542
9543                                 if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9544                                         /* Generic method interface
9545                                            calls are resolved via a
9546                                            helper function and don't
9547                                            need an imt. */
9548                                         if (!cmethod_context || !cmethod_context->method_inst)
9549                                                 pass_imt_from_rgctx = TRUE;
9550                                 }
9551
9552                                 /*
9553                                  * If a shared method calls another
9554                                  * shared method then the caller must
9555                                  * have a generic sharing context
9556                                  * because the magic trampoline
9557                                  * requires it.  FIXME: We shouldn't
9558                                  * have to force the vtable/mrgctx
9559                                  * variable here.  Instead there
9560                                  * should be a flag in the cfg to
9561                                  * request a generic sharing context.
9562                                  */
9563                                 if (context_used &&
9564                                                 ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
9565                                         mono_get_vtable_var (cfg);
9566                         }
9567
9568                         if (pass_vtable) {
9569                                 if (context_used) {
9570                                         vtable_arg = emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
9571                                 } else {
9572                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
9573
9574                                         CHECK_TYPELOAD (cmethod->klass);
9575                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
9576                                 }
9577                         }
9578
9579                         if (pass_mrgctx) {
9580                                 g_assert (!vtable_arg);
9581
9582                                 if (!cfg->compile_aot) {
9583                                         /* 
9584                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
9585                                          * for type load errors before.
9586                                          */
9587                                         mono_class_setup_vtable (cmethod->klass);
9588                                         CHECK_TYPELOAD (cmethod->klass);
9589                                 }
9590
9591                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
9592
9593                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
9594                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
9595                                          MONO_METHOD_IS_FINAL (cmethod)) &&
9596                                         !mono_class_is_marshalbyref (cmethod->klass)) {
9597                                         if (virtual_)
9598                                                 check_this = TRUE;
9599                                         virtual_ = 0;
9600                                 }
9601                         }
9602
9603                         if (pass_imt_from_rgctx) {
9604                                 g_assert (!pass_vtable);
9605
9606                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9607                                         cmethod, MONO_RGCTX_INFO_METHOD);
9608                         }
9609
9610                         if (check_this)
9611                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9612
9613                         /* Calling virtual generic methods */
9614                         if (virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) &&
9615                             !(MONO_METHOD_IS_FINAL (cmethod) && 
9616                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
9617                             fsig->generic_param_count && 
9618                                 !(cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) &&
9619                                 !cfg->llvm_only) {
9620                                 MonoInst *this_temp, *this_arg_temp, *store;
9621                                 MonoInst *iargs [4];
9622
9623                                 g_assert (fsig->is_inflated);
9624
9625                                 /* Prevent inlining of methods that contain indirect calls */
9626                                 INLINE_FAILURE ("virtual generic call");
9627
9628                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
9629                                         GSHAREDVT_FAILURE (*ip);
9630
9631                                 if (cfg->backend->have_generalized_imt_trampoline && cfg->backend->gshared_supported && cmethod->wrapper_type == MONO_WRAPPER_NONE) {
9632                                         g_assert (!imt_arg);
9633                                         if (!context_used)
9634                                                 g_assert (cmethod->is_inflated);
9635                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
9636                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
9637                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, sp [0], imt_arg, NULL);
9638                                 } else {
9639                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
9640                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
9641                                         MONO_ADD_INS (cfg->cbb, store);
9642
9643                                         /* FIXME: This should be a managed pointer */
9644                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
9645
9646                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
9647                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
9648                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
9649                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
9650                                         addr = mono_emit_jit_icall (cfg,
9651                                                                                                 mono_helper_compile_generic_method, iargs);
9652
9653                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
9654
9655                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9656                                 }
9657
9658                                 goto call_end;
9659                         }
9660
9661                         /*
9662                          * Implement a workaround for the inherent races involved in locking:
9663                          * Monitor.Enter ()
9664                          * try {
9665                          * } finally {
9666                          *    Monitor.Exit ()
9667                          * }
9668                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
9669                          * try block, the Exit () won't be executed, see:
9670                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
9671                          * To work around this, we extend such try blocks to include the last x bytes
9672                          * of the Monitor.Enter () call.
9673                          */
9674                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
9675                                 MonoBasicBlock *tbb;
9676
9677                                 GET_BBLOCK (cfg, tbb, ip + 5);
9678                                 /* 
9679                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
9680                                  * from Monitor.Enter like ArgumentNullException.
9681                                  */
9682                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
9683                                         /* Mark this bblock as needing to be extended */
9684                                         tbb->extend_try_block = TRUE;
9685                                 }
9686                         }
9687
9688                         /* Conversion to a JIT intrinsic */
9689                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
9690                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9691                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9692                                         emit_widen = FALSE;
9693                                 }
9694                                 goto call_end;
9695                         }
9696                         CHECK_CFG_ERROR;
9697                         
9698                         /* Inlining */
9699                         if ((cfg->opt & MONO_OPT_INLINE) &&
9700                                 (!virtual_ || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
9701                             mono_method_check_inlining (cfg, cmethod)) {
9702                                 int costs;
9703                                 gboolean always = FALSE;
9704
9705                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
9706                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
9707                                         /* Prevent inlining of methods that call wrappers */
9708                                         INLINE_FAILURE ("wrapper call");
9709                                         cmethod = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
9710                                         always = TRUE;
9711                                 }
9712
9713                                 costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, always);
9714                                 if (costs) {
9715                                         cfg->real_offset += 5;
9716
9717                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9718                                                 /* *sp is already set by inline_method */
9719                                                 sp++;
9720                                                 push_res = FALSE;
9721                                         }
9722
9723                                         inline_costs += costs;
9724
9725                                         goto call_end;
9726                                 }
9727                         }
9728
9729                         /* Tail recursion elimination */
9730                         if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
9731                                 gboolean has_vtargs = FALSE;
9732                                 int i;
9733
9734                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9735                                 INLINE_FAILURE ("tail call");
9736
9737                                 /* keep it simple */
9738                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
9739                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
9740                                                 has_vtargs = TRUE;
9741                                 }
9742
9743                                 if (!has_vtargs) {
9744                                         if (need_seq_point) {
9745                                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
9746                                                 need_seq_point = FALSE;
9747                                         }
9748                                         for (i = 0; i < n; ++i)
9749                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9750                                         MONO_INST_NEW (cfg, ins, OP_BR);
9751                                         MONO_ADD_INS (cfg->cbb, ins);
9752                                         tblock = start_bblock->out_bb [0];
9753                                         link_bblock (cfg, cfg->cbb, tblock);
9754                                         ins->inst_target_bb = tblock;
9755                                         start_new_bblock = 1;
9756
9757                                         /* skip the CEE_RET, too */
9758                                         if (ip_in_bb (cfg, cfg->cbb, ip + 5))
9759                                                 skip_ret = TRUE;
9760                                         push_res = FALSE;
9761                                         goto call_end;
9762                                 }
9763                         }
9764
9765                         inline_costs += 10 * num_calls++;
9766
9767                         /*
9768                          * Synchronized wrappers.
9769                          * Its hard to determine where to replace a method with its synchronized
9770                          * wrapper without causing an infinite recursion. The current solution is
9771                          * to add the synchronized wrapper in the trampolines, and to
9772                          * change the called method to a dummy wrapper, and resolve that wrapper
9773                          * to the real method in mono_jit_compile_method ().
9774                          */
9775                         if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
9776                                 MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
9777                                 if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
9778                                         cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
9779                         }
9780
9781                         /*
9782                          * Making generic calls out of gsharedvt methods.
9783                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9784                          * patching gshared method addresses into a gsharedvt method.
9785                          */
9786                         if (cfg->gsharedvt && (mini_is_gsharedvt_signature (fsig) || cmethod->is_inflated || cmethod->klass->generic_class) &&
9787                                 !(cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY) &&
9788                                 (!(cfg->llvm_only && virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)))) {
9789                                 MonoRgctxInfoType info_type;
9790
9791                                 if (virtual_) {
9792                                         //if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
9793                                                 //GSHAREDVT_FAILURE (*ip);
9794                                         // disable for possible remoting calls
9795                                         if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
9796                                                 GSHAREDVT_FAILURE (*ip);
9797                                         if (fsig->generic_param_count) {
9798                                                 /* virtual generic call */
9799                                                 g_assert (!imt_arg);
9800                                                 /* Same as the virtual generic case above */
9801                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9802                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9803                                                 /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
9804                                                 vtable_arg = NULL;
9805                                         } else if ((cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !imt_arg) {
9806                                                 /* This can happen when we call a fully instantiated iface method */
9807                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9808                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9809                                                 vtable_arg = NULL;
9810                                         }
9811                                 }
9812
9813                                 if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
9814                                         keep_this_alive = sp [0];
9815
9816                                 if (virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
9817                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
9818                                 else
9819                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
9820                                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
9821
9822                                 if (cfg->llvm_only) {
9823                                         // FIXME: Avoid initializing vtable_arg
9824                                         ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
9825                                 } else {
9826                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9827                                 }
9828                                 goto call_end;
9829                         }
9830
9831                         /* Generic sharing */
9832
9833                         /*
9834                          * Use this if the callee is gsharedvt sharable too, since
9835                          * at runtime we might find an instantiation so the call cannot
9836                          * be patched (the 'no_patch' code path in mini-trampolines.c).
9837                          */
9838                         if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
9839                                 (!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
9840                                  !mono_class_generic_sharing_enabled (cmethod->klass)) &&
9841                                 (!virtual_ || MONO_METHOD_IS_FINAL (cmethod) ||
9842                                  !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
9843                                 INLINE_FAILURE ("gshared");
9844
9845                                 g_assert (cfg->gshared && cmethod);
9846                                 g_assert (!addr);
9847
9848                                 /*
9849                                  * We are compiling a call to a
9850                                  * generic method from shared code,
9851                                  * which means that we have to look up
9852                                  * the method in the rgctx and do an
9853                                  * indirect call.
9854                                  */
9855                                 if (fsig->hasthis)
9856                                         MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9857
9858                                 if (cfg->llvm_only) {
9859                                         if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig))
9860                                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER);
9861                                         else
9862                                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9863                                         // FIXME: Avoid initializing imt_arg/vtable_arg
9864                                         ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
9865                                 } else {
9866                                         addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9867                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9868                                 }
9869                                 goto call_end;
9870                         }
9871
9872                         /* Direct calls to icalls */
9873                         if (direct_icall) {
9874                                 MonoMethod *wrapper;
9875                                 int costs;
9876
9877                                 /* Inline the wrapper */
9878                                 wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
9879
9880                                 costs = inline_method (cfg, wrapper, fsig, sp, ip, cfg->real_offset, TRUE);
9881                                 g_assert (costs > 0);
9882                                 cfg->real_offset += 5;
9883
9884                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9885                                         /* *sp is already set by inline_method */
9886                                         sp++;
9887                                         push_res = FALSE;
9888                                 }
9889
9890                                 inline_costs += costs;
9891
9892                                 goto call_end;
9893                         }
9894                                         
9895                         /* Array methods */
9896                         if (array_rank) {
9897                                 MonoInst *addr;
9898
9899                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
9900                                         MonoInst *val = sp [fsig->param_count];
9901
9902                                         if (val->type == STACK_OBJ) {
9903                                                 MonoInst *iargs [2];
9904
9905                                                 iargs [0] = sp [0];
9906                                                 iargs [1] = val;
9907                                                 
9908                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
9909                                         }
9910                                         
9911                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
9912                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
9913                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !(val->opcode == OP_PCONST && val->inst_c0 == 0))
9914                                                 emit_write_barrier (cfg, addr, val);
9915                                         if (cfg->gen_write_barriers && mini_is_gsharedvt_klass (cmethod->klass))
9916                                                 GSHAREDVT_FAILURE (*ip);
9917                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
9918                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9919
9920                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
9921                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
9922                                         if (!cmethod->klass->element_class->valuetype && !readonly)
9923                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
9924                                         CHECK_TYPELOAD (cmethod->klass);
9925                                         
9926                                         readonly = FALSE;
9927                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9928                                         ins = addr;
9929                                 } else {
9930                                         g_assert_not_reached ();
9931                                 }
9932
9933                                 emit_widen = FALSE;
9934                                 goto call_end;
9935                         }
9936
9937                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual_ ? sp [0] : NULL);
9938                         if (ins)
9939                                 goto call_end;
9940
9941                         /* Tail prefix / tail call optimization */
9942
9943                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
9944                         /* FIXME: runtime generic context pointer for jumps? */
9945                         /* FIXME: handle this for generic sharing eventually */
9946                         if ((ins_flag & MONO_INST_TAILCALL) &&
9947                                 !vtable_arg && !cfg->gshared && is_supported_tail_call (cfg, method, cmethod, fsig, call_opcode))
9948                                 supported_tail_call = TRUE;
9949
9950                         if (supported_tail_call) {
9951                                 MonoCallInst *call;
9952
9953                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9954                                 INLINE_FAILURE ("tail call");
9955
9956                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
9957
9958                                 if (cfg->backend->have_op_tail_call) {
9959                                         /* Handle tail calls similarly to normal calls */
9960                                         tail_call = TRUE;
9961                                 } else {
9962                                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
9963
9964                                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9965                                         call->tail_call = TRUE;
9966                                         call->method = cmethod;
9967                                         call->signature = mono_method_signature (cmethod);
9968
9969                                         /*
9970                                          * We implement tail calls by storing the actual arguments into the 
9971                                          * argument variables, then emitting a CEE_JMP.
9972                                          */
9973                                         for (i = 0; i < n; ++i) {
9974                                                 /* Prevent argument from being register allocated */
9975                                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
9976                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9977                                         }
9978                                         ins = (MonoInst*)call;
9979                                         ins->inst_p0 = cmethod;
9980                                         ins->inst_p1 = arg_array [0];
9981                                         MONO_ADD_INS (cfg->cbb, ins);
9982                                         link_bblock (cfg, cfg->cbb, end_bblock);
9983                                         start_new_bblock = 1;
9984
9985                                         // FIXME: Eliminate unreachable epilogs
9986
9987                                         /*
9988                                          * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9989                                          * only reachable from this call.
9990                                          */
9991                                         GET_BBLOCK (cfg, tblock, ip + 5);
9992                                         if (tblock == cfg->cbb || tblock->in_count == 0)
9993                                                 skip_ret = TRUE;
9994                                         push_res = FALSE;
9995
9996                                         goto call_end;
9997                                 }
9998                         }
9999
10000                         /*
10001                          * Virtual calls in llvm-only mode.
10002                          */
10003                         if (cfg->llvm_only && virtual_ && cmethod && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
10004                                 ins = emit_llvmonly_virtual_call (cfg, cmethod, fsig, context_used, sp);
10005                                 goto call_end;
10006                         }
10007
10008                         /* Common call */
10009                         INLINE_FAILURE ("call");
10010                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual_ ? sp [0] : NULL,
10011                                                                                           imt_arg, vtable_arg);
10012
10013                         if (tail_call && !cfg->llvm_only) {
10014                                 link_bblock (cfg, cfg->cbb, end_bblock);
10015                                 start_new_bblock = 1;
10016
10017                                 // FIXME: Eliminate unreachable epilogs
10018
10019                                 /*
10020                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
10021                                  * only reachable from this call.
10022                                  */
10023                                 GET_BBLOCK (cfg, tblock, ip + 5);
10024                                 if (tblock == cfg->cbb || tblock->in_count == 0)
10025                                         skip_ret = TRUE;
10026                                 push_res = FALSE;
10027                         }
10028
10029                         call_end:
10030
10031                         /* End of call, INS should contain the result of the call, if any */
10032
10033                         if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
10034                                 g_assert (ins);
10035                                 if (emit_widen)
10036                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
10037                                 else
10038                                         *sp++ = ins;
10039                         }
10040
10041                         if (keep_this_alive) {
10042                                 MonoInst *dummy_use;
10043
10044                                 /* See mono_emit_method_call_full () */
10045                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
10046                         }
10047
10048                         if (cfg->llvm_only && cmethod && method_needs_stack_walk (cfg, cmethod)) {
10049                                 /*
10050                                  * Clang can convert these calls to tail calls which screw up the stack
10051                                  * walk. This happens even when the -fno-optimize-sibling-calls
10052                                  * option is passed to clang.
10053                                  * Work around this by emitting a dummy call.
10054                                  */
10055                                 mono_emit_jit_icall (cfg, mono_dummy_jit_icall, NULL);
10056                         }
10057
10058                         CHECK_CFG_EXCEPTION;
10059
10060                         ip += 5;
10061                         if (skip_ret) {
10062                                 g_assert (*ip == CEE_RET);
10063                                 ip += 1;
10064                         }
10065                         ins_flag = 0;
10066                         constrained_class = NULL;
10067                         if (need_seq_point)
10068                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10069                         break;
10070                 }
10071                 case CEE_RET:
10072                         if (cfg->method != method) {
10073                                 /* return from inlined method */
10074                                 /* 
10075                                  * If in_count == 0, that means the ret is unreachable due to
10076                                  * being preceeded by a throw. In that case, inline_method () will
10077                                  * handle setting the return value 
10078                                  * (test case: test_0_inline_throw ()).
10079                                  */
10080                                 if (return_var && cfg->cbb->in_count) {
10081                                         MonoType *ret_type = mono_method_signature (method)->ret;
10082
10083                                         MonoInst *store;
10084                                         CHECK_STACK (1);
10085                                         --sp;
10086
10087                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
10088                                                 UNVERIFIED;
10089
10090                                         //g_assert (returnvar != -1);
10091                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
10092                                         cfg->ret_var_set = TRUE;
10093                                 } 
10094                         } else {
10095                                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
10096
10097                                 if (cfg->lmf_var && cfg->cbb->in_count && !cfg->llvm_only)
10098                                         emit_pop_lmf (cfg);
10099
10100                                 if (cfg->ret) {
10101                                         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (method)->ret);
10102
10103                                         if (seq_points && !sym_seq_points) {
10104                                                 /* 
10105                                                  * Place a seq point here too even through the IL stack is not
10106                                                  * empty, so a step over on
10107                                                  * call <FOO>
10108                                                  * ret
10109                                                  * will work correctly.
10110                                                  */
10111                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
10112                                                 MONO_ADD_INS (cfg->cbb, ins);
10113                                         }
10114
10115                                         g_assert (!return_var);
10116                                         CHECK_STACK (1);
10117                                         --sp;
10118
10119                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
10120                                                 UNVERIFIED;
10121
10122                                         emit_setret (cfg, *sp);
10123                                 }
10124                         }
10125                         if (sp != stack_start)
10126                                 UNVERIFIED;
10127                         MONO_INST_NEW (cfg, ins, OP_BR);
10128                         ip++;
10129                         ins->inst_target_bb = end_bblock;
10130                         MONO_ADD_INS (cfg->cbb, ins);
10131                         link_bblock (cfg, cfg->cbb, end_bblock);
10132                         start_new_bblock = 1;
10133                         break;
10134                 case CEE_BR_S:
10135                         CHECK_OPSIZE (2);
10136                         MONO_INST_NEW (cfg, ins, OP_BR);
10137                         ip++;
10138                         target = ip + 1 + (signed char)(*ip);
10139                         ++ip;
10140                         GET_BBLOCK (cfg, tblock, target);
10141                         link_bblock (cfg, cfg->cbb, tblock);
10142                         ins->inst_target_bb = tblock;
10143                         if (sp != stack_start) {
10144                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10145                                 sp = stack_start;
10146                                 CHECK_UNVERIFIABLE (cfg);
10147                         }
10148                         MONO_ADD_INS (cfg->cbb, ins);
10149                         start_new_bblock = 1;
10150                         inline_costs += BRANCH_COST;
10151                         break;
10152                 case CEE_BEQ_S:
10153                 case CEE_BGE_S:
10154                 case CEE_BGT_S:
10155                 case CEE_BLE_S:
10156                 case CEE_BLT_S:
10157                 case CEE_BNE_UN_S:
10158                 case CEE_BGE_UN_S:
10159                 case CEE_BGT_UN_S:
10160                 case CEE_BLE_UN_S:
10161                 case CEE_BLT_UN_S:
10162                         CHECK_OPSIZE (2);
10163                         CHECK_STACK (2);
10164                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
10165                         ip++;
10166                         target = ip + 1 + *(signed char*)ip;
10167                         ip++;
10168
10169                         ADD_BINCOND (NULL);
10170
10171                         sp = stack_start;
10172                         inline_costs += BRANCH_COST;
10173                         break;
10174                 case CEE_BR:
10175                         CHECK_OPSIZE (5);
10176                         MONO_INST_NEW (cfg, ins, OP_BR);
10177                         ip++;
10178
10179                         target = ip + 4 + (gint32)read32(ip);
10180                         ip += 4;
10181                         GET_BBLOCK (cfg, tblock, target);
10182                         link_bblock (cfg, cfg->cbb, tblock);
10183                         ins->inst_target_bb = tblock;
10184                         if (sp != stack_start) {
10185                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10186                                 sp = stack_start;
10187                                 CHECK_UNVERIFIABLE (cfg);
10188                         }
10189
10190                         MONO_ADD_INS (cfg->cbb, ins);
10191
10192                         start_new_bblock = 1;
10193                         inline_costs += BRANCH_COST;
10194                         break;
10195                 case CEE_BRFALSE_S:
10196                 case CEE_BRTRUE_S:
10197                 case CEE_BRFALSE:
10198                 case CEE_BRTRUE: {
10199                         MonoInst *cmp;
10200                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
10201                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
10202                         guint32 opsize = is_short ? 1 : 4;
10203
10204                         CHECK_OPSIZE (opsize);
10205                         CHECK_STACK (1);
10206                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
10207                                 UNVERIFIED;
10208                         ip ++;
10209                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
10210                         ip += opsize;
10211
10212                         sp--;
10213
10214                         GET_BBLOCK (cfg, tblock, target);
10215                         link_bblock (cfg, cfg->cbb, tblock);
10216                         GET_BBLOCK (cfg, tblock, ip);
10217                         link_bblock (cfg, cfg->cbb, tblock);
10218
10219                         if (sp != stack_start) {
10220                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10221                                 CHECK_UNVERIFIABLE (cfg);
10222                         }
10223
10224                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
10225                         cmp->sreg1 = sp [0]->dreg;
10226                         type_from_op (cfg, cmp, sp [0], NULL);
10227                         CHECK_TYPE (cmp);
10228
10229 #if SIZEOF_REGISTER == 4
10230                         if (cmp->opcode == OP_LCOMPARE_IMM) {
10231                                 /* Convert it to OP_LCOMPARE */
10232                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
10233                                 ins->type = STACK_I8;
10234                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
10235                                 ins->inst_l = 0;
10236                                 MONO_ADD_INS (cfg->cbb, ins);
10237                                 cmp->opcode = OP_LCOMPARE;
10238                                 cmp->sreg2 = ins->dreg;
10239                         }
10240 #endif
10241                         MONO_ADD_INS (cfg->cbb, cmp);
10242
10243                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
10244                         type_from_op (cfg, ins, sp [0], NULL);
10245                         MONO_ADD_INS (cfg->cbb, ins);
10246                         ins->inst_many_bb = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
10247                         GET_BBLOCK (cfg, tblock, target);
10248                         ins->inst_true_bb = tblock;
10249                         GET_BBLOCK (cfg, tblock, ip);
10250                         ins->inst_false_bb = tblock;
10251                         start_new_bblock = 2;
10252
10253                         sp = stack_start;
10254                         inline_costs += BRANCH_COST;
10255                         break;
10256                 }
10257                 case CEE_BEQ:
10258                 case CEE_BGE:
10259                 case CEE_BGT:
10260                 case CEE_BLE:
10261                 case CEE_BLT:
10262                 case CEE_BNE_UN:
10263                 case CEE_BGE_UN:
10264                 case CEE_BGT_UN:
10265                 case CEE_BLE_UN:
10266                 case CEE_BLT_UN:
10267                         CHECK_OPSIZE (5);
10268                         CHECK_STACK (2);
10269                         MONO_INST_NEW (cfg, ins, *ip);
10270                         ip++;
10271                         target = ip + 4 + (gint32)read32(ip);
10272                         ip += 4;
10273
10274                         ADD_BINCOND (NULL);
10275
10276                         sp = stack_start;
10277                         inline_costs += BRANCH_COST;
10278                         break;
10279                 case CEE_SWITCH: {
10280                         MonoInst *src1;
10281                         MonoBasicBlock **targets;
10282                         MonoBasicBlock *default_bblock;
10283                         MonoJumpInfoBBTable *table;
10284                         int offset_reg = alloc_preg (cfg);
10285                         int target_reg = alloc_preg (cfg);
10286                         int table_reg = alloc_preg (cfg);
10287                         int sum_reg = alloc_preg (cfg);
10288                         gboolean use_op_switch;
10289
10290                         CHECK_OPSIZE (5);
10291                         CHECK_STACK (1);
10292                         n = read32 (ip + 1);
10293                         --sp;
10294                         src1 = sp [0];
10295                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
10296                                 UNVERIFIED;
10297
10298                         ip += 5;
10299                         CHECK_OPSIZE (n * sizeof (guint32));
10300                         target = ip + n * sizeof (guint32);
10301
10302                         GET_BBLOCK (cfg, default_bblock, target);
10303                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
10304
10305                         targets = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
10306                         for (i = 0; i < n; ++i) {
10307                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
10308                                 targets [i] = tblock;
10309                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
10310                                 ip += 4;
10311                         }
10312
10313                         if (sp != stack_start) {
10314                                 /* 
10315                                  * Link the current bb with the targets as well, so handle_stack_args
10316                                  * will set their in_stack correctly.
10317                                  */
10318                                 link_bblock (cfg, cfg->cbb, default_bblock);
10319                                 for (i = 0; i < n; ++i)
10320                                         link_bblock (cfg, cfg->cbb, targets [i]);
10321
10322                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10323                                 sp = stack_start;
10324                                 CHECK_UNVERIFIABLE (cfg);
10325
10326                                 /* Undo the links */
10327                                 mono_unlink_bblock (cfg, cfg->cbb, default_bblock);
10328                                 for (i = 0; i < n; ++i)
10329                                         mono_unlink_bblock (cfg, cfg->cbb, targets [i]);
10330                         }
10331
10332                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
10333                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
10334
10335                         for (i = 0; i < n; ++i)
10336                                 link_bblock (cfg, cfg->cbb, targets [i]);
10337
10338                         table = (MonoJumpInfoBBTable *)mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
10339                         table->table = targets;
10340                         table->table_size = n;
10341
10342                         use_op_switch = FALSE;
10343 #ifdef TARGET_ARM
10344                         /* ARM implements SWITCH statements differently */
10345                         /* FIXME: Make it use the generic implementation */
10346                         if (!cfg->compile_aot)
10347                                 use_op_switch = TRUE;
10348 #endif
10349
10350                         if (COMPILE_LLVM (cfg))
10351                                 use_op_switch = TRUE;
10352
10353                         cfg->cbb->has_jump_table = 1;
10354
10355                         if (use_op_switch) {
10356                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
10357                                 ins->sreg1 = src1->dreg;
10358                                 ins->inst_p0 = table;
10359                                 ins->inst_many_bb = targets;
10360                                 ins->klass = (MonoClass *)GUINT_TO_POINTER (n);
10361                                 MONO_ADD_INS (cfg->cbb, ins);
10362                         } else {
10363                                 if (sizeof (gpointer) == 8)
10364                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
10365                                 else
10366                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
10367
10368 #if SIZEOF_REGISTER == 8
10369                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
10370                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
10371 #endif
10372
10373                                 if (cfg->compile_aot) {
10374                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
10375                                 } else {
10376                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
10377                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
10378                                         ins->inst_p0 = table;
10379                                         ins->dreg = table_reg;
10380                                         MONO_ADD_INS (cfg->cbb, ins);
10381                                 }
10382
10383                                 /* FIXME: Use load_memindex */
10384                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
10385                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
10386                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
10387                         }
10388                         start_new_bblock = 1;
10389                         inline_costs += (BRANCH_COST * 2);
10390                         break;
10391                 }
10392                 case CEE_LDIND_I1:
10393                 case CEE_LDIND_U1:
10394                 case CEE_LDIND_I2:
10395                 case CEE_LDIND_U2:
10396                 case CEE_LDIND_I4:
10397                 case CEE_LDIND_U4:
10398                 case CEE_LDIND_I8:
10399                 case CEE_LDIND_I:
10400                 case CEE_LDIND_R4:
10401                 case CEE_LDIND_R8:
10402                 case CEE_LDIND_REF:
10403                         CHECK_STACK (1);
10404                         --sp;
10405
10406                         switch (*ip) {
10407                         case CEE_LDIND_R4:
10408                         case CEE_LDIND_R8:
10409                                 dreg = alloc_freg (cfg);
10410                                 break;
10411                         case CEE_LDIND_I8:
10412                                 dreg = alloc_lreg (cfg);
10413                                 break;
10414                         case CEE_LDIND_REF:
10415                                 dreg = alloc_ireg_ref (cfg);
10416                                 break;
10417                         default:
10418                                 dreg = alloc_preg (cfg);
10419                         }
10420
10421                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
10422                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
10423                         if (*ip == CEE_LDIND_R4)
10424                                 ins->type = cfg->r4_stack_type;
10425                         ins->flags |= ins_flag;
10426                         MONO_ADD_INS (cfg->cbb, ins);
10427                         *sp++ = ins;
10428                         if (ins_flag & MONO_INST_VOLATILE) {
10429                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10430                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10431                         }
10432                         ins_flag = 0;
10433                         ++ip;
10434                         break;
10435                 case CEE_STIND_REF:
10436                 case CEE_STIND_I1:
10437                 case CEE_STIND_I2:
10438                 case CEE_STIND_I4:
10439                 case CEE_STIND_I8:
10440                 case CEE_STIND_R4:
10441                 case CEE_STIND_R8:
10442                 case CEE_STIND_I:
10443                         CHECK_STACK (2);
10444                         sp -= 2;
10445
10446                         if (ins_flag & MONO_INST_VOLATILE) {
10447                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
10448                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
10449                         }
10450
10451                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
10452                         ins->flags |= ins_flag;
10453                         ins_flag = 0;
10454
10455                         MONO_ADD_INS (cfg->cbb, ins);
10456
10457                         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)))
10458                                 emit_write_barrier (cfg, sp [0], sp [1]);
10459
10460                         inline_costs += 1;
10461                         ++ip;
10462                         break;
10463
10464                 case CEE_MUL:
10465                         CHECK_STACK (2);
10466
10467                         MONO_INST_NEW (cfg, ins, (*ip));
10468                         sp -= 2;
10469                         ins->sreg1 = sp [0]->dreg;
10470                         ins->sreg2 = sp [1]->dreg;
10471                         type_from_op (cfg, ins, sp [0], sp [1]);
10472                         CHECK_TYPE (ins);
10473                         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type);
10474
10475                         /* Use the immediate opcodes if possible */
10476                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
10477                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
10478                                 if (imm_opcode != -1) {
10479                                         ins->opcode = imm_opcode;
10480                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
10481                                         ins->sreg2 = -1;
10482
10483                                         NULLIFY_INS (sp [1]);
10484                                 }
10485                         }
10486
10487                         MONO_ADD_INS ((cfg)->cbb, (ins));
10488
10489                         *sp++ = mono_decompose_opcode (cfg, ins);
10490                         ip++;
10491                         break;
10492                 case CEE_ADD:
10493                 case CEE_SUB:
10494                 case CEE_DIV:
10495                 case CEE_DIV_UN:
10496                 case CEE_REM:
10497                 case CEE_REM_UN:
10498                 case CEE_AND:
10499                 case CEE_OR:
10500                 case CEE_XOR:
10501                 case CEE_SHL:
10502                 case CEE_SHR:
10503                 case CEE_SHR_UN:
10504                         CHECK_STACK (2);
10505
10506                         MONO_INST_NEW (cfg, ins, (*ip));
10507                         sp -= 2;
10508                         ins->sreg1 = sp [0]->dreg;
10509                         ins->sreg2 = sp [1]->dreg;
10510                         type_from_op (cfg, ins, sp [0], sp [1]);
10511                         CHECK_TYPE (ins);
10512                         add_widen_op (cfg, ins, &sp [0], &sp [1]);
10513                         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type);
10514
10515                         /* FIXME: Pass opcode to is_inst_imm */
10516
10517                         /* Use the immediate opcodes if possible */
10518                         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)) {
10519                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
10520                                 if (imm_opcode != -1) {
10521                                         ins->opcode = imm_opcode;
10522                                         if (sp [1]->opcode == OP_I8CONST) {
10523 #if SIZEOF_REGISTER == 8
10524                                                 ins->inst_imm = sp [1]->inst_l;
10525 #else
10526                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
10527                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
10528 #endif
10529                                         }
10530                                         else
10531                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
10532                                         ins->sreg2 = -1;
10533
10534                                         /* Might be followed by an instruction added by add_widen_op */
10535                                         if (sp [1]->next == NULL)
10536                                                 NULLIFY_INS (sp [1]);
10537                                 }
10538                         }
10539                         MONO_ADD_INS ((cfg)->cbb, (ins));
10540
10541                         *sp++ = mono_decompose_opcode (cfg, ins);
10542                         ip++;
10543                         break;
10544                 case CEE_NEG:
10545                 case CEE_NOT:
10546                 case CEE_CONV_I1:
10547                 case CEE_CONV_I2:
10548                 case CEE_CONV_I4:
10549                 case CEE_CONV_R4:
10550                 case CEE_CONV_R8:
10551                 case CEE_CONV_U4:
10552                 case CEE_CONV_I8:
10553                 case CEE_CONV_U8:
10554                 case CEE_CONV_OVF_I8:
10555                 case CEE_CONV_OVF_U8:
10556                 case CEE_CONV_R_UN:
10557                         CHECK_STACK (1);
10558
10559                         /* Special case this earlier so we have long constants in the IR */
10560                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
10561                                 int data = sp [-1]->inst_c0;
10562                                 sp [-1]->opcode = OP_I8CONST;
10563                                 sp [-1]->type = STACK_I8;
10564 #if SIZEOF_REGISTER == 8
10565                                 if ((*ip) == CEE_CONV_U8)
10566                                         sp [-1]->inst_c0 = (guint32)data;
10567                                 else
10568                                         sp [-1]->inst_c0 = data;
10569 #else
10570                                 sp [-1]->inst_ls_word = data;
10571                                 if ((*ip) == CEE_CONV_U8)
10572                                         sp [-1]->inst_ms_word = 0;
10573                                 else
10574                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
10575 #endif
10576                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
10577                         }
10578                         else {
10579                                 ADD_UNOP (*ip);
10580                         }
10581                         ip++;
10582                         break;
10583                 case CEE_CONV_OVF_I4:
10584                 case CEE_CONV_OVF_I1:
10585                 case CEE_CONV_OVF_I2:
10586                 case CEE_CONV_OVF_I:
10587                 case CEE_CONV_OVF_U:
10588                         CHECK_STACK (1);
10589
10590                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10591                                 ADD_UNOP (CEE_CONV_OVF_I8);
10592                                 ADD_UNOP (*ip);
10593                         } else {
10594                                 ADD_UNOP (*ip);
10595                         }
10596                         ip++;
10597                         break;
10598                 case CEE_CONV_OVF_U1:
10599                 case CEE_CONV_OVF_U2:
10600                 case CEE_CONV_OVF_U4:
10601                         CHECK_STACK (1);
10602
10603                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10604                                 ADD_UNOP (CEE_CONV_OVF_U8);
10605                                 ADD_UNOP (*ip);
10606                         } else {
10607                                 ADD_UNOP (*ip);
10608                         }
10609                         ip++;
10610                         break;
10611                 case CEE_CONV_OVF_I1_UN:
10612                 case CEE_CONV_OVF_I2_UN:
10613                 case CEE_CONV_OVF_I4_UN:
10614                 case CEE_CONV_OVF_I8_UN:
10615                 case CEE_CONV_OVF_U1_UN:
10616                 case CEE_CONV_OVF_U2_UN:
10617                 case CEE_CONV_OVF_U4_UN:
10618                 case CEE_CONV_OVF_U8_UN:
10619                 case CEE_CONV_OVF_I_UN:
10620                 case CEE_CONV_OVF_U_UN:
10621                 case CEE_CONV_U2:
10622                 case CEE_CONV_U1:
10623                 case CEE_CONV_I:
10624                 case CEE_CONV_U:
10625                         CHECK_STACK (1);
10626                         ADD_UNOP (*ip);
10627                         CHECK_CFG_EXCEPTION;
10628                         ip++;
10629                         break;
10630                 case CEE_ADD_OVF:
10631                 case CEE_ADD_OVF_UN:
10632                 case CEE_MUL_OVF:
10633                 case CEE_MUL_OVF_UN:
10634                 case CEE_SUB_OVF:
10635                 case CEE_SUB_OVF_UN:
10636                         CHECK_STACK (2);
10637                         ADD_BINOP (*ip);
10638                         ip++;
10639                         break;
10640                 case CEE_CPOBJ:
10641                         GSHAREDVT_FAILURE (*ip);
10642                         CHECK_OPSIZE (5);
10643                         CHECK_STACK (2);
10644                         token = read32 (ip + 1);
10645                         klass = mini_get_class (method, token, generic_context);
10646                         CHECK_TYPELOAD (klass);
10647                         sp -= 2;
10648                         if (generic_class_is_reference_type (cfg, klass)) {
10649                                 MonoInst *store, *load;
10650                                 int dreg = alloc_ireg_ref (cfg);
10651
10652                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
10653                                 load->flags |= ins_flag;
10654                                 MONO_ADD_INS (cfg->cbb, load);
10655
10656                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
10657                                 store->flags |= ins_flag;
10658                                 MONO_ADD_INS (cfg->cbb, store);
10659
10660                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
10661                                         emit_write_barrier (cfg, sp [0], sp [1]);
10662                         } else {
10663                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10664                         }
10665                         ins_flag = 0;
10666                         ip += 5;
10667                         break;
10668                 case CEE_LDOBJ: {
10669                         int loc_index = -1;
10670                         int stloc_len = 0;
10671
10672                         CHECK_OPSIZE (5);
10673                         CHECK_STACK (1);
10674                         --sp;
10675                         token = read32 (ip + 1);
10676                         klass = mini_get_class (method, token, generic_context);
10677                         CHECK_TYPELOAD (klass);
10678
10679                         /* Optimize the common ldobj+stloc combination */
10680                         switch (ip [5]) {
10681                         case CEE_STLOC_S:
10682                                 loc_index = ip [6];
10683                                 stloc_len = 2;
10684                                 break;
10685                         case CEE_STLOC_0:
10686                         case CEE_STLOC_1:
10687                         case CEE_STLOC_2:
10688                         case CEE_STLOC_3:
10689                                 loc_index = ip [5] - CEE_STLOC_0;
10690                                 stloc_len = 1;
10691                                 break;
10692                         default:
10693                                 break;
10694                         }
10695
10696                         if ((loc_index != -1) && ip_in_bb (cfg, cfg->cbb, ip + 5)) {
10697                                 CHECK_LOCAL (loc_index);
10698
10699                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10700                                 ins->dreg = cfg->locals [loc_index]->dreg;
10701                                 ins->flags |= ins_flag;
10702                                 ip += 5;
10703                                 ip += stloc_len;
10704                                 if (ins_flag & MONO_INST_VOLATILE) {
10705                                         /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10706                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10707                                 }
10708                                 ins_flag = 0;
10709                                 break;
10710                         }
10711
10712                         /* Optimize the ldobj+stobj combination */
10713                         /* The reference case ends up being a load+store anyway */
10714                         /* Skip this if the operation is volatile. */
10715                         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)) {
10716                                 CHECK_STACK (1);
10717
10718                                 sp --;
10719
10720                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10721
10722                                 ip += 5 + 5;
10723                                 ins_flag = 0;
10724                                 break;
10725                         }
10726
10727                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10728                         ins->flags |= ins_flag;
10729                         *sp++ = ins;
10730
10731                         if (ins_flag & MONO_INST_VOLATILE) {
10732                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10733                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10734                         }
10735
10736                         ip += 5;
10737                         ins_flag = 0;
10738                         inline_costs += 1;
10739                         break;
10740                 }
10741                 case CEE_LDSTR:
10742                         CHECK_STACK_OVF (1);
10743                         CHECK_OPSIZE (5);
10744                         n = read32 (ip + 1);
10745
10746                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
10747                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
10748                                 ins->type = STACK_OBJ;
10749                                 *sp = ins;
10750                         }
10751                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
10752                                 MonoInst *iargs [1];
10753                                 char *str = (char *)mono_method_get_wrapper_data (method, n);
10754
10755                                 if (cfg->compile_aot)
10756                                         EMIT_NEW_LDSTRLITCONST (cfg, iargs [0], str);
10757                                 else
10758                                         EMIT_NEW_PCONST (cfg, iargs [0], str);
10759                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
10760                         } else {
10761                                 if (cfg->opt & MONO_OPT_SHARED) {
10762                                         MonoInst *iargs [3];
10763
10764                                         if (cfg->compile_aot) {
10765                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
10766                                         }
10767                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10768                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
10769                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
10770                                         *sp = mono_emit_jit_icall (cfg, ves_icall_mono_ldstr, iargs);
10771                                         mono_ldstr_checked (cfg->domain, image, mono_metadata_token_index (n), &cfg->error);
10772                                         CHECK_CFG_ERROR;
10773                                 } else {
10774                                         if (cfg->cbb->out_of_line) {
10775                                                 MonoInst *iargs [2];
10776
10777                                                 if (image == mono_defaults.corlib) {
10778                                                         /* 
10779                                                          * Avoid relocations in AOT and save some space by using a 
10780                                                          * version of helper_ldstr specialized to mscorlib.
10781                                                          */
10782                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
10783                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
10784                                                 } else {
10785                                                         /* Avoid creating the string object */
10786                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
10787                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
10788                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
10789                                                 }
10790                                         } 
10791                                         else
10792                                         if (cfg->compile_aot) {
10793                                                 NEW_LDSTRCONST (cfg, ins, image, n);
10794                                                 *sp = ins;
10795                                                 MONO_ADD_INS (cfg->cbb, ins);
10796                                         } 
10797                                         else {
10798                                                 NEW_PCONST (cfg, ins, NULL);
10799                                                 ins->type = STACK_OBJ;
10800                                                 ins->inst_p0 = mono_ldstr_checked (cfg->domain, image, mono_metadata_token_index (n), &cfg->error);
10801                                                 CHECK_CFG_ERROR;
10802                                                 
10803                                                 if (!ins->inst_p0)
10804                                                         OUT_OF_MEMORY_FAILURE;
10805
10806                                                 *sp = ins;
10807                                                 MONO_ADD_INS (cfg->cbb, ins);
10808                                         }
10809                                 }
10810                         }
10811
10812                         sp++;
10813                         ip += 5;
10814                         break;
10815                 case CEE_NEWOBJ: {
10816                         MonoInst *iargs [2];
10817                         MonoMethodSignature *fsig;
10818                         MonoInst this_ins;
10819                         MonoInst *alloc;
10820                         MonoInst *vtable_arg = NULL;
10821
10822                         CHECK_OPSIZE (5);
10823                         token = read32 (ip + 1);
10824                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
10825                         CHECK_CFG_ERROR;
10826
10827                         fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
10828                         CHECK_CFG_ERROR;
10829
10830                         mono_save_token_info (cfg, image, token, cmethod);
10831
10832                         if (!mono_class_init (cmethod->klass))
10833                                 TYPE_LOAD_ERROR (cmethod->klass);
10834
10835                         context_used = mini_method_check_context_used (cfg, cmethod);
10836
10837                         if (mono_security_core_clr_enabled ())
10838                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
10839
10840                         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)) {
10841                                 emit_class_init (cfg, cmethod->klass);
10842                                 CHECK_TYPELOAD (cmethod->klass);
10843                         }
10844
10845                         /*
10846                         if (cfg->gsharedvt) {
10847                                 if (mini_is_gsharedvt_variable_signature (sig))
10848                                         GSHAREDVT_FAILURE (*ip);
10849                         }
10850                         */
10851
10852                         n = fsig->param_count;
10853                         CHECK_STACK (n);
10854
10855                         /* 
10856                          * Generate smaller code for the common newobj <exception> instruction in
10857                          * argument checking code.
10858                          */
10859                         if (cfg->cbb->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
10860                                 is_exception_class (cmethod->klass) && n <= 2 &&
10861                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
10862                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
10863                                 MonoInst *iargs [3];
10864
10865                                 sp -= n;
10866
10867                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
10868                                 switch (n) {
10869                                 case 0:
10870                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
10871                                         break;
10872                                 case 1:
10873                                         iargs [1] = sp [0];
10874                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
10875                                         break;
10876                                 case 2:
10877                                         iargs [1] = sp [0];
10878                                         iargs [2] = sp [1];
10879                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
10880                                         break;
10881                                 default:
10882                                         g_assert_not_reached ();
10883                                 }
10884
10885                                 ip += 5;
10886                                 inline_costs += 5;
10887                                 break;
10888                         }
10889
10890                         /* move the args to allow room for 'this' in the first position */
10891                         while (n--) {
10892                                 --sp;
10893                                 sp [1] = sp [0];
10894                         }
10895
10896                         /* check_call_signature () requires sp[0] to be set */
10897                         this_ins.type = STACK_OBJ;
10898                         sp [0] = &this_ins;
10899                         if (check_call_signature (cfg, fsig, sp))
10900                                 UNVERIFIED;
10901
10902                         iargs [0] = NULL;
10903
10904                         if (mini_class_is_system_array (cmethod->klass)) {
10905                                 *sp = emit_get_rgctx_method (cfg, context_used,
10906                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
10907
10908                                 /* Avoid varargs in the common case */
10909                                 if (fsig->param_count == 1)
10910                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
10911                                 else if (fsig->param_count == 2)
10912                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
10913                                 else if (fsig->param_count == 3)
10914                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
10915                                 else if (fsig->param_count == 4)
10916                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
10917                                 else
10918                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
10919                         } else if (cmethod->string_ctor) {
10920                                 g_assert (!context_used);
10921                                 g_assert (!vtable_arg);
10922                                 /* we simply pass a null pointer */
10923                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
10924                                 /* now call the string ctor */
10925                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
10926                         } else {
10927                                 if (cmethod->klass->valuetype) {
10928                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
10929                                         emit_init_rvar (cfg, iargs [0]->dreg, &cmethod->klass->byval_arg);
10930                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
10931
10932                                         alloc = NULL;
10933
10934                                         /* 
10935                                          * The code generated by mini_emit_virtual_call () expects
10936                                          * iargs [0] to be a boxed instance, but luckily the vcall
10937                                          * will be transformed into a normal call there.
10938                                          */
10939                                 } else if (context_used) {
10940                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
10941                                         *sp = alloc;
10942                                 } else {
10943                                         MonoVTable *vtable = NULL;
10944
10945                                         if (!cfg->compile_aot)
10946                                                 vtable = mono_class_vtable (cfg->domain, cmethod->klass);
10947                                         CHECK_TYPELOAD (cmethod->klass);
10948
10949                                         /*
10950                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
10951                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
10952                                          * As a workaround, we call class cctors before allocating objects.
10953                                          */
10954                                         if (mini_field_access_needs_cctor_run (cfg, method, cmethod->klass, vtable) && !(g_slist_find (class_inits, cmethod->klass))) {
10955                                                 emit_class_init (cfg, cmethod->klass);
10956                                                 if (cfg->verbose_level > 2)
10957                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
10958                                                 class_inits = g_slist_prepend (class_inits, cmethod->klass);
10959                                         }
10960
10961                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
10962                                         *sp = alloc;
10963                                 }
10964                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
10965
10966                                 if (alloc)
10967                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
10968
10969                                 /* Now call the actual ctor */
10970                                 handle_ctor_call (cfg, cmethod, fsig, context_used, sp, ip, &inline_costs);
10971                                 CHECK_CFG_EXCEPTION;
10972                         }
10973
10974                         if (alloc == NULL) {
10975                                 /* Valuetype */
10976                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
10977                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
10978                                 *sp++= ins;
10979                         } else {
10980                                 *sp++ = alloc;
10981                         }
10982                         
10983                         ip += 5;
10984                         inline_costs += 5;
10985                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip - header->code)))
10986                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10987                         break;
10988                 }
10989                 case CEE_CASTCLASS:
10990                 case CEE_ISINST: {
10991                         CHECK_STACK (1);
10992                         --sp;
10993                         CHECK_OPSIZE (5);
10994                         token = read32 (ip + 1);
10995                         klass = mini_get_class (method, token, generic_context);
10996                         CHECK_TYPELOAD (klass);
10997                         if (sp [0]->type != STACK_OBJ)
10998                                 UNVERIFIED;
10999
11000                         MONO_INST_NEW (cfg, ins, *ip == CEE_ISINST ? OP_ISINST : OP_CASTCLASS);
11001                         ins->dreg = alloc_preg (cfg);
11002                         ins->sreg1 = (*sp)->dreg;
11003                         ins->klass = klass;
11004                         ins->type = STACK_OBJ;
11005                         MONO_ADD_INS (cfg->cbb, ins);
11006
11007                         CHECK_CFG_EXCEPTION;
11008                         *sp++ = ins;
11009                         ip += 5;
11010
11011                         cfg->flags |= MONO_CFG_HAS_TYPE_CHECK;
11012                         break;
11013                 }
11014                 case CEE_UNBOX_ANY: {
11015                         MonoInst *res, *addr;
11016
11017                         CHECK_STACK (1);
11018                         --sp;
11019                         CHECK_OPSIZE (5);
11020                         token = read32 (ip + 1);
11021                         klass = mini_get_class (method, token, generic_context);
11022                         CHECK_TYPELOAD (klass);
11023
11024                         mono_save_token_info (cfg, image, token, klass);
11025
11026                         context_used = mini_class_check_context_used (cfg, klass);
11027
11028                         if (mini_is_gsharedvt_klass (klass)) {
11029                                 res = handle_unbox_gsharedvt (cfg, klass, *sp);
11030                                 inline_costs += 2;
11031                         } else if (generic_class_is_reference_type (cfg, klass)) {
11032                                 MONO_INST_NEW (cfg, res, OP_CASTCLASS);
11033                                 res->dreg = alloc_preg (cfg);
11034                                 res->sreg1 = (*sp)->dreg;
11035                                 res->klass = klass;
11036                                 res->type = STACK_OBJ;
11037                                 MONO_ADD_INS (cfg->cbb, res);
11038                                 cfg->flags |= MONO_CFG_HAS_TYPE_CHECK;
11039                         } else if (mono_class_is_nullable (klass)) {
11040                                 res = handle_unbox_nullable (cfg, *sp, klass, context_used);
11041                         } else {
11042                                 addr = handle_unbox (cfg, klass, sp, context_used);
11043                                 /* LDOBJ */
11044                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11045                                 res = ins;
11046                                 inline_costs += 2;
11047                         }
11048
11049                         *sp ++ = res;
11050                         ip += 5;
11051                         break;
11052                 }
11053                 case CEE_BOX: {
11054                         MonoInst *val;
11055                         MonoClass *enum_class;
11056                         MonoMethod *has_flag;
11057
11058                         CHECK_STACK (1);
11059                         --sp;
11060                         val = *sp;
11061                         CHECK_OPSIZE (5);
11062                         token = read32 (ip + 1);
11063                         klass = mini_get_class (method, token, generic_context);
11064                         CHECK_TYPELOAD (klass);
11065
11066                         mono_save_token_info (cfg, image, token, klass);
11067
11068                         context_used = mini_class_check_context_used (cfg, klass);
11069
11070                         if (generic_class_is_reference_type (cfg, klass)) {
11071                                 *sp++ = val;
11072                                 ip += 5;
11073                                 break;
11074                         }
11075
11076                         if (klass == mono_defaults.void_class)
11077                                 UNVERIFIED;
11078                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
11079                                 UNVERIFIED;
11080                         /* frequent check in generic code: box (struct), brtrue */
11081
11082                         /*
11083                          * Look for:
11084                          *
11085                          *   <push int/long ptr>
11086                          *   <push int/long>
11087                          *   box MyFlags
11088                          *   constrained. MyFlags
11089                          *   callvirt instace bool class [mscorlib] System.Enum::HasFlag (class [mscorlib] System.Enum)
11090                          *
11091                          * If we find this sequence and the operand types on box and constrained
11092                          * are equal, we can emit a specialized instruction sequence instead of
11093                          * the very slow HasFlag () call.
11094                          */
11095                         if ((cfg->opt & MONO_OPT_INTRINS) &&
11096                             /* Cheap checks first. */
11097                             ip + 5 + 6 + 5 < end &&
11098                             ip [5] == CEE_PREFIX1 &&
11099                             ip [6] == CEE_CONSTRAINED_ &&
11100                             ip [11] == CEE_CALLVIRT &&
11101                             ip_in_bb (cfg, cfg->cbb, ip + 5 + 6 + 5) &&
11102                             mono_class_is_enum (klass) &&
11103                             (enum_class = mini_get_class (method, read32 (ip + 7), generic_context)) &&
11104                             (has_flag = mini_get_method (cfg, method, read32 (ip + 12), NULL, generic_context)) &&
11105                             has_flag->klass == mono_defaults.enum_class &&
11106                             !strcmp (has_flag->name, "HasFlag") &&
11107                             has_flag->signature->hasthis &&
11108                             has_flag->signature->param_count == 1) {
11109                                 CHECK_TYPELOAD (enum_class);
11110
11111                                 if (enum_class == klass) {
11112                                         MonoInst *enum_this, *enum_flag;
11113
11114                                         ip += 5 + 6 + 5;
11115                                         --sp;
11116
11117                                         enum_this = sp [0];
11118                                         enum_flag = sp [1];
11119
11120                                         *sp++ = handle_enum_has_flag (cfg, klass, enum_this, enum_flag);
11121                                         break;
11122                                 }
11123                         }
11124
11125                         // FIXME: LLVM can't handle the inconsistent bb linking
11126                         if (!mono_class_is_nullable (klass) &&
11127                                 !mini_is_gsharedvt_klass (klass) &&
11128                                 ip + 5 < end && ip_in_bb (cfg, cfg->cbb, ip + 5) &&
11129                                 (ip [5] == CEE_BRTRUE || 
11130                                  ip [5] == CEE_BRTRUE_S ||
11131                                  ip [5] == CEE_BRFALSE ||
11132                                  ip [5] == CEE_BRFALSE_S)) {
11133                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
11134                                 int dreg;
11135                                 MonoBasicBlock *true_bb, *false_bb;
11136
11137                                 ip += 5;
11138
11139                                 if (cfg->verbose_level > 3) {
11140                                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
11141                                         printf ("<box+brtrue opt>\n");
11142                                 }
11143
11144                                 switch (*ip) {
11145                                 case CEE_BRTRUE_S:
11146                                 case CEE_BRFALSE_S:
11147                                         CHECK_OPSIZE (2);
11148                                         ip++;
11149                                         target = ip + 1 + (signed char)(*ip);
11150                                         ip++;
11151                                         break;
11152                                 case CEE_BRTRUE:
11153                                 case CEE_BRFALSE:
11154                                         CHECK_OPSIZE (5);
11155                                         ip++;
11156                                         target = ip + 4 + (gint)(read32 (ip));
11157                                         ip += 4;
11158                                         break;
11159                                 default:
11160                                         g_assert_not_reached ();
11161                                 }
11162
11163                                 /* 
11164                                  * We need to link both bblocks, since it is needed for handling stack
11165                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
11166                                  * Branching to only one of them would lead to inconsistencies, so
11167                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
11168                                  */
11169                                 GET_BBLOCK (cfg, true_bb, target);
11170                                 GET_BBLOCK (cfg, false_bb, ip);
11171
11172                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
11173                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
11174
11175                                 if (sp != stack_start) {
11176                                         handle_stack_args (cfg, stack_start, sp - stack_start);
11177                                         sp = stack_start;
11178                                         CHECK_UNVERIFIABLE (cfg);
11179                                 }
11180
11181                                 if (COMPILE_LLVM (cfg)) {
11182                                         dreg = alloc_ireg (cfg);
11183                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
11184                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
11185
11186                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
11187                                 } else {
11188                                         /* The JIT can't eliminate the iconst+compare */
11189                                         MONO_INST_NEW (cfg, ins, OP_BR);
11190                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
11191                                         MONO_ADD_INS (cfg->cbb, ins);
11192                                 }
11193
11194                                 start_new_bblock = 1;
11195                                 break;
11196                         }
11197
11198                         *sp++ = handle_box (cfg, val, klass, context_used);
11199
11200                         CHECK_CFG_EXCEPTION;
11201                         ip += 5;
11202                         inline_costs += 1;
11203                         break;
11204                 }
11205                 case CEE_UNBOX: {
11206                         CHECK_STACK (1);
11207                         --sp;
11208                         CHECK_OPSIZE (5);
11209                         token = read32 (ip + 1);
11210                         klass = mini_get_class (method, token, generic_context);
11211                         CHECK_TYPELOAD (klass);
11212
11213                         mono_save_token_info (cfg, image, token, klass);
11214
11215                         context_used = mini_class_check_context_used (cfg, klass);
11216
11217                         if (mono_class_is_nullable (klass)) {
11218                                 MonoInst *val;
11219
11220                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
11221                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
11222
11223                                 *sp++= ins;
11224                         } else {
11225                                 ins = handle_unbox (cfg, klass, sp, context_used);
11226                                 *sp++ = ins;
11227                         }
11228                         ip += 5;
11229                         inline_costs += 2;
11230                         break;
11231                 }
11232                 case CEE_LDFLD:
11233                 case CEE_LDFLDA:
11234                 case CEE_STFLD:
11235                 case CEE_LDSFLD:
11236                 case CEE_LDSFLDA:
11237                 case CEE_STSFLD: {
11238                         MonoClassField *field;
11239 #ifndef DISABLE_REMOTING
11240                         int costs;
11241 #endif
11242                         guint foffset;
11243                         gboolean is_instance;
11244                         int op;
11245                         gpointer addr = NULL;
11246                         gboolean is_special_static;
11247                         MonoType *ftype;
11248                         MonoInst *store_val = NULL;
11249                         MonoInst *thread_ins;
11250
11251                         op = *ip;
11252                         is_instance = (op == CEE_LDFLD || op == CEE_LDFLDA || op == CEE_STFLD);
11253                         if (is_instance) {
11254                                 if (op == CEE_STFLD) {
11255                                         CHECK_STACK (2);
11256                                         sp -= 2;
11257                                         store_val = sp [1];
11258                                 } else {
11259                                         CHECK_STACK (1);
11260                                         --sp;
11261                                 }
11262                                 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
11263                                         UNVERIFIED;
11264                                 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
11265                                         UNVERIFIED;
11266                         } else {
11267                                 if (op == CEE_STSFLD) {
11268                                         CHECK_STACK (1);
11269                                         sp--;
11270                                         store_val = sp [0];
11271                                 }
11272                         }
11273
11274                         CHECK_OPSIZE (5);
11275                         token = read32 (ip + 1);
11276                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
11277                                 field = (MonoClassField *)mono_method_get_wrapper_data (method, token);
11278                                 klass = field->parent;
11279                         }
11280                         else {
11281                                 field = mono_field_from_token_checked (image, token, &klass, generic_context, &cfg->error);
11282                                 CHECK_CFG_ERROR;
11283                         }
11284                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
11285                                 FIELD_ACCESS_FAILURE (method, field);
11286                         mono_class_init (klass);
11287
11288                         /* if the class is Critical then transparent code cannot access it's fields */
11289                         if (!is_instance && mono_security_core_clr_enabled ())
11290                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
11291
11292                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
11293                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
11294                         if (mono_security_core_clr_enabled ())
11295                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
11296                         */
11297
11298                         ftype = mono_field_get_type (field);
11299
11300                         /*
11301                          * LDFLD etc. is usable on static fields as well, so convert those cases to
11302                          * the static case.
11303                          */
11304                         if (is_instance && ftype->attrs & FIELD_ATTRIBUTE_STATIC) {
11305                                 switch (op) {
11306                                 case CEE_LDFLD:
11307                                         op = CEE_LDSFLD;
11308                                         break;
11309                                 case CEE_STFLD:
11310                                         op = CEE_STSFLD;
11311                                         break;
11312                                 case CEE_LDFLDA:
11313                                         op = CEE_LDSFLDA;
11314                                         break;
11315                                 default:
11316                                         g_assert_not_reached ();
11317                                 }
11318                                 is_instance = FALSE;
11319                         }
11320
11321                         context_used = mini_class_check_context_used (cfg, klass);
11322
11323                         /* INSTANCE CASE */
11324
11325                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
11326                         if (op == CEE_STFLD) {
11327                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
11328                                         UNVERIFIED;
11329 #ifndef DISABLE_REMOTING
11330                                 if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
11331                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
11332                                         MonoInst *iargs [5];
11333
11334                                         GSHAREDVT_FAILURE (op);
11335
11336                                         iargs [0] = sp [0];
11337                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11338                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
11339                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
11340                                                     field->offset);
11341                                         iargs [4] = sp [1];
11342
11343                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
11344                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
11345                                                                                            iargs, ip, cfg->real_offset, TRUE);
11346                                                 CHECK_CFG_EXCEPTION;
11347                                                 g_assert (costs > 0);
11348                                                       
11349                                                 cfg->real_offset += 5;
11350
11351                                                 inline_costs += costs;
11352                                         } else {
11353                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
11354                                         }
11355                                 } else
11356 #endif
11357                                 {
11358                                         MonoInst *store, *wbarrier_ptr_ins = NULL;
11359
11360                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
11361
11362                                         if (ins_flag & MONO_INST_VOLATILE) {
11363                                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11364                                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11365                                         }
11366
11367                                         if (mini_is_gsharedvt_klass (klass)) {
11368                                                 MonoInst *offset_ins;
11369
11370                                                 context_used = mini_class_check_context_used (cfg, klass);
11371
11372                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11373                                                 /* The value is offset by 1 */
11374                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11375                                                 dreg = alloc_ireg_mp (cfg);
11376                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11377                                                 wbarrier_ptr_ins = ins;
11378                                                 /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
11379                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
11380                                         } else {
11381                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
11382                                         }
11383                                         if (sp [0]->opcode != OP_LDADDR)
11384                                                 store->flags |= MONO_INST_FAULT;
11385
11386                                         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)) {
11387                                                 if (mini_is_gsharedvt_klass (klass)) {
11388                                                         g_assert (wbarrier_ptr_ins);
11389                                                         emit_write_barrier (cfg, wbarrier_ptr_ins, sp [1]);
11390                                                 } else {
11391                                                         /* insert call to write barrier */
11392                                                         MonoInst *ptr;
11393                                                         int dreg;
11394
11395                                                         dreg = alloc_ireg_mp (cfg);
11396                                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
11397                                                         emit_write_barrier (cfg, ptr, sp [1]);
11398                                                 }
11399                                         }
11400
11401                                         store->flags |= ins_flag;
11402                                 }
11403                                 ins_flag = 0;
11404                                 ip += 5;
11405                                 break;
11406                         }
11407
11408 #ifndef DISABLE_REMOTING
11409                         if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
11410                                 MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
11411                                 MonoInst *iargs [4];
11412
11413                                 GSHAREDVT_FAILURE (op);
11414
11415                                 iargs [0] = sp [0];
11416                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11417                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
11418                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
11419                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
11420                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
11421                                                                                    iargs, ip, cfg->real_offset, TRUE);
11422                                         CHECK_CFG_EXCEPTION;
11423                                         g_assert (costs > 0);
11424                                                       
11425                                         cfg->real_offset += 5;
11426
11427                                         *sp++ = iargs [0];
11428
11429                                         inline_costs += costs;
11430                                 } else {
11431                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
11432                                         *sp++ = ins;
11433                                 }
11434                         } else 
11435 #endif
11436                         if (is_instance) {
11437                                 if (sp [0]->type == STACK_VTYPE) {
11438                                         MonoInst *var;
11439
11440                                         /* Have to compute the address of the variable */
11441
11442                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
11443                                         if (!var)
11444                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
11445                                         else
11446                                                 g_assert (var->klass == klass);
11447                                         
11448                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
11449                                         sp [0] = ins;
11450                                 }
11451
11452                                 if (op == CEE_LDFLDA) {
11453                                         if (sp [0]->type == STACK_OBJ) {
11454                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
11455                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
11456                                         }
11457
11458                                         dreg = alloc_ireg_mp (cfg);
11459
11460                                         if (mini_is_gsharedvt_klass (klass)) {
11461                                                 MonoInst *offset_ins;
11462
11463                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11464                                                 /* The value is offset by 1 */
11465                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11466                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11467                                         } else {
11468                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
11469                                         }
11470                                         ins->klass = mono_class_from_mono_type (field->type);
11471                                         ins->type = STACK_MP;
11472                                         *sp++ = ins;
11473                                 } else {
11474                                         MonoInst *load;
11475
11476                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
11477
11478                                         if (mini_is_gsharedvt_klass (klass)) {
11479                                                 MonoInst *offset_ins;
11480
11481                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11482                                                 /* The value is offset by 1 */
11483                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11484                                                 dreg = alloc_ireg_mp (cfg);
11485                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11486                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
11487                                         } else {
11488                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
11489                                         }
11490                                         load->flags |= ins_flag;
11491                                         if (sp [0]->opcode != OP_LDADDR)
11492                                                 load->flags |= MONO_INST_FAULT;
11493                                         *sp++ = load;
11494                                 }
11495                         }
11496
11497                         if (is_instance) {
11498                                 ins_flag = 0;
11499                                 ip += 5;
11500                                 break;
11501                         }
11502
11503                         /* STATIC CASE */
11504                         context_used = mini_class_check_context_used (cfg, klass);
11505
11506                         if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL) {
11507                                 mono_error_set_field_load (&cfg->error, field->parent, field->name, "Using static instructions with literal field");
11508                                 CHECK_CFG_ERROR;
11509                         }
11510
11511                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
11512                          * to be called here.
11513                          */
11514                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
11515                                 mono_class_vtable (cfg->domain, klass);
11516                                 CHECK_TYPELOAD (klass);
11517                         }
11518                         mono_domain_lock (cfg->domain);
11519                         if (cfg->domain->special_static_fields)
11520                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
11521                         mono_domain_unlock (cfg->domain);
11522
11523                         is_special_static = mono_class_field_is_special_static (field);
11524
11525                         if (is_special_static && ((gsize)addr & 0x80000000) == 0)
11526                                 thread_ins = mono_get_thread_intrinsic (cfg);
11527                         else
11528                                 thread_ins = NULL;
11529
11530                         /* Generate IR to compute the field address */
11531                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && thread_ins && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
11532                                 /*
11533                                  * Fast access to TLS data
11534                                  * Inline version of get_thread_static_data () in
11535                                  * threads.c.
11536                                  */
11537                                 guint32 offset;
11538                                 int idx, static_data_reg, array_reg, dreg;
11539
11540                                 GSHAREDVT_FAILURE (op);
11541
11542                                 MONO_ADD_INS (cfg->cbb, thread_ins);
11543                                 static_data_reg = alloc_ireg (cfg);
11544                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
11545
11546                                 if (cfg->compile_aot) {
11547                                         int offset_reg, offset2_reg, idx_reg;
11548
11549                                         /* For TLS variables, this will return the TLS offset */
11550                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
11551                                         offset_reg = ins->dreg;
11552                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
11553                                         idx_reg = alloc_ireg (cfg);
11554                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, idx_reg, offset_reg, 0x3f);
11555                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
11556                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
11557                                         array_reg = alloc_ireg (cfg);
11558                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
11559                                         offset2_reg = alloc_ireg (cfg);
11560                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, offset2_reg, offset_reg, 6);
11561                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset2_reg, 0x1ffffff);
11562                                         dreg = alloc_ireg (cfg);
11563                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
11564                                 } else {
11565                                         offset = (gsize)addr & 0x7fffffff;
11566                                         idx = offset & 0x3f;
11567
11568                                         array_reg = alloc_ireg (cfg);
11569                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
11570                                         dreg = alloc_ireg (cfg);
11571                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, ((offset >> 6) & 0x1ffffff));
11572                                 }
11573                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
11574                                         (cfg->compile_aot && is_special_static) ||
11575                                         (context_used && is_special_static)) {
11576                                 MonoInst *iargs [2];
11577
11578                                 g_assert (field->parent);
11579                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11580                                 if (context_used) {
11581                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
11582                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
11583                                 } else {
11584                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11585                                 }
11586                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11587                         } else if (context_used) {
11588                                 MonoInst *static_data;
11589
11590                                 /*
11591                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
11592                                         method->klass->name_space, method->klass->name, method->name,
11593                                         depth, field->offset);
11594                                 */
11595
11596                                 if (mono_class_needs_cctor_run (klass, method))
11597                                         emit_class_init (cfg, klass);
11598
11599                                 /*
11600                                  * The pointer we're computing here is
11601                                  *
11602                                  *   super_info.static_data + field->offset
11603                                  */
11604                                 static_data = emit_get_rgctx_klass (cfg, context_used,
11605                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
11606
11607                                 if (mini_is_gsharedvt_klass (klass)) {
11608                                         MonoInst *offset_ins;
11609
11610                                         offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11611                                         /* The value is offset by 1 */
11612                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11613                                         dreg = alloc_ireg_mp (cfg);
11614                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
11615                                 } else if (field->offset == 0) {
11616                                         ins = static_data;
11617                                 } else {
11618                                         int addr_reg = mono_alloc_preg (cfg);
11619                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
11620                                 }
11621                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
11622                                 MonoInst *iargs [2];
11623
11624                                 g_assert (field->parent);
11625                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11626                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11627                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11628                         } else {
11629                                 MonoVTable *vtable = NULL;
11630
11631                                 if (!cfg->compile_aot)
11632                                         vtable = mono_class_vtable (cfg->domain, klass);
11633                                 CHECK_TYPELOAD (klass);
11634
11635                                 if (!addr) {
11636                                         if (mini_field_access_needs_cctor_run (cfg, method, klass, vtable)) {
11637                                                 if (!(g_slist_find (class_inits, klass))) {
11638                                                         emit_class_init (cfg, klass);
11639                                                         if (cfg->verbose_level > 2)
11640                                                                 printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
11641                                                         class_inits = g_slist_prepend (class_inits, klass);
11642                                                 }
11643                                         } else {
11644                                                 if (cfg->run_cctors) {
11645                                                         /* This makes so that inline cannot trigger */
11646                                                         /* .cctors: too many apps depend on them */
11647                                                         /* running with a specific order... */
11648                                                         g_assert (vtable);
11649                                                         if (! vtable->initialized)
11650                                                                 INLINE_FAILURE ("class init");
11651                                                         if (!mono_runtime_class_init_full (vtable, &cfg->error)) {
11652                                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
11653                                                                 goto exception_exit;
11654                                                         }
11655                                                 }
11656                                         }
11657                                         if (cfg->compile_aot)
11658                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
11659                                         else {
11660                                                 g_assert (vtable);
11661                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11662                                                 g_assert (addr);
11663                                                 EMIT_NEW_PCONST (cfg, ins, addr);
11664                                         }
11665                                 } else {
11666                                         MonoInst *iargs [1];
11667                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
11668                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
11669                                 }
11670                         }
11671
11672                         /* Generate IR to do the actual load/store operation */
11673
11674                         if ((op == CEE_STFLD || op == CEE_STSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11675                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11676                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11677                         }
11678
11679                         if (op == CEE_LDSFLDA) {
11680                                 ins->klass = mono_class_from_mono_type (ftype);
11681                                 ins->type = STACK_PTR;
11682                                 *sp++ = ins;
11683                         } else if (op == CEE_STSFLD) {
11684                                 MonoInst *store;
11685
11686                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
11687                                 store->flags |= ins_flag;
11688                         } else {
11689                                 gboolean is_const = FALSE;
11690                                 MonoVTable *vtable = NULL;
11691                                 gpointer addr = NULL;
11692
11693                                 if (!context_used) {
11694                                         vtable = mono_class_vtable (cfg->domain, klass);
11695                                         CHECK_TYPELOAD (klass);
11696                                 }
11697                                 if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) ||
11698                                                 (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) {
11699                                         int ro_type = ftype->type;
11700                                         if (!addr)
11701                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11702                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
11703                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
11704                                         }
11705
11706                                         GSHAREDVT_FAILURE (op);
11707
11708                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
11709                                         is_const = TRUE;
11710                                         switch (ro_type) {
11711                                         case MONO_TYPE_BOOLEAN:
11712                                         case MONO_TYPE_U1:
11713                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
11714                                                 sp++;
11715                                                 break;
11716                                         case MONO_TYPE_I1:
11717                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
11718                                                 sp++;
11719                                                 break;                                          
11720                                         case MONO_TYPE_CHAR:
11721                                         case MONO_TYPE_U2:
11722                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
11723                                                 sp++;
11724                                                 break;
11725                                         case MONO_TYPE_I2:
11726                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
11727                                                 sp++;
11728                                                 break;
11729                                                 break;
11730                                         case MONO_TYPE_I4:
11731                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
11732                                                 sp++;
11733                                                 break;                                          
11734                                         case MONO_TYPE_U4:
11735                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
11736                                                 sp++;
11737                                                 break;
11738                                         case MONO_TYPE_I:
11739                                         case MONO_TYPE_U:
11740                                         case MONO_TYPE_PTR:
11741                                         case MONO_TYPE_FNPTR:
11742                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11743                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
11744                                                 sp++;
11745                                                 break;
11746                                         case MONO_TYPE_STRING:
11747                                         case MONO_TYPE_OBJECT:
11748                                         case MONO_TYPE_CLASS:
11749                                         case MONO_TYPE_SZARRAY:
11750                                         case MONO_TYPE_ARRAY:
11751                                                 if (!mono_gc_is_moving ()) {
11752                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11753                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
11754                                                         sp++;
11755                                                 } else {
11756                                                         is_const = FALSE;
11757                                                 }
11758                                                 break;
11759                                         case MONO_TYPE_I8:
11760                                         case MONO_TYPE_U8:
11761                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
11762                                                 sp++;
11763                                                 break;
11764                                         case MONO_TYPE_R4:
11765                                         case MONO_TYPE_R8:
11766                                         case MONO_TYPE_VALUETYPE:
11767                                         default:
11768                                                 is_const = FALSE;
11769                                                 break;
11770                                         }
11771                                 }
11772
11773                                 if (!is_const) {
11774                                         MonoInst *load;
11775
11776                                         CHECK_STACK_OVF (1);
11777
11778                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
11779                                         load->flags |= ins_flag;
11780                                         ins_flag = 0;
11781                                         *sp++ = load;
11782                                 }
11783                         }
11784
11785                         if ((op == CEE_LDFLD || op == CEE_LDSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11786                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
11787                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
11788                         }
11789
11790                         ins_flag = 0;
11791                         ip += 5;
11792                         break;
11793                 }
11794                 case CEE_STOBJ:
11795                         CHECK_STACK (2);
11796                         sp -= 2;
11797                         CHECK_OPSIZE (5);
11798                         token = read32 (ip + 1);
11799                         klass = mini_get_class (method, token, generic_context);
11800                         CHECK_TYPELOAD (klass);
11801                         if (ins_flag & MONO_INST_VOLATILE) {
11802                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11803                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11804                         }
11805                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
11806                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
11807                         ins->flags |= ins_flag;
11808                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
11809                                         generic_class_is_reference_type (cfg, klass)) {
11810                                 /* insert call to write barrier */
11811                                 emit_write_barrier (cfg, sp [0], sp [1]);
11812                         }
11813                         ins_flag = 0;
11814                         ip += 5;
11815                         inline_costs += 1;
11816                         break;
11817
11818                         /*
11819                          * Array opcodes
11820                          */
11821                 case CEE_NEWARR: {
11822                         MonoInst *len_ins;
11823                         const char *data_ptr;
11824                         int data_size = 0;
11825                         guint32 field_token;
11826
11827                         CHECK_STACK (1);
11828                         --sp;
11829
11830                         CHECK_OPSIZE (5);
11831                         token = read32 (ip + 1);
11832
11833                         klass = mini_get_class (method, token, generic_context);
11834                         CHECK_TYPELOAD (klass);
11835
11836                         context_used = mini_class_check_context_used (cfg, klass);
11837
11838                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
11839                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_OVF_U4);
11840                                 ins->sreg1 = sp [0]->dreg;
11841                                 ins->type = STACK_I4;
11842                                 ins->dreg = alloc_ireg (cfg);
11843                                 MONO_ADD_INS (cfg->cbb, ins);
11844                                 *sp = mono_decompose_opcode (cfg, ins);
11845                         }
11846
11847                         if (context_used) {
11848                                 MonoInst *args [3];
11849                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11850                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
11851
11852                                 /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
11853
11854                                 /* vtable */
11855                                 args [0] = emit_get_rgctx_klass (cfg, context_used,
11856                                         array_class, MONO_RGCTX_INFO_VTABLE);
11857                                 /* array len */
11858                                 args [1] = sp [0];
11859
11860                                 if (managed_alloc)
11861                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
11862                                 else
11863                                         ins = mono_emit_jit_icall (cfg, ves_icall_array_new_specific, args);
11864                         } else {
11865                                 if (cfg->opt & MONO_OPT_SHARED) {
11866                                         /* Decompose now to avoid problems with references to the domainvar */
11867                                         MonoInst *iargs [3];
11868
11869                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11870                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11871                                         iargs [2] = sp [0];
11872
11873                                         ins = mono_emit_jit_icall (cfg, ves_icall_array_new, iargs);
11874                                 } else {
11875                                         /* Decompose later since it is needed by abcrem */
11876                                         MonoClass *array_type = mono_array_class_get (klass, 1);
11877                                         mono_class_vtable (cfg->domain, array_type);
11878                                         CHECK_TYPELOAD (array_type);
11879
11880                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
11881                                         ins->dreg = alloc_ireg_ref (cfg);
11882                                         ins->sreg1 = sp [0]->dreg;
11883                                         ins->inst_newa_class = klass;
11884                                         ins->type = STACK_OBJ;
11885                                         ins->klass = array_type;
11886                                         MONO_ADD_INS (cfg->cbb, ins);
11887                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11888                                         cfg->cbb->has_array_access = TRUE;
11889
11890                                         /* Needed so mono_emit_load_get_addr () gets called */
11891                                         mono_get_got_var (cfg);
11892                                 }
11893                         }
11894
11895                         len_ins = sp [0];
11896                         ip += 5;
11897                         *sp++ = ins;
11898                         inline_costs += 1;
11899
11900                         /* 
11901                          * we inline/optimize the initialization sequence if possible.
11902                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
11903                          * for small sizes open code the memcpy
11904                          * ensure the rva field is big enough
11905                          */
11906                         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))) {
11907                                 MonoMethod *memcpy_method = get_memcpy_method ();
11908                                 MonoInst *iargs [3];
11909                                 int add_reg = alloc_ireg_mp (cfg);
11910
11911                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, MONO_STRUCT_OFFSET (MonoArray, vector));
11912                                 if (cfg->compile_aot) {
11913                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
11914                                 } else {
11915                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
11916                                 }
11917                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
11918                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
11919                                 ip += 11;
11920                         }
11921
11922                         break;
11923                 }
11924                 case CEE_LDLEN:
11925                         CHECK_STACK (1);
11926                         --sp;
11927                         if (sp [0]->type != STACK_OBJ)
11928                                 UNVERIFIED;
11929
11930                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
11931                         ins->dreg = alloc_preg (cfg);
11932                         ins->sreg1 = sp [0]->dreg;
11933                         ins->type = STACK_I4;
11934                         /* This flag will be inherited by the decomposition */
11935                         ins->flags |= MONO_INST_FAULT;
11936                         MONO_ADD_INS (cfg->cbb, ins);
11937                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11938                         cfg->cbb->has_array_access = TRUE;
11939                         ip ++;
11940                         *sp++ = ins;
11941                         break;
11942                 case CEE_LDELEMA:
11943                         CHECK_STACK (2);
11944                         sp -= 2;
11945                         CHECK_OPSIZE (5);
11946                         if (sp [0]->type != STACK_OBJ)
11947                                 UNVERIFIED;
11948
11949                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11950
11951                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11952                         CHECK_TYPELOAD (klass);
11953                         /* we need to make sure that this array is exactly the type it needs
11954                          * to be for correctness. the wrappers are lax with their usage
11955                          * so we need to ignore them here
11956                          */
11957                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
11958                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11959                                 mini_emit_check_array_type (cfg, sp [0], array_class);
11960                                 CHECK_TYPELOAD (array_class);
11961                         }
11962
11963                         readonly = FALSE;
11964                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11965                         *sp++ = ins;
11966                         ip += 5;
11967                         break;
11968                 case CEE_LDELEM:
11969                 case CEE_LDELEM_I1:
11970                 case CEE_LDELEM_U1:
11971                 case CEE_LDELEM_I2:
11972                 case CEE_LDELEM_U2:
11973                 case CEE_LDELEM_I4:
11974                 case CEE_LDELEM_U4:
11975                 case CEE_LDELEM_I8:
11976                 case CEE_LDELEM_I:
11977                 case CEE_LDELEM_R4:
11978                 case CEE_LDELEM_R8:
11979                 case CEE_LDELEM_REF: {
11980                         MonoInst *addr;
11981
11982                         CHECK_STACK (2);
11983                         sp -= 2;
11984
11985                         if (*ip == CEE_LDELEM) {
11986                                 CHECK_OPSIZE (5);
11987                                 token = read32 (ip + 1);
11988                                 klass = mini_get_class (method, token, generic_context);
11989                                 CHECK_TYPELOAD (klass);
11990                                 mono_class_init (klass);
11991                         }
11992                         else
11993                                 klass = array_access_to_klass (*ip);
11994
11995                         if (sp [0]->type != STACK_OBJ)
11996                                 UNVERIFIED;
11997
11998                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11999
12000                         if (mini_is_gsharedvt_variable_klass (klass)) {
12001                                 // FIXME-VT: OP_ICONST optimization
12002                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
12003                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
12004                                 ins->opcode = OP_LOADV_MEMBASE;
12005                         } else if (sp [1]->opcode == OP_ICONST) {
12006                                 int array_reg = sp [0]->dreg;
12007                                 int index_reg = sp [1]->dreg;
12008                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
12009
12010                                 if (SIZEOF_REGISTER == 8 && COMPILE_LLVM (cfg))
12011                                         MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, index_reg);
12012
12013                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
12014                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
12015                         } else {
12016                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
12017                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
12018                         }
12019                         *sp++ = ins;
12020                         if (*ip == CEE_LDELEM)
12021                                 ip += 5;
12022                         else
12023                                 ++ip;
12024                         break;
12025                 }
12026                 case CEE_STELEM_I:
12027                 case CEE_STELEM_I1:
12028                 case CEE_STELEM_I2:
12029                 case CEE_STELEM_I4:
12030                 case CEE_STELEM_I8:
12031                 case CEE_STELEM_R4:
12032                 case CEE_STELEM_R8:
12033                 case CEE_STELEM_REF:
12034                 case CEE_STELEM: {
12035                         CHECK_STACK (3);
12036                         sp -= 3;
12037
12038                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
12039
12040                         if (*ip == CEE_STELEM) {
12041                                 CHECK_OPSIZE (5);
12042                                 token = read32 (ip + 1);
12043                                 klass = mini_get_class (method, token, generic_context);
12044                                 CHECK_TYPELOAD (klass);
12045                                 mono_class_init (klass);
12046                         }
12047                         else
12048                                 klass = array_access_to_klass (*ip);
12049
12050                         if (sp [0]->type != STACK_OBJ)
12051                                 UNVERIFIED;
12052
12053                         emit_array_store (cfg, klass, sp, TRUE);
12054
12055                         if (*ip == CEE_STELEM)
12056                                 ip += 5;
12057                         else
12058                                 ++ip;
12059                         inline_costs += 1;
12060                         break;
12061                 }
12062                 case CEE_CKFINITE: {
12063                         CHECK_STACK (1);
12064                         --sp;
12065
12066                         if (cfg->llvm_only) {
12067                                 MonoInst *iargs [1];
12068
12069                                 iargs [0] = sp [0];
12070                                 *sp++ = mono_emit_jit_icall (cfg, mono_ckfinite, iargs);
12071                         } else  {
12072                                 MONO_INST_NEW (cfg, ins, OP_CKFINITE);
12073                                 ins->sreg1 = sp [0]->dreg;
12074                                 ins->dreg = alloc_freg (cfg);
12075                                 ins->type = STACK_R8;
12076                                 MONO_ADD_INS (cfg->cbb, ins);
12077
12078                                 *sp++ = mono_decompose_opcode (cfg, ins);
12079                         }
12080
12081                         ++ip;
12082                         break;
12083                 }
12084                 case CEE_REFANYVAL: {
12085                         MonoInst *src_var, *src;
12086
12087                         int klass_reg = alloc_preg (cfg);
12088                         int dreg = alloc_preg (cfg);
12089
12090                         GSHAREDVT_FAILURE (*ip);
12091
12092                         CHECK_STACK (1);
12093                         MONO_INST_NEW (cfg, ins, *ip);
12094                         --sp;
12095                         CHECK_OPSIZE (5);
12096                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
12097                         CHECK_TYPELOAD (klass);
12098
12099                         context_used = mini_class_check_context_used (cfg, klass);
12100
12101                         // FIXME:
12102                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12103                         if (!src_var)
12104                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
12105                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
12106                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass));
12107
12108                         if (context_used) {
12109                                 MonoInst *klass_ins;
12110
12111                                 klass_ins = emit_get_rgctx_klass (cfg, context_used,
12112                                                 klass, MONO_RGCTX_INFO_KLASS);
12113
12114                                 // FIXME:
12115                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
12116                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
12117                         } else {
12118                                 mini_emit_class_check (cfg, klass_reg, klass);
12119                         }
12120                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value));
12121                         ins->type = STACK_MP;
12122                         ins->klass = klass;
12123                         *sp++ = ins;
12124                         ip += 5;
12125                         break;
12126                 }
12127                 case CEE_MKREFANY: {
12128                         MonoInst *loc, *addr;
12129
12130                         GSHAREDVT_FAILURE (*ip);
12131
12132                         CHECK_STACK (1);
12133                         MONO_INST_NEW (cfg, ins, *ip);
12134                         --sp;
12135                         CHECK_OPSIZE (5);
12136                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
12137                         CHECK_TYPELOAD (klass);
12138
12139                         context_used = mini_class_check_context_used (cfg, klass);
12140
12141                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
12142                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
12143
12144                         if (context_used) {
12145                                 MonoInst *const_ins;
12146                                 int type_reg = alloc_preg (cfg);
12147
12148                                 const_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
12149                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
12150                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
12151                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
12152                         } else if (cfg->compile_aot) {
12153                                 int const_reg = alloc_preg (cfg);
12154                                 int type_reg = alloc_preg (cfg);
12155
12156                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
12157                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
12158                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
12159                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
12160                         } else {
12161                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), &klass->byval_arg);
12162                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), klass);
12163                         }
12164                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
12165
12166                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
12167                         ins->type = STACK_VTYPE;
12168                         ins->klass = mono_defaults.typed_reference_class;
12169                         *sp++ = ins;
12170                         ip += 5;
12171                         break;
12172                 }
12173                 case CEE_LDTOKEN: {
12174                         gpointer handle;
12175                         MonoClass *handle_class;
12176
12177                         CHECK_STACK_OVF (1);
12178
12179                         CHECK_OPSIZE (5);
12180                         n = read32 (ip + 1);
12181
12182                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
12183                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
12184                                 handle = mono_method_get_wrapper_data (method, n);
12185                                 handle_class = (MonoClass *)mono_method_get_wrapper_data (method, n + 1);
12186                                 if (handle_class == mono_defaults.typehandle_class)
12187                                         handle = &((MonoClass*)handle)->byval_arg;
12188                         }
12189                         else {
12190                                 handle = mono_ldtoken_checked (image, n, &handle_class, generic_context, &cfg->error);
12191                                 CHECK_CFG_ERROR;
12192                         }
12193                         if (!handle)
12194                                 LOAD_ERROR;
12195                         mono_class_init (handle_class);
12196                         if (cfg->gshared) {
12197                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
12198                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
12199                                         /* This case handles ldtoken
12200                                            of an open type, like for
12201                                            typeof(Gen<>). */
12202                                         context_used = 0;
12203                                 } else if (handle_class == mono_defaults.typehandle_class) {
12204                                         context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type ((MonoType *)handle));
12205                                 } else if (handle_class == mono_defaults.fieldhandle_class)
12206                                         context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
12207                                 else if (handle_class == mono_defaults.methodhandle_class)
12208                                         context_used = mini_method_check_context_used (cfg, (MonoMethod *)handle);
12209                                 else
12210                                         g_assert_not_reached ();
12211                         }
12212
12213                         if ((cfg->opt & MONO_OPT_SHARED) &&
12214                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
12215                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
12216                                 MonoInst *addr, *vtvar, *iargs [3];
12217                                 int method_context_used;
12218
12219                                 method_context_used = mini_method_check_context_used (cfg, method);
12220
12221                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
12222
12223                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
12224                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
12225                                 if (method_context_used) {
12226                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
12227                                                 method, MONO_RGCTX_INFO_METHOD);
12228                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
12229                                 } else {
12230                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
12231                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
12232                                 }
12233                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12234
12235                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
12236
12237                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12238                         } else {
12239                                 if ((ip + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 5) && 
12240                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
12241                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
12242                                         (cmethod->klass == mono_defaults.systemtype_class) &&
12243                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
12244                                         MonoClass *tclass = mono_class_from_mono_type ((MonoType *)handle);
12245
12246                                         mono_class_init (tclass);
12247                                         if (context_used) {
12248                                                 ins = emit_get_rgctx_klass (cfg, context_used,
12249                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
12250                                         } else if (cfg->compile_aot) {
12251                                                 if (method->wrapper_type) {
12252                                                         mono_error_init (&error); //got to do it since there are multiple conditionals below
12253                                                         if (mono_class_get_checked (tclass->image, tclass->type_token, &error) == tclass && !generic_context) {
12254                                                                 /* Special case for static synchronized wrappers */
12255                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
12256                                                         } else {
12257                                                                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
12258                                                                 /* FIXME: n is not a normal token */
12259                                                                 DISABLE_AOT (cfg);
12260                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12261                                                         }
12262                                                 } else {
12263                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
12264                                                 }
12265                                         } else {
12266                                                 MonoReflectionType *rt = mono_type_get_object_checked (cfg->domain, (MonoType *)handle, &cfg->error);
12267                                                 CHECK_CFG_ERROR;
12268                                                 EMIT_NEW_PCONST (cfg, ins, rt);
12269                                         }
12270                                         ins->type = STACK_OBJ;
12271                                         ins->klass = cmethod->klass;
12272                                         ip += 5;
12273                                 } else {
12274                                         MonoInst *addr, *vtvar;
12275
12276                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
12277
12278                                         if (context_used) {
12279                                                 if (handle_class == mono_defaults.typehandle_class) {
12280                                                         ins = emit_get_rgctx_klass (cfg, context_used,
12281                                                                         mono_class_from_mono_type ((MonoType *)handle),
12282                                                                         MONO_RGCTX_INFO_TYPE);
12283                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
12284                                                         ins = emit_get_rgctx_method (cfg, context_used,
12285                                                                         (MonoMethod *)handle, MONO_RGCTX_INFO_METHOD);
12286                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
12287                                                         ins = emit_get_rgctx_field (cfg, context_used,
12288                                                                         (MonoClassField *)handle, MONO_RGCTX_INFO_CLASS_FIELD);
12289                                                 } else {
12290                                                         g_assert_not_reached ();
12291                                                 }
12292                                         } else if (cfg->compile_aot) {
12293                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n, generic_context);
12294                                         } else {
12295                                                 EMIT_NEW_PCONST (cfg, ins, handle);
12296                                         }
12297                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12298                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
12299                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12300                                 }
12301                         }
12302
12303                         *sp++ = ins;
12304                         ip += 5;
12305                         break;
12306                 }
12307                 case CEE_THROW:
12308                         CHECK_STACK (1);
12309                         if (sp [-1]->type != STACK_OBJ)
12310                                 UNVERIFIED;
12311
12312                         MONO_INST_NEW (cfg, ins, OP_THROW);
12313                         --sp;
12314                         ins->sreg1 = sp [0]->dreg;
12315                         ip++;
12316                         cfg->cbb->out_of_line = TRUE;
12317                         MONO_ADD_INS (cfg->cbb, ins);
12318                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
12319                         MONO_ADD_INS (cfg->cbb, ins);
12320                         sp = stack_start;
12321                         
12322                         link_bblock (cfg, cfg->cbb, end_bblock);
12323                         start_new_bblock = 1;
12324                         /* This can complicate code generation for llvm since the return value might not be defined */
12325                         if (COMPILE_LLVM (cfg))
12326                                 INLINE_FAILURE ("throw");
12327                         break;
12328                 case CEE_ENDFINALLY:
12329                         if (!ip_in_finally_clause (cfg, ip - header->code))
12330                                 UNVERIFIED;
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_ATOMIC_STORE_I4: {
12767                                 g_assert (mono_arch_opcode_supported (OP_ATOMIC_STORE_I4));
12768
12769                                 CHECK_OPSIZE (6);
12770                                 CHECK_STACK (2);
12771                                 sp -= 2;
12772
12773                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_STORE_I4);
12774                                 ins->dreg = sp [0]->dreg;
12775                                 ins->sreg1 = sp [1]->dreg;
12776                                 ins->backend.memory_barrier_kind = (int) read32 (ip + 2);
12777                                 MONO_ADD_INS (cfg->cbb, ins);
12778
12779                                 ip += 6;
12780                                 break;
12781                         }
12782                         case CEE_MONO_JIT_ATTACH: {
12783                                 MonoInst *args [16], *domain_ins;
12784                                 MonoInst *ad_ins, *jit_tls_ins;
12785                                 MonoBasicBlock *next_bb = NULL, *call_bb = NULL;
12786
12787                                 g_assert (!mono_threads_is_coop_enabled ());
12788
12789                                 cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12790
12791                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12792                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12793
12794                                 ad_ins = mono_get_domain_intrinsic (cfg);
12795                                 jit_tls_ins = mono_get_jit_tls_intrinsic (cfg);
12796
12797                                 if (cfg->backend->have_tls_get && ad_ins && jit_tls_ins) {
12798                                         NEW_BBLOCK (cfg, next_bb);
12799                                         NEW_BBLOCK (cfg, call_bb);
12800
12801                                         if (cfg->compile_aot) {
12802                                                 /* AOT code is only used in the root domain */
12803                                                 EMIT_NEW_PCONST (cfg, domain_ins, NULL);
12804                                         } else {
12805                                                 EMIT_NEW_PCONST (cfg, domain_ins, cfg->domain);
12806                                         }
12807                                         MONO_ADD_INS (cfg->cbb, ad_ins);
12808                                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, ad_ins->dreg, domain_ins->dreg);
12809                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, call_bb);
12810
12811                                         MONO_ADD_INS (cfg->cbb, jit_tls_ins);
12812                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, jit_tls_ins->dreg, 0);
12813                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, call_bb);
12814
12815                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, next_bb);
12816                                         MONO_START_BB (cfg, call_bb);
12817                                 }
12818
12819                                 /* AOT code is only used in the root domain */
12820                                 EMIT_NEW_PCONST (cfg, args [0], cfg->compile_aot ? NULL : cfg->domain);
12821                                 ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
12822                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12823
12824                                 if (next_bb)
12825                                         MONO_START_BB (cfg, next_bb);
12826
12827
12828                                 ip += 2;
12829                                 break;
12830                         }
12831                         case CEE_MONO_JIT_DETACH: {
12832                                 MonoInst *args [16];
12833
12834                                 /* Restore the original domain */
12835                                 dreg = alloc_ireg (cfg);
12836                                 EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->orig_domain_var->dreg);
12837                                 mono_emit_jit_icall (cfg, mono_jit_set_domain, args);
12838                                 ip += 2;
12839                                 break;
12840                         }
12841                         case CEE_MONO_CALLI_EXTRA_ARG: {
12842                                 MonoInst *addr;
12843                                 MonoMethodSignature *fsig;
12844                                 MonoInst *arg;
12845
12846                                 /*
12847                                  * This is the same as CEE_CALLI, but passes an additional argument
12848                                  * to the called method in llvmonly mode.
12849                                  * This is only used by delegate invoke wrappers to call the
12850                                  * actual delegate method.
12851                                  */
12852                                 g_assert (method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE);
12853
12854                                 CHECK_OPSIZE (6);
12855                                 token = read32 (ip + 2);
12856
12857                                 ins = NULL;
12858
12859                                 cmethod = NULL;
12860                                 CHECK_STACK (1);
12861                                 --sp;
12862                                 addr = *sp;
12863                                 fsig = mini_get_signature (method, token, generic_context, &cfg->error);
12864                                 CHECK_CFG_ERROR;
12865
12866                                 if (cfg->llvm_only)
12867                                         cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, fsig);
12868
12869                                 n = fsig->param_count + fsig->hasthis + 1;
12870
12871                                 CHECK_STACK (n);
12872
12873                                 sp -= n;
12874                                 arg = sp [n - 1];
12875
12876                                 if (cfg->llvm_only) {
12877                                         /*
12878                                          * The lowest bit of 'arg' determines whenever the callee uses the gsharedvt
12879                                          * cconv. This is set by mono_init_delegate ().
12880                                          */
12881                                         if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig)) {
12882                                                 MonoInst *callee = addr;
12883                                                 MonoInst *call, *localloc_ins;
12884                                                 MonoBasicBlock *is_gsharedvt_bb, *end_bb;
12885                                                 int low_bit_reg = alloc_preg (cfg);
12886
12887                                                 NEW_BBLOCK (cfg, is_gsharedvt_bb);
12888                                                 NEW_BBLOCK (cfg, end_bb);
12889
12890                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, low_bit_reg, arg->dreg, 1);
12891                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_bit_reg, 0);
12892                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_gsharedvt_bb);
12893
12894                                                 /* Normal case: callee uses a normal cconv, have to add an out wrapper */
12895                                                 addr = emit_get_rgctx_sig (cfg, context_used,
12896                                                                                                    fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
12897                                                 /*
12898                                                  * ADDR points to a gsharedvt-out wrapper, have to pass <callee, arg> as an extra arg.
12899                                                  */
12900                                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
12901                                                 ins->dreg = alloc_preg (cfg);
12902                                                 ins->inst_imm = 2 * SIZEOF_VOID_P;
12903                                                 MONO_ADD_INS (cfg->cbb, ins);
12904                                                 localloc_ins = ins;
12905                                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12906                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, 0, callee->dreg);
12907                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, SIZEOF_VOID_P, arg->dreg);
12908
12909                                                 call = emit_extra_arg_calli (cfg, fsig, sp, localloc_ins->dreg, addr);
12910                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12911
12912                                                 /* Gsharedvt case: callee uses a gsharedvt cconv, no conversion is needed */
12913                                                 MONO_START_BB (cfg, is_gsharedvt_bb);
12914                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PXOR_IMM, arg->dreg, arg->dreg, 1);
12915                                                 ins = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
12916                                                 ins->dreg = call->dreg;
12917
12918                                                 MONO_START_BB (cfg, end_bb);
12919                                         } else {
12920                                                 /* Caller uses a normal calling conv */
12921
12922                                                 MonoInst *callee = addr;
12923                                                 MonoInst *call, *localloc_ins;
12924                                                 MonoBasicBlock *is_gsharedvt_bb, *end_bb;
12925                                                 int low_bit_reg = alloc_preg (cfg);
12926
12927                                                 NEW_BBLOCK (cfg, is_gsharedvt_bb);
12928                                                 NEW_BBLOCK (cfg, end_bb);
12929
12930                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, low_bit_reg, arg->dreg, 1);
12931                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_bit_reg, 0);
12932                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_gsharedvt_bb);
12933
12934                                                 /* Normal case: callee uses a normal cconv, no conversion is needed */
12935                                                 call = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
12936                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12937                                                 /* Gsharedvt case: callee uses a gsharedvt cconv, have to add an in wrapper */
12938                                                 MONO_START_BB (cfg, is_gsharedvt_bb);
12939                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PXOR_IMM, arg->dreg, arg->dreg, 1);
12940                                                 NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER, fsig);
12941                                                 MONO_ADD_INS (cfg->cbb, addr);
12942                                                 /*
12943                                                  * ADDR points to a gsharedvt-in wrapper, have to pass <callee, arg> as an extra arg.
12944                                                  */
12945                                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
12946                                                 ins->dreg = alloc_preg (cfg);
12947                                                 ins->inst_imm = 2 * SIZEOF_VOID_P;
12948                                                 MONO_ADD_INS (cfg->cbb, ins);
12949                                                 localloc_ins = ins;
12950                                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12951                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, 0, callee->dreg);
12952                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, SIZEOF_VOID_P, arg->dreg);
12953
12954                                                 ins = emit_extra_arg_calli (cfg, fsig, sp, localloc_ins->dreg, addr);
12955                                                 ins->dreg = call->dreg;
12956                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12957
12958                                                 MONO_START_BB (cfg, end_bb);
12959                                         }
12960                                 } else {
12961                                         /* Same as CEE_CALLI */
12962                                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
12963                                                 /*
12964                                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
12965                                                  */
12966                                                 MonoInst *callee = addr;
12967
12968                                                 addr = emit_get_rgctx_sig (cfg, context_used,
12969                                                                                                    fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
12970                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
12971                                         } else {
12972                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
12973                                         }
12974                                 }
12975
12976                                 if (!MONO_TYPE_IS_VOID (fsig->ret))
12977                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
12978
12979                                 CHECK_CFG_EXCEPTION;
12980
12981                                 ip += 6;
12982                                 ins_flag = 0;
12983                                 constrained_class = NULL;
12984                                 break;
12985                         }
12986                         case CEE_MONO_LDDOMAIN:
12987                                 CHECK_STACK_OVF (1);
12988                                 EMIT_NEW_PCONST (cfg, ins, cfg->compile_aot ? NULL : cfg->domain);
12989                                 ip += 2;
12990                                 *sp++ = ins;
12991                                 break;
12992                         case CEE_MONO_GET_LAST_ERROR:
12993                                 CHECK_OPSIZE (2);
12994                                 CHECK_STACK_OVF (1);
12995
12996                                 MONO_INST_NEW (cfg, ins, OP_GET_LAST_ERROR);
12997                                 ins->dreg = alloc_dreg (cfg, STACK_I4);
12998                                 ins->type = STACK_I4;
12999                                 MONO_ADD_INS (cfg->cbb, ins);
13000
13001                                 ip += 2;
13002                                 *sp++ = ins;
13003                                 break;
13004                         default:
13005                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
13006                                 break;
13007                         }
13008                         break;
13009                 }
13010
13011                 case CEE_PREFIX1: {
13012                         CHECK_OPSIZE (2);
13013                         switch (ip [1]) {
13014                         case CEE_ARGLIST: {
13015                                 /* somewhat similar to LDTOKEN */
13016                                 MonoInst *addr, *vtvar;
13017                                 CHECK_STACK_OVF (1);
13018                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
13019
13020                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
13021                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
13022
13023                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
13024                                 ins->type = STACK_VTYPE;
13025                                 ins->klass = mono_defaults.argumenthandle_class;
13026                                 *sp++ = ins;
13027                                 ip += 2;
13028                                 break;
13029                         }
13030                         case CEE_CEQ:
13031                         case CEE_CGT:
13032                         case CEE_CGT_UN:
13033                         case CEE_CLT:
13034                         case CEE_CLT_UN: {
13035                                 MonoInst *cmp, *arg1, *arg2;
13036
13037                                 CHECK_STACK (2);
13038                                 sp -= 2;
13039                                 arg1 = sp [0];
13040                                 arg2 = sp [1];
13041
13042                                 /*
13043                                  * The following transforms:
13044                                  *    CEE_CEQ    into OP_CEQ
13045                                  *    CEE_CGT    into OP_CGT
13046                                  *    CEE_CGT_UN into OP_CGT_UN
13047                                  *    CEE_CLT    into OP_CLT
13048                                  *    CEE_CLT_UN into OP_CLT_UN
13049                                  */
13050                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
13051
13052                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
13053                                 cmp->sreg1 = arg1->dreg;
13054                                 cmp->sreg2 = arg2->dreg;
13055                                 type_from_op (cfg, cmp, arg1, arg2);
13056                                 CHECK_TYPE (cmp);
13057                                 add_widen_op (cfg, cmp, &arg1, &arg2);
13058                                 if ((arg1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((arg1->type == STACK_PTR) || (arg1->type == STACK_OBJ) || (arg1->type == STACK_MP))))
13059                                         cmp->opcode = OP_LCOMPARE;
13060                                 else if (arg1->type == STACK_R4)
13061                                         cmp->opcode = OP_RCOMPARE;
13062                                 else if (arg1->type == STACK_R8)
13063                                         cmp->opcode = OP_FCOMPARE;
13064                                 else
13065                                         cmp->opcode = OP_ICOMPARE;
13066                                 MONO_ADD_INS (cfg->cbb, cmp);
13067                                 ins->type = STACK_I4;
13068                                 ins->dreg = alloc_dreg (cfg, (MonoStackType)ins->type);
13069                                 type_from_op (cfg, ins, arg1, arg2);
13070
13071                                 if (cmp->opcode == OP_FCOMPARE || cmp->opcode == OP_RCOMPARE) {
13072                                         /*
13073                                          * The backends expect the fceq opcodes to do the
13074                                          * comparison too.
13075                                          */
13076                                         ins->sreg1 = cmp->sreg1;
13077                                         ins->sreg2 = cmp->sreg2;
13078                                         NULLIFY_INS (cmp);
13079                                 }
13080                                 MONO_ADD_INS (cfg->cbb, ins);
13081                                 *sp++ = ins;
13082                                 ip += 2;
13083                                 break;
13084                         }
13085                         case CEE_LDFTN: {
13086                                 MonoInst *argconst;
13087                                 MonoMethod *cil_method;
13088
13089                                 CHECK_STACK_OVF (1);
13090                                 CHECK_OPSIZE (6);
13091                                 n = read32 (ip + 2);
13092                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
13093                                 CHECK_CFG_ERROR;
13094
13095                                 mono_class_init (cmethod->klass);
13096
13097                                 mono_save_token_info (cfg, image, n, cmethod);
13098
13099                                 context_used = mini_method_check_context_used (cfg, cmethod);
13100
13101                                 cil_method = cmethod;
13102                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
13103                                         emit_method_access_failure (cfg, method, cil_method);
13104
13105                                 if (mono_security_core_clr_enabled ())
13106                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
13107
13108                                 /* 
13109                                  * Optimize the common case of ldftn+delegate creation
13110                                  */
13111                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
13112                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
13113                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
13114                                                 MonoInst *target_ins, *handle_ins;
13115                                                 MonoMethod *invoke;
13116                                                 int invoke_context_used;
13117
13118                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
13119                                                 if (!invoke || !mono_method_signature (invoke))
13120                                                         LOAD_ERROR;
13121
13122                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
13123
13124                                                 target_ins = sp [-1];
13125
13126                                                 if (mono_security_core_clr_enabled ())
13127                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
13128
13129                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
13130                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
13131                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
13132                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
13133                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
13134                                                         }
13135                                                 }
13136
13137                                                 /* FIXME: SGEN support */
13138                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
13139                                                         ip += 6;
13140                                                         if (cfg->verbose_level > 3)
13141                                                                 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));
13142                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, FALSE))) {
13143                                                                 sp --;
13144                                                                 *sp = handle_ins;
13145                                                                 CHECK_CFG_EXCEPTION;
13146                                                                 ip += 5;
13147                                                                 sp ++;
13148                                                                 break;
13149                                                         }
13150                                                         ip -= 6;
13151                                                 }
13152                                         }
13153                                 }
13154
13155                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
13156                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
13157                                 *sp++ = ins;
13158                                 
13159                                 ip += 6;
13160                                 inline_costs += 10 * num_calls++;
13161                                 break;
13162                         }
13163                         case CEE_LDVIRTFTN: {
13164                                 MonoInst *args [2];
13165
13166                                 CHECK_STACK (1);
13167                                 CHECK_OPSIZE (6);
13168                                 n = read32 (ip + 2);
13169                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
13170                                 CHECK_CFG_ERROR;
13171
13172                                 mono_class_init (cmethod->klass);
13173  
13174                                 context_used = mini_method_check_context_used (cfg, cmethod);
13175
13176                                 if (mono_security_core_clr_enabled ())
13177                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
13178
13179                                 /*
13180                                  * Optimize the common case of ldvirtftn+delegate creation
13181                                  */
13182                                 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)) {
13183                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
13184                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
13185                                                 MonoInst *target_ins, *handle_ins;
13186                                                 MonoMethod *invoke;
13187                                                 int invoke_context_used;
13188                                                 gboolean is_virtual = cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL;
13189
13190                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
13191                                                 if (!invoke || !mono_method_signature (invoke))
13192                                                         LOAD_ERROR;
13193
13194                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
13195
13196                                                 target_ins = sp [-1];
13197
13198                                                 if (mono_security_core_clr_enabled ())
13199                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
13200
13201                                                 /* FIXME: SGEN support */
13202                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
13203                                                         ip += 6;
13204                                                         if (cfg->verbose_level > 3)
13205                                                                 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));
13206                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, is_virtual))) {
13207                                                                 sp -= 2;
13208                                                                 *sp = handle_ins;
13209                                                                 CHECK_CFG_EXCEPTION;
13210                                                                 ip += 5;
13211                                                                 sp ++;
13212                                                                 break;
13213                                                         }
13214                                                         ip -= 6;
13215                                                 }
13216                                         }
13217                                 }
13218
13219                                 --sp;
13220                                 args [0] = *sp;
13221
13222                                 args [1] = emit_get_rgctx_method (cfg, context_used,
13223                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
13224
13225                                 if (context_used)
13226                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
13227                                 else
13228                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
13229
13230                                 ip += 6;
13231                                 inline_costs += 10 * num_calls++;
13232                                 break;
13233                         }
13234                         case CEE_LDARG:
13235                                 CHECK_STACK_OVF (1);
13236                                 CHECK_OPSIZE (4);
13237                                 n = read16 (ip + 2);
13238                                 CHECK_ARG (n);
13239                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
13240                                 *sp++ = ins;
13241                                 ip += 4;
13242                                 break;
13243                         case CEE_LDARGA:
13244                                 CHECK_STACK_OVF (1);
13245                                 CHECK_OPSIZE (4);
13246                                 n = read16 (ip + 2);
13247                                 CHECK_ARG (n);
13248                                 NEW_ARGLOADA (cfg, ins, n);
13249                                 MONO_ADD_INS (cfg->cbb, ins);
13250                                 *sp++ = ins;
13251                                 ip += 4;
13252                                 break;
13253                         case CEE_STARG:
13254                                 CHECK_STACK (1);
13255                                 --sp;
13256                                 CHECK_OPSIZE (4);
13257                                 n = read16 (ip + 2);
13258                                 CHECK_ARG (n);
13259                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
13260                                         UNVERIFIED;
13261                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
13262                                 ip += 4;
13263                                 break;
13264                         case CEE_LDLOC:
13265                                 CHECK_STACK_OVF (1);
13266                                 CHECK_OPSIZE (4);
13267                                 n = read16 (ip + 2);
13268                                 CHECK_LOCAL (n);
13269                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
13270                                 *sp++ = ins;
13271                                 ip += 4;
13272                                 break;
13273                         case CEE_LDLOCA: {
13274                                 unsigned char *tmp_ip;
13275                                 CHECK_STACK_OVF (1);
13276                                 CHECK_OPSIZE (4);
13277                                 n = read16 (ip + 2);
13278                                 CHECK_LOCAL (n);
13279
13280                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
13281                                         ip = tmp_ip;
13282                                         inline_costs += 1;
13283                                         break;
13284                                 }                       
13285                                 
13286                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
13287                                 *sp++ = ins;
13288                                 ip += 4;
13289                                 break;
13290                         }
13291                         case CEE_STLOC:
13292                                 CHECK_STACK (1);
13293                                 --sp;
13294                                 CHECK_OPSIZE (4);
13295                                 n = read16 (ip + 2);
13296                                 CHECK_LOCAL (n);
13297                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
13298                                         UNVERIFIED;
13299                                 emit_stloc_ir (cfg, sp, header, n);
13300                                 ip += 4;
13301                                 inline_costs += 1;
13302                                 break;
13303                         case CEE_LOCALLOC: {
13304                                 CHECK_STACK (1);
13305                                 MonoBasicBlock *non_zero_bb, *end_bb;
13306                                 int alloc_ptr = alloc_preg (cfg);
13307                                 --sp;
13308                                 if (sp != stack_start) 
13309                                         UNVERIFIED;
13310                                 if (cfg->method != method) 
13311                                         /* 
13312                                          * Inlining this into a loop in a parent could lead to 
13313                                          * stack overflows which is different behavior than the
13314                                          * non-inlined case, thus disable inlining in this case.
13315                                          */
13316                                         INLINE_FAILURE("localloc");
13317
13318                                 NEW_BBLOCK (cfg, non_zero_bb);
13319                                 NEW_BBLOCK (cfg, end_bb);
13320
13321                                 /* if size != zero */
13322                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
13323                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, non_zero_bb);
13324
13325                                 //size is zero, so result is NULL
13326                                 MONO_EMIT_NEW_PCONST (cfg, alloc_ptr, NULL);
13327                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
13328
13329                                 MONO_START_BB (cfg, non_zero_bb);
13330                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
13331                                 ins->dreg = alloc_ptr;
13332                                 ins->sreg1 = sp [0]->dreg;
13333                                 ins->type = STACK_PTR;
13334                                 MONO_ADD_INS (cfg->cbb, ins);
13335
13336                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
13337                                 if (init_locals)
13338                                         ins->flags |= MONO_INST_INIT;
13339
13340                                 MONO_START_BB (cfg, end_bb);
13341                                 EMIT_NEW_UNALU (cfg, ins, OP_MOVE, alloc_preg (cfg), alloc_ptr);
13342                                 ins->type = STACK_PTR;
13343
13344                                 *sp++ = ins;
13345                                 ip += 2;
13346                                 break;
13347                         }
13348                         case CEE_ENDFILTER: {
13349                                 MonoExceptionClause *clause, *nearest;
13350                                 int cc;
13351
13352                                 CHECK_STACK (1);
13353                                 --sp;
13354                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
13355                                         UNVERIFIED;
13356                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
13357                                 ins->sreg1 = (*sp)->dreg;
13358                                 MONO_ADD_INS (cfg->cbb, ins);
13359                                 start_new_bblock = 1;
13360                                 ip += 2;
13361
13362                                 nearest = NULL;
13363                                 for (cc = 0; cc < header->num_clauses; ++cc) {
13364                                         clause = &header->clauses [cc];
13365                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
13366                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
13367                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset)))
13368                                                 nearest = clause;
13369                                 }
13370                                 g_assert (nearest);
13371                                 if ((ip - header->code) != nearest->handler_offset)
13372                                         UNVERIFIED;
13373
13374                                 break;
13375                         }
13376                         case CEE_UNALIGNED_:
13377                                 ins_flag |= MONO_INST_UNALIGNED;
13378                                 /* FIXME: record alignment? we can assume 1 for now */
13379                                 CHECK_OPSIZE (3);
13380                                 ip += 3;
13381                                 break;
13382                         case CEE_VOLATILE_:
13383                                 ins_flag |= MONO_INST_VOLATILE;
13384                                 ip += 2;
13385                                 break;
13386                         case CEE_TAIL_:
13387                                 ins_flag   |= MONO_INST_TAILCALL;
13388                                 cfg->flags |= MONO_CFG_HAS_TAIL;
13389                                 /* Can't inline tail calls at this time */
13390                                 inline_costs += 100000;
13391                                 ip += 2;
13392                                 break;
13393                         case CEE_INITOBJ:
13394                                 CHECK_STACK (1);
13395                                 --sp;
13396                                 CHECK_OPSIZE (6);
13397                                 token = read32 (ip + 2);
13398                                 klass = mini_get_class (method, token, generic_context);
13399                                 CHECK_TYPELOAD (klass);
13400                                 if (generic_class_is_reference_type (cfg, klass))
13401                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
13402                                 else
13403                                         mini_emit_initobj (cfg, *sp, NULL, klass);
13404                                 ip += 6;
13405                                 inline_costs += 1;
13406                                 break;
13407                         case CEE_CONSTRAINED_:
13408                                 CHECK_OPSIZE (6);
13409                                 token = read32 (ip + 2);
13410                                 constrained_class = mini_get_class (method, token, generic_context);
13411                                 CHECK_TYPELOAD (constrained_class);
13412                                 ip += 6;
13413                                 break;
13414                         case CEE_CPBLK:
13415                         case CEE_INITBLK: {
13416                                 MonoInst *iargs [3];
13417                                 CHECK_STACK (3);
13418                                 sp -= 3;
13419
13420                                 /* Skip optimized paths for volatile operations. */
13421                                 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)) {
13422                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
13423                                 } 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)) {
13424                                         /* emit_memset only works when val == 0 */
13425                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
13426                                 } else {
13427                                         MonoInst *call;
13428                                         iargs [0] = sp [0];
13429                                         iargs [1] = sp [1];
13430                                         iargs [2] = sp [2];
13431                                         if (ip [1] == CEE_CPBLK) {
13432                                                 /*
13433                                                  * FIXME: It's unclear whether we should be emitting both the acquire
13434                                                  * and release barriers for cpblk. It is technically both a load and
13435                                                  * store operation, so it seems like that's the sensible thing to do.
13436                                                  *
13437                                                  * FIXME: We emit full barriers on both sides of the operation for
13438                                                  * simplicity. We should have a separate atomic memcpy method instead.
13439                                                  */
13440                                                 MonoMethod *memcpy_method = get_memcpy_method ();
13441
13442                                                 if (ins_flag & MONO_INST_VOLATILE)
13443                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
13444
13445                                                 call = mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
13446                                                 call->flags |= ins_flag;
13447
13448                                                 if (ins_flag & MONO_INST_VOLATILE)
13449                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
13450                                         } else {
13451                                                 MonoMethod *memset_method = get_memset_method ();
13452                                                 if (ins_flag & MONO_INST_VOLATILE) {
13453                                                         /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
13454                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
13455                                                 }
13456                                                 call = mono_emit_method_call (cfg, memset_method, iargs, NULL);
13457                                                 call->flags |= ins_flag;
13458                                         }
13459                                 }
13460                                 ip += 2;
13461                                 ins_flag = 0;
13462                                 inline_costs += 1;
13463                                 break;
13464                         }
13465                         case CEE_NO_:
13466                                 CHECK_OPSIZE (3);
13467                                 if (ip [2] & 0x1)
13468                                         ins_flag |= MONO_INST_NOTYPECHECK;
13469                                 if (ip [2] & 0x2)
13470                                         ins_flag |= MONO_INST_NORANGECHECK;
13471                                 /* we ignore the no-nullcheck for now since we
13472                                  * really do it explicitly only when doing callvirt->call
13473                                  */
13474                                 ip += 3;
13475                                 break;
13476                         case CEE_RETHROW: {
13477                                 MonoInst *load;
13478                                 int handler_offset = -1;
13479
13480                                 for (i = 0; i < header->num_clauses; ++i) {
13481                                         MonoExceptionClause *clause = &header->clauses [i];
13482                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
13483                                                 handler_offset = clause->handler_offset;
13484                                                 break;
13485                                         }
13486                                 }
13487
13488                                 cfg->cbb->flags |= BB_EXCEPTION_UNSAFE;
13489
13490                                 if (handler_offset == -1)
13491                                         UNVERIFIED;
13492
13493                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
13494                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
13495                                 ins->sreg1 = load->dreg;
13496                                 MONO_ADD_INS (cfg->cbb, ins);
13497
13498                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
13499                                 MONO_ADD_INS (cfg->cbb, ins);
13500
13501                                 sp = stack_start;
13502                                 link_bblock (cfg, cfg->cbb, end_bblock);
13503                                 start_new_bblock = 1;
13504                                 ip += 2;
13505                                 break;
13506                         }
13507                         case CEE_SIZEOF: {
13508                                 guint32 val;
13509                                 int ialign;
13510
13511                                 CHECK_STACK_OVF (1);
13512                                 CHECK_OPSIZE (6);
13513                                 token = read32 (ip + 2);
13514                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !image_is_dynamic (method->klass->image) && !generic_context) {
13515                                         MonoType *type = mono_type_create_from_typespec_checked (image, token, &cfg->error);
13516                                         CHECK_CFG_ERROR;
13517
13518                                         val = mono_type_size (type, &ialign);
13519                                 } else {
13520                                         MonoClass *klass = mini_get_class (method, token, generic_context);
13521                                         CHECK_TYPELOAD (klass);
13522
13523                                         val = mono_type_size (&klass->byval_arg, &ialign);
13524
13525                                         if (mini_is_gsharedvt_klass (klass))
13526                                                 GSHAREDVT_FAILURE (*ip);
13527                                 }
13528                                 EMIT_NEW_ICONST (cfg, ins, val);
13529                                 *sp++= ins;
13530                                 ip += 6;
13531                                 break;
13532                         }
13533                         case CEE_REFANYTYPE: {
13534                                 MonoInst *src_var, *src;
13535
13536                                 GSHAREDVT_FAILURE (*ip);
13537
13538                                 CHECK_STACK (1);
13539                                 --sp;
13540
13541                                 // FIXME:
13542                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
13543                                 if (!src_var)
13544                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
13545                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
13546                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type));
13547                                 *sp++ = ins;
13548                                 ip += 2;
13549                                 break;
13550                         }
13551                         case CEE_READONLY_:
13552                                 readonly = TRUE;
13553                                 ip += 2;
13554                                 break;
13555
13556                         case CEE_UNUSED56:
13557                         case CEE_UNUSED57:
13558                         case CEE_UNUSED70:
13559                         case CEE_UNUSED:
13560                         case CEE_UNUSED99:
13561                                 UNVERIFIED;
13562                                 
13563                         default:
13564                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
13565                                 UNVERIFIED;
13566                         }
13567                         break;
13568                 }
13569                 case CEE_UNUSED58:
13570                 case CEE_UNUSED1:
13571                         UNVERIFIED;
13572
13573                 default:
13574                         g_warning ("opcode 0x%02x not handled", *ip);
13575                         UNVERIFIED;
13576                 }
13577         }
13578         if (start_new_bblock != 1)
13579                 UNVERIFIED;
13580
13581         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
13582         if (cfg->cbb->next_bb) {
13583                 /* This could already be set because of inlining, #693905 */
13584                 MonoBasicBlock *bb = cfg->cbb;
13585
13586                 while (bb->next_bb)
13587                         bb = bb->next_bb;
13588                 bb->next_bb = end_bblock;
13589         } else {
13590                 cfg->cbb->next_bb = end_bblock;
13591         }
13592
13593         if (cfg->method == method && cfg->domainvar) {
13594                 MonoInst *store;
13595                 MonoInst *get_domain;
13596
13597                 cfg->cbb = init_localsbb;
13598
13599                 if ((get_domain = mono_get_domain_intrinsic (cfg))) {
13600                         MONO_ADD_INS (cfg->cbb, get_domain);
13601                 } else {
13602                         get_domain = mono_emit_jit_icall (cfg, mono_domain_get, NULL);
13603                 }
13604                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
13605                 MONO_ADD_INS (cfg->cbb, store);
13606         }
13607
13608 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
13609         if (cfg->compile_aot)
13610                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
13611                 mono_get_got_var (cfg);
13612 #endif
13613
13614         if (cfg->method == method && cfg->got_var)
13615                 mono_emit_load_got_addr (cfg);
13616
13617         if (init_localsbb) {
13618                 cfg->cbb = init_localsbb;
13619                 cfg->ip = NULL;
13620                 for (i = 0; i < header->num_locals; ++i) {
13621                         emit_init_local (cfg, i, header->locals [i], init_locals);
13622                 }
13623         }
13624
13625         if (cfg->init_ref_vars && cfg->method == method) {
13626                 /* Emit initialization for ref vars */
13627                 // FIXME: Avoid duplication initialization for IL locals.
13628                 for (i = 0; i < cfg->num_varinfo; ++i) {
13629                         MonoInst *ins = cfg->varinfo [i];
13630
13631                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
13632                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
13633                 }
13634         }
13635
13636         if (cfg->lmf_var && cfg->method == method && !cfg->llvm_only) {
13637                 cfg->cbb = init_localsbb;
13638                 emit_push_lmf (cfg);
13639         }
13640
13641         cfg->cbb = init_localsbb;
13642         emit_instrumentation_call (cfg, mono_profiler_method_enter);
13643
13644         if (seq_points) {
13645                 MonoBasicBlock *bb;
13646
13647                 /*
13648                  * Make seq points at backward branch targets interruptable.
13649                  */
13650                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
13651                         if (bb->code && bb->in_count > 1 && bb->code->opcode == OP_SEQ_POINT)
13652                                 bb->code->flags |= MONO_INST_SINGLE_STEP_LOC;
13653         }
13654
13655         /* Add a sequence point for method entry/exit events */
13656         if (seq_points && cfg->gen_sdb_seq_points) {
13657                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
13658                 MONO_ADD_INS (init_localsbb, ins);
13659                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
13660                 MONO_ADD_INS (cfg->bb_exit, ins);
13661         }
13662
13663         /*
13664          * Add seq points for IL offsets which have line number info, but wasn't generated a seq point during JITting because
13665          * the code they refer to was dead (#11880).
13666          */
13667         if (sym_seq_points) {
13668                 for (i = 0; i < header->code_size; ++i) {
13669                         if (mono_bitset_test_fast (seq_point_locs, i) && !mono_bitset_test_fast (seq_point_set_locs, i)) {
13670                                 MonoInst *ins;
13671
13672                                 NEW_SEQ_POINT (cfg, ins, i, FALSE);
13673                                 mono_add_seq_point (cfg, NULL, ins, SEQ_POINT_NATIVE_OFFSET_DEAD_CODE);
13674                         }
13675                 }
13676         }
13677
13678         cfg->ip = NULL;
13679
13680         if (cfg->method == method) {
13681                 MonoBasicBlock *bb;
13682                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13683                         bb->region = mono_find_block_region (cfg, bb->real_offset);
13684                         if (cfg->spvars)
13685                                 mono_create_spvar_for_region (cfg, bb->region);
13686                         if (cfg->verbose_level > 2)
13687                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
13688                 }
13689         } else {
13690                 MonoBasicBlock *bb;
13691                 /* get_most_deep_clause () in mini-llvm.c depends on this for inlined bblocks */
13692                 for (bb = start_bblock; bb != end_bblock; bb  = bb->next_bb) {
13693                         bb->real_offset = inline_offset;
13694                 }
13695         }
13696
13697         if (inline_costs < 0) {
13698                 char *mname;
13699
13700                 /* Method is too large */
13701                 mname = mono_method_full_name (method, TRUE);
13702                 mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Method %s is too complex.", mname));
13703                 g_free (mname);
13704         }
13705
13706         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
13707                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
13708
13709         goto cleanup;
13710
13711 mono_error_exit:
13712         g_assert (!mono_error_ok (&cfg->error));
13713         goto cleanup;
13714  
13715  exception_exit:
13716         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
13717         goto cleanup;
13718
13719  unverified:
13720         set_exception_type_from_invalid_il (cfg, method, ip);
13721         goto cleanup;
13722
13723  cleanup:
13724         g_slist_free (class_inits);
13725         mono_basic_block_free (original_bb);
13726         cfg->dont_inline = g_list_remove (cfg->dont_inline, method);
13727         if (cfg->exception_type)
13728                 return -1;
13729         else
13730                 return inline_costs;
13731 }
13732
13733 static int
13734 store_membase_reg_to_store_membase_imm (int opcode)
13735 {
13736         switch (opcode) {
13737         case OP_STORE_MEMBASE_REG:
13738                 return OP_STORE_MEMBASE_IMM;
13739         case OP_STOREI1_MEMBASE_REG:
13740                 return OP_STOREI1_MEMBASE_IMM;
13741         case OP_STOREI2_MEMBASE_REG:
13742                 return OP_STOREI2_MEMBASE_IMM;
13743         case OP_STOREI4_MEMBASE_REG:
13744                 return OP_STOREI4_MEMBASE_IMM;
13745         case OP_STOREI8_MEMBASE_REG:
13746                 return OP_STOREI8_MEMBASE_IMM;
13747         default:
13748                 g_assert_not_reached ();
13749         }
13750
13751         return -1;
13752 }               
13753
13754 int
13755 mono_op_to_op_imm (int opcode)
13756 {
13757         switch (opcode) {
13758         case OP_IADD:
13759                 return OP_IADD_IMM;
13760         case OP_ISUB:
13761                 return OP_ISUB_IMM;
13762         case OP_IDIV:
13763                 return OP_IDIV_IMM;
13764         case OP_IDIV_UN:
13765                 return OP_IDIV_UN_IMM;
13766         case OP_IREM:
13767                 return OP_IREM_IMM;
13768         case OP_IREM_UN:
13769                 return OP_IREM_UN_IMM;
13770         case OP_IMUL:
13771                 return OP_IMUL_IMM;
13772         case OP_IAND:
13773                 return OP_IAND_IMM;
13774         case OP_IOR:
13775                 return OP_IOR_IMM;
13776         case OP_IXOR:
13777                 return OP_IXOR_IMM;
13778         case OP_ISHL:
13779                 return OP_ISHL_IMM;
13780         case OP_ISHR:
13781                 return OP_ISHR_IMM;
13782         case OP_ISHR_UN:
13783                 return OP_ISHR_UN_IMM;
13784
13785         case OP_LADD:
13786                 return OP_LADD_IMM;
13787         case OP_LSUB:
13788                 return OP_LSUB_IMM;
13789         case OP_LAND:
13790                 return OP_LAND_IMM;
13791         case OP_LOR:
13792                 return OP_LOR_IMM;
13793         case OP_LXOR:
13794                 return OP_LXOR_IMM;
13795         case OP_LSHL:
13796                 return OP_LSHL_IMM;
13797         case OP_LSHR:
13798                 return OP_LSHR_IMM;
13799         case OP_LSHR_UN:
13800                 return OP_LSHR_UN_IMM;
13801 #if SIZEOF_REGISTER == 8
13802         case OP_LREM:
13803                 return OP_LREM_IMM;
13804 #endif
13805
13806         case OP_COMPARE:
13807                 return OP_COMPARE_IMM;
13808         case OP_ICOMPARE:
13809                 return OP_ICOMPARE_IMM;
13810         case OP_LCOMPARE:
13811                 return OP_LCOMPARE_IMM;
13812
13813         case OP_STORE_MEMBASE_REG:
13814                 return OP_STORE_MEMBASE_IMM;
13815         case OP_STOREI1_MEMBASE_REG:
13816                 return OP_STOREI1_MEMBASE_IMM;
13817         case OP_STOREI2_MEMBASE_REG:
13818                 return OP_STOREI2_MEMBASE_IMM;
13819         case OP_STOREI4_MEMBASE_REG:
13820                 return OP_STOREI4_MEMBASE_IMM;
13821
13822 #if defined(TARGET_X86) || defined (TARGET_AMD64)
13823         case OP_X86_PUSH:
13824                 return OP_X86_PUSH_IMM;
13825         case OP_X86_COMPARE_MEMBASE_REG:
13826                 return OP_X86_COMPARE_MEMBASE_IMM;
13827 #endif
13828 #if defined(TARGET_AMD64)
13829         case OP_AMD64_ICOMPARE_MEMBASE_REG:
13830                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13831 #endif
13832         case OP_VOIDCALL_REG:
13833                 return OP_VOIDCALL;
13834         case OP_CALL_REG:
13835                 return OP_CALL;
13836         case OP_LCALL_REG:
13837                 return OP_LCALL;
13838         case OP_FCALL_REG:
13839                 return OP_FCALL;
13840         case OP_LOCALLOC:
13841                 return OP_LOCALLOC_IMM;
13842         }
13843
13844         return -1;
13845 }
13846
13847 static int
13848 ldind_to_load_membase (int opcode)
13849 {
13850         switch (opcode) {
13851         case CEE_LDIND_I1:
13852                 return OP_LOADI1_MEMBASE;
13853         case CEE_LDIND_U1:
13854                 return OP_LOADU1_MEMBASE;
13855         case CEE_LDIND_I2:
13856                 return OP_LOADI2_MEMBASE;
13857         case CEE_LDIND_U2:
13858                 return OP_LOADU2_MEMBASE;
13859         case CEE_LDIND_I4:
13860                 return OP_LOADI4_MEMBASE;
13861         case CEE_LDIND_U4:
13862                 return OP_LOADU4_MEMBASE;
13863         case CEE_LDIND_I:
13864                 return OP_LOAD_MEMBASE;
13865         case CEE_LDIND_REF:
13866                 return OP_LOAD_MEMBASE;
13867         case CEE_LDIND_I8:
13868                 return OP_LOADI8_MEMBASE;
13869         case CEE_LDIND_R4:
13870                 return OP_LOADR4_MEMBASE;
13871         case CEE_LDIND_R8:
13872                 return OP_LOADR8_MEMBASE;
13873         default:
13874                 g_assert_not_reached ();
13875         }
13876
13877         return -1;
13878 }
13879
13880 static int
13881 stind_to_store_membase (int opcode)
13882 {
13883         switch (opcode) {
13884         case CEE_STIND_I1:
13885                 return OP_STOREI1_MEMBASE_REG;
13886         case CEE_STIND_I2:
13887                 return OP_STOREI2_MEMBASE_REG;
13888         case CEE_STIND_I4:
13889                 return OP_STOREI4_MEMBASE_REG;
13890         case CEE_STIND_I:
13891         case CEE_STIND_REF:
13892                 return OP_STORE_MEMBASE_REG;
13893         case CEE_STIND_I8:
13894                 return OP_STOREI8_MEMBASE_REG;
13895         case CEE_STIND_R4:
13896                 return OP_STORER4_MEMBASE_REG;
13897         case CEE_STIND_R8:
13898                 return OP_STORER8_MEMBASE_REG;
13899         default:
13900                 g_assert_not_reached ();
13901         }
13902
13903         return -1;
13904 }
13905
13906 int
13907 mono_load_membase_to_load_mem (int opcode)
13908 {
13909         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
13910 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13911         switch (opcode) {
13912         case OP_LOAD_MEMBASE:
13913                 return OP_LOAD_MEM;
13914         case OP_LOADU1_MEMBASE:
13915                 return OP_LOADU1_MEM;
13916         case OP_LOADU2_MEMBASE:
13917                 return OP_LOADU2_MEM;
13918         case OP_LOADI4_MEMBASE:
13919                 return OP_LOADI4_MEM;
13920         case OP_LOADU4_MEMBASE:
13921                 return OP_LOADU4_MEM;
13922 #if SIZEOF_REGISTER == 8
13923         case OP_LOADI8_MEMBASE:
13924                 return OP_LOADI8_MEM;
13925 #endif
13926         }
13927 #endif
13928
13929         return -1;
13930 }
13931
13932 static inline int
13933 op_to_op_dest_membase (int store_opcode, int opcode)
13934 {
13935 #if defined(TARGET_X86)
13936         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
13937                 return -1;
13938
13939         switch (opcode) {
13940         case OP_IADD:
13941                 return OP_X86_ADD_MEMBASE_REG;
13942         case OP_ISUB:
13943                 return OP_X86_SUB_MEMBASE_REG;
13944         case OP_IAND:
13945                 return OP_X86_AND_MEMBASE_REG;
13946         case OP_IOR:
13947                 return OP_X86_OR_MEMBASE_REG;
13948         case OP_IXOR:
13949                 return OP_X86_XOR_MEMBASE_REG;
13950         case OP_ADD_IMM:
13951         case OP_IADD_IMM:
13952                 return OP_X86_ADD_MEMBASE_IMM;
13953         case OP_SUB_IMM:
13954         case OP_ISUB_IMM:
13955                 return OP_X86_SUB_MEMBASE_IMM;
13956         case OP_AND_IMM:
13957         case OP_IAND_IMM:
13958                 return OP_X86_AND_MEMBASE_IMM;
13959         case OP_OR_IMM:
13960         case OP_IOR_IMM:
13961                 return OP_X86_OR_MEMBASE_IMM;
13962         case OP_XOR_IMM:
13963         case OP_IXOR_IMM:
13964                 return OP_X86_XOR_MEMBASE_IMM;
13965         case OP_MOVE:
13966                 return OP_NOP;
13967         }
13968 #endif
13969
13970 #if defined(TARGET_AMD64)
13971         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
13972                 return -1;
13973
13974         switch (opcode) {
13975         case OP_IADD:
13976                 return OP_X86_ADD_MEMBASE_REG;
13977         case OP_ISUB:
13978                 return OP_X86_SUB_MEMBASE_REG;
13979         case OP_IAND:
13980                 return OP_X86_AND_MEMBASE_REG;
13981         case OP_IOR:
13982                 return OP_X86_OR_MEMBASE_REG;
13983         case OP_IXOR:
13984                 return OP_X86_XOR_MEMBASE_REG;
13985         case OP_IADD_IMM:
13986                 return OP_X86_ADD_MEMBASE_IMM;
13987         case OP_ISUB_IMM:
13988                 return OP_X86_SUB_MEMBASE_IMM;
13989         case OP_IAND_IMM:
13990                 return OP_X86_AND_MEMBASE_IMM;
13991         case OP_IOR_IMM:
13992                 return OP_X86_OR_MEMBASE_IMM;
13993         case OP_IXOR_IMM:
13994                 return OP_X86_XOR_MEMBASE_IMM;
13995         case OP_LADD:
13996                 return OP_AMD64_ADD_MEMBASE_REG;
13997         case OP_LSUB:
13998                 return OP_AMD64_SUB_MEMBASE_REG;
13999         case OP_LAND:
14000                 return OP_AMD64_AND_MEMBASE_REG;
14001         case OP_LOR:
14002                 return OP_AMD64_OR_MEMBASE_REG;
14003         case OP_LXOR:
14004                 return OP_AMD64_XOR_MEMBASE_REG;
14005         case OP_ADD_IMM:
14006         case OP_LADD_IMM:
14007                 return OP_AMD64_ADD_MEMBASE_IMM;
14008         case OP_SUB_IMM:
14009         case OP_LSUB_IMM:
14010                 return OP_AMD64_SUB_MEMBASE_IMM;
14011         case OP_AND_IMM:
14012         case OP_LAND_IMM:
14013                 return OP_AMD64_AND_MEMBASE_IMM;
14014         case OP_OR_IMM:
14015         case OP_LOR_IMM:
14016                 return OP_AMD64_OR_MEMBASE_IMM;
14017         case OP_XOR_IMM:
14018         case OP_LXOR_IMM:
14019                 return OP_AMD64_XOR_MEMBASE_IMM;
14020         case OP_MOVE:
14021                 return OP_NOP;
14022         }
14023 #endif
14024
14025         return -1;
14026 }
14027
14028 static inline int
14029 op_to_op_store_membase (int store_opcode, int opcode)
14030 {
14031 #if defined(TARGET_X86) || defined(TARGET_AMD64)
14032         switch (opcode) {
14033         case OP_ICEQ:
14034                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
14035                         return OP_X86_SETEQ_MEMBASE;
14036         case OP_CNE:
14037                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
14038                         return OP_X86_SETNE_MEMBASE;
14039         }
14040 #endif
14041
14042         return -1;
14043 }
14044
14045 static inline int
14046 op_to_op_src1_membase (MonoCompile *cfg, int load_opcode, int opcode)
14047 {
14048 #ifdef TARGET_X86
14049         /* FIXME: This has sign extension issues */
14050         /*
14051         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
14052                 return OP_X86_COMPARE_MEMBASE8_IMM;
14053         */
14054
14055         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
14056                 return -1;
14057
14058         switch (opcode) {
14059         case OP_X86_PUSH:
14060                 return OP_X86_PUSH_MEMBASE;
14061         case OP_COMPARE_IMM:
14062         case OP_ICOMPARE_IMM:
14063                 return OP_X86_COMPARE_MEMBASE_IMM;
14064         case OP_COMPARE:
14065         case OP_ICOMPARE:
14066                 return OP_X86_COMPARE_MEMBASE_REG;
14067         }
14068 #endif
14069
14070 #ifdef TARGET_AMD64
14071         /* FIXME: This has sign extension issues */
14072         /*
14073         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
14074                 return OP_X86_COMPARE_MEMBASE8_IMM;
14075         */
14076
14077         switch (opcode) {
14078         case OP_X86_PUSH:
14079                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
14080                         return OP_X86_PUSH_MEMBASE;
14081                 break;
14082                 /* FIXME: This only works for 32 bit immediates
14083         case OP_COMPARE_IMM:
14084         case OP_LCOMPARE_IMM:
14085                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
14086                         return OP_AMD64_COMPARE_MEMBASE_IMM;
14087                 */
14088         case OP_ICOMPARE_IMM:
14089                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
14090                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
14091                 break;
14092         case OP_COMPARE:
14093         case OP_LCOMPARE:
14094                 if (cfg->backend->ilp32 && load_opcode == OP_LOAD_MEMBASE)
14095                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
14096                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
14097                         return OP_AMD64_COMPARE_MEMBASE_REG;
14098                 break;
14099         case OP_ICOMPARE:
14100                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
14101                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
14102                 break;
14103         }
14104 #endif
14105
14106         return -1;
14107 }
14108
14109 static inline int
14110 op_to_op_src2_membase (MonoCompile *cfg, int load_opcode, int opcode)
14111 {
14112 #ifdef TARGET_X86
14113         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
14114                 return -1;
14115         
14116         switch (opcode) {
14117         case OP_COMPARE:
14118         case OP_ICOMPARE:
14119                 return OP_X86_COMPARE_REG_MEMBASE;
14120         case OP_IADD:
14121                 return OP_X86_ADD_REG_MEMBASE;
14122         case OP_ISUB:
14123                 return OP_X86_SUB_REG_MEMBASE;
14124         case OP_IAND:
14125                 return OP_X86_AND_REG_MEMBASE;
14126         case OP_IOR:
14127                 return OP_X86_OR_REG_MEMBASE;
14128         case OP_IXOR:
14129                 return OP_X86_XOR_REG_MEMBASE;
14130         }
14131 #endif
14132
14133 #ifdef TARGET_AMD64
14134         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && cfg->backend->ilp32)) {
14135                 switch (opcode) {
14136                 case OP_ICOMPARE:
14137                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
14138                 case OP_IADD:
14139                         return OP_X86_ADD_REG_MEMBASE;
14140                 case OP_ISUB:
14141                         return OP_X86_SUB_REG_MEMBASE;
14142                 case OP_IAND:
14143                         return OP_X86_AND_REG_MEMBASE;
14144                 case OP_IOR:
14145                         return OP_X86_OR_REG_MEMBASE;
14146                 case OP_IXOR:
14147                         return OP_X86_XOR_REG_MEMBASE;
14148                 }
14149         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32)) {
14150                 switch (opcode) {
14151                 case OP_COMPARE:
14152                 case OP_LCOMPARE:
14153                         return OP_AMD64_COMPARE_REG_MEMBASE;
14154                 case OP_LADD:
14155                         return OP_AMD64_ADD_REG_MEMBASE;
14156                 case OP_LSUB:
14157                         return OP_AMD64_SUB_REG_MEMBASE;
14158                 case OP_LAND:
14159                         return OP_AMD64_AND_REG_MEMBASE;
14160                 case OP_LOR:
14161                         return OP_AMD64_OR_REG_MEMBASE;
14162                 case OP_LXOR:
14163                         return OP_AMD64_XOR_REG_MEMBASE;
14164                 }
14165         }
14166 #endif
14167
14168         return -1;
14169 }
14170
14171 int
14172 mono_op_to_op_imm_noemul (int opcode)
14173 {
14174         switch (opcode) {
14175 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
14176         case OP_LSHR:
14177         case OP_LSHL:
14178         case OP_LSHR_UN:
14179                 return -1;
14180 #endif
14181 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
14182         case OP_IDIV:
14183         case OP_IDIV_UN:
14184         case OP_IREM:
14185         case OP_IREM_UN:
14186                 return -1;
14187 #endif
14188 #if defined(MONO_ARCH_EMULATE_MUL_DIV)
14189         case OP_IMUL:
14190                 return -1;
14191 #endif
14192         default:
14193                 return mono_op_to_op_imm (opcode);
14194         }
14195 }
14196
14197 /**
14198  * mono_handle_global_vregs:
14199  *
14200  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
14201  * for them.
14202  */
14203 void
14204 mono_handle_global_vregs (MonoCompile *cfg)
14205 {
14206         gint32 *vreg_to_bb;
14207         MonoBasicBlock *bb;
14208         int i, pos;
14209
14210         vreg_to_bb = (gint32 *)mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
14211
14212 #ifdef MONO_ARCH_SIMD_INTRINSICS
14213         if (cfg->uses_simd_intrinsics)
14214                 mono_simd_simplify_indirection (cfg);
14215 #endif
14216
14217         /* Find local vregs used in more than one bb */
14218         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
14219                 MonoInst *ins = bb->code;       
14220                 int block_num = bb->block_num;
14221
14222                 if (cfg->verbose_level > 2)
14223                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
14224
14225                 cfg->cbb = bb;
14226                 for (; ins; ins = ins->next) {
14227                         const char *spec = INS_INFO (ins->opcode);
14228                         int regtype = 0, regindex;
14229                         gint32 prev_bb;
14230
14231                         if (G_UNLIKELY (cfg->verbose_level > 2))
14232                                 mono_print_ins (ins);
14233
14234                         g_assert (ins->opcode >= MONO_CEE_LAST);
14235
14236                         for (regindex = 0; regindex < 4; regindex ++) {
14237                                 int vreg = 0;
14238
14239                                 if (regindex == 0) {
14240                                         regtype = spec [MONO_INST_DEST];
14241                                         if (regtype == ' ')
14242                                                 continue;
14243                                         vreg = ins->dreg;
14244                                 } else if (regindex == 1) {
14245                                         regtype = spec [MONO_INST_SRC1];
14246                                         if (regtype == ' ')
14247                                                 continue;
14248                                         vreg = ins->sreg1;
14249                                 } else if (regindex == 2) {
14250                                         regtype = spec [MONO_INST_SRC2];
14251                                         if (regtype == ' ')
14252                                                 continue;
14253                                         vreg = ins->sreg2;
14254                                 } else if (regindex == 3) {
14255                                         regtype = spec [MONO_INST_SRC3];
14256                                         if (regtype == ' ')
14257                                                 continue;
14258                                         vreg = ins->sreg3;
14259                                 }
14260
14261 #if SIZEOF_REGISTER == 4
14262                                 /* In the LLVM case, the long opcodes are not decomposed */
14263                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
14264                                         /*
14265                                          * Since some instructions reference the original long vreg,
14266                                          * and some reference the two component vregs, it is quite hard
14267                                          * to determine when it needs to be global. So be conservative.
14268                                          */
14269                                         if (!get_vreg_to_inst (cfg, vreg)) {
14270                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
14271
14272                                                 if (cfg->verbose_level > 2)
14273                                                         printf ("LONG VREG R%d made global.\n", vreg);
14274                                         }
14275
14276                                         /*
14277                                          * Make the component vregs volatile since the optimizations can
14278                                          * get confused otherwise.
14279                                          */
14280                                         get_vreg_to_inst (cfg, MONO_LVREG_LS (vreg))->flags |= MONO_INST_VOLATILE;
14281                                         get_vreg_to_inst (cfg, MONO_LVREG_MS (vreg))->flags |= MONO_INST_VOLATILE;
14282                                 }
14283 #endif
14284
14285                                 g_assert (vreg != -1);
14286
14287                                 prev_bb = vreg_to_bb [vreg];
14288                                 if (prev_bb == 0) {
14289                                         /* 0 is a valid block num */
14290                                         vreg_to_bb [vreg] = block_num + 1;
14291                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
14292                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
14293                                                 continue;
14294
14295                                         if (!get_vreg_to_inst (cfg, vreg)) {
14296                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14297                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
14298
14299                                                 switch (regtype) {
14300                                                 case 'i':
14301                                                         if (vreg_is_ref (cfg, vreg))
14302                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg);
14303                                                         else
14304                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
14305                                                         break;
14306                                                 case 'l':
14307                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
14308                                                         break;
14309                                                 case 'f':
14310                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
14311                                                         break;
14312                                                 case 'v':
14313                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
14314                                                         break;
14315                                                 default:
14316                                                         g_assert_not_reached ();
14317                                                 }
14318                                         }
14319
14320                                         /* Flag as having been used in more than one bb */
14321                                         vreg_to_bb [vreg] = -1;
14322                                 }
14323                         }
14324                 }
14325         }
14326
14327         /* If a variable is used in only one bblock, convert it into a local vreg */
14328         for (i = 0; i < cfg->num_varinfo; i++) {
14329                 MonoInst *var = cfg->varinfo [i];
14330                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
14331
14332                 switch (var->type) {
14333                 case STACK_I4:
14334                 case STACK_OBJ:
14335                 case STACK_PTR:
14336                 case STACK_MP:
14337                 case STACK_VTYPE:
14338 #if SIZEOF_REGISTER == 8
14339                 case STACK_I8:
14340 #endif
14341 #if !defined(TARGET_X86)
14342                 /* Enabling this screws up the fp stack on x86 */
14343                 case STACK_R8:
14344 #endif
14345                         if (mono_arch_is_soft_float ())
14346                                 break;
14347
14348                         /*
14349                         if (var->type == STACK_VTYPE && cfg->gsharedvt && mini_is_gsharedvt_variable_type (var->inst_vtype))
14350                                 break;
14351                         */
14352
14353                         /* Arguments are implicitly global */
14354                         /* Putting R4 vars into registers doesn't work currently */
14355                         /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
14356                         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) {
14357                                 /* 
14358                                  * Make that the variable's liveness interval doesn't contain a call, since
14359                                  * that would cause the lvreg to be spilled, making the whole optimization
14360                                  * useless.
14361                                  */
14362                                 /* This is too slow for JIT compilation */
14363 #if 0
14364                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
14365                                         MonoInst *ins;
14366                                         int def_index, call_index, ins_index;
14367                                         gboolean spilled = FALSE;
14368
14369                                         def_index = -1;
14370                                         call_index = -1;
14371                                         ins_index = 0;
14372                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
14373                                                 const char *spec = INS_INFO (ins->opcode);
14374
14375                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
14376                                                         def_index = ins_index;
14377
14378                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
14379                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
14380                                                         if (call_index > def_index) {
14381                                                                 spilled = TRUE;
14382                                                                 break;
14383                                                         }
14384                                                 }
14385
14386                                                 if (MONO_IS_CALL (ins))
14387                                                         call_index = ins_index;
14388
14389                                                 ins_index ++;
14390                                         }
14391
14392                                         if (spilled)
14393                                                 break;
14394                                 }
14395 #endif
14396
14397                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14398                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
14399                                 var->flags |= MONO_INST_IS_DEAD;
14400                                 cfg->vreg_to_inst [var->dreg] = NULL;
14401                         }
14402                         break;
14403                 }
14404         }
14405
14406         /* 
14407          * Compress the varinfo and vars tables so the liveness computation is faster and
14408          * takes up less space.
14409          */
14410         pos = 0;
14411         for (i = 0; i < cfg->num_varinfo; ++i) {
14412                 MonoInst *var = cfg->varinfo [i];
14413                 if (pos < i && cfg->locals_start == i)
14414                         cfg->locals_start = pos;
14415                 if (!(var->flags & MONO_INST_IS_DEAD)) {
14416                         if (pos < i) {
14417                                 cfg->varinfo [pos] = cfg->varinfo [i];
14418                                 cfg->varinfo [pos]->inst_c0 = pos;
14419                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
14420                                 cfg->vars [pos].idx = pos;
14421 #if SIZEOF_REGISTER == 4
14422                                 if (cfg->varinfo [pos]->type == STACK_I8) {
14423                                         /* Modify the two component vars too */
14424                                         MonoInst *var1;
14425
14426                                         var1 = get_vreg_to_inst (cfg, MONO_LVREG_LS (cfg->varinfo [pos]->dreg));
14427                                         var1->inst_c0 = pos;
14428                                         var1 = get_vreg_to_inst (cfg, MONO_LVREG_MS (cfg->varinfo [pos]->dreg));
14429                                         var1->inst_c0 = pos;
14430                                 }
14431 #endif
14432                         }
14433                         pos ++;
14434                 }
14435         }
14436         cfg->num_varinfo = pos;
14437         if (cfg->locals_start > cfg->num_varinfo)
14438                 cfg->locals_start = cfg->num_varinfo;
14439 }
14440
14441 /*
14442  * mono_allocate_gsharedvt_vars:
14443  *
14444  *   Allocate variables with gsharedvt types to entries in the MonoGSharedVtMethodRuntimeInfo.entries array.
14445  * Initialize cfg->gsharedvt_vreg_to_idx with the mapping between vregs and indexes.
14446  */
14447 void
14448 mono_allocate_gsharedvt_vars (MonoCompile *cfg)
14449 {
14450         int i;
14451
14452         cfg->gsharedvt_vreg_to_idx = (int *)mono_mempool_alloc0 (cfg->mempool, sizeof (int) * cfg->next_vreg);
14453
14454         for (i = 0; i < cfg->num_varinfo; ++i) {
14455                 MonoInst *ins = cfg->varinfo [i];
14456                 int idx;
14457
14458                 if (mini_is_gsharedvt_variable_type (ins->inst_vtype)) {
14459                         if (i >= cfg->locals_start) {
14460                                 /* Local */
14461                                 idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
14462                                 cfg->gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
14463                                 ins->opcode = OP_GSHAREDVT_LOCAL;
14464                                 ins->inst_imm = idx;
14465                         } else {
14466                                 /* Arg */
14467                                 cfg->gsharedvt_vreg_to_idx [ins->dreg] = -1;
14468                                 ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
14469                         }
14470                 }
14471         }
14472 }
14473
14474 /**
14475  * mono_spill_global_vars:
14476  *
14477  *   Generate spill code for variables which are not allocated to registers, 
14478  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
14479  * code is generated which could be optimized by the local optimization passes.
14480  */
14481 void
14482 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
14483 {
14484         MonoBasicBlock *bb;
14485         char spec2 [16];
14486         int orig_next_vreg;
14487         guint32 *vreg_to_lvreg;
14488         guint32 *lvregs;
14489         guint32 i, lvregs_len;
14490         gboolean dest_has_lvreg = FALSE;
14491         MonoStackType stacktypes [128];
14492         MonoInst **live_range_start, **live_range_end;
14493         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
14494
14495         *need_local_opts = FALSE;
14496
14497         memset (spec2, 0, sizeof (spec2));
14498
14499         /* FIXME: Move this function to mini.c */
14500         stacktypes ['i'] = STACK_PTR;
14501         stacktypes ['l'] = STACK_I8;
14502         stacktypes ['f'] = STACK_R8;
14503 #ifdef MONO_ARCH_SIMD_INTRINSICS
14504         stacktypes ['x'] = STACK_VTYPE;
14505 #endif
14506
14507 #if SIZEOF_REGISTER == 4
14508         /* Create MonoInsts for longs */
14509         for (i = 0; i < cfg->num_varinfo; i++) {
14510                 MonoInst *ins = cfg->varinfo [i];
14511
14512                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
14513                         switch (ins->type) {
14514                         case STACK_R8:
14515                         case STACK_I8: {
14516                                 MonoInst *tree;
14517
14518                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
14519                                         break;
14520
14521                                 g_assert (ins->opcode == OP_REGOFFSET);
14522
14523                                 tree = get_vreg_to_inst (cfg, MONO_LVREG_LS (ins->dreg));
14524                                 g_assert (tree);
14525                                 tree->opcode = OP_REGOFFSET;
14526                                 tree->inst_basereg = ins->inst_basereg;
14527                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
14528
14529                                 tree = get_vreg_to_inst (cfg, MONO_LVREG_MS (ins->dreg));
14530                                 g_assert (tree);
14531                                 tree->opcode = OP_REGOFFSET;
14532                                 tree->inst_basereg = ins->inst_basereg;
14533                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
14534                                 break;
14535                         }
14536                         default:
14537                                 break;
14538                         }
14539                 }
14540         }
14541 #endif
14542
14543         if (cfg->compute_gc_maps) {
14544                 /* registers need liveness info even for !non refs */
14545                 for (i = 0; i < cfg->num_varinfo; i++) {
14546                         MonoInst *ins = cfg->varinfo [i];
14547
14548                         if (ins->opcode == OP_REGVAR)
14549                                 ins->flags |= MONO_INST_GC_TRACK;
14550                 }
14551         }
14552                 
14553         /* FIXME: widening and truncation */
14554
14555         /*
14556          * As an optimization, when a variable allocated to the stack is first loaded into 
14557          * an lvreg, we will remember the lvreg and use it the next time instead of loading
14558          * the variable again.
14559          */
14560         orig_next_vreg = cfg->next_vreg;
14561         vreg_to_lvreg = (guint32 *)mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
14562         lvregs = (guint32 *)mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
14563         lvregs_len = 0;
14564
14565         /* 
14566          * These arrays contain the first and last instructions accessing a given
14567          * variable.
14568          * Since we emit bblocks in the same order we process them here, and we
14569          * don't split live ranges, these will precisely describe the live range of
14570          * the variable, i.e. the instruction range where a valid value can be found
14571          * in the variables location.
14572          * The live range is computed using the liveness info computed by the liveness pass.
14573          * We can't use vmv->range, since that is an abstract live range, and we need
14574          * one which is instruction precise.
14575          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
14576          */
14577         /* FIXME: Only do this if debugging info is requested */
14578         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
14579         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
14580         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
14581         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
14582         
14583         /* Add spill loads/stores */
14584         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
14585                 MonoInst *ins;
14586
14587                 if (cfg->verbose_level > 2)
14588                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
14589
14590                 /* Clear vreg_to_lvreg array */
14591                 for (i = 0; i < lvregs_len; i++)
14592                         vreg_to_lvreg [lvregs [i]] = 0;
14593                 lvregs_len = 0;
14594
14595                 cfg->cbb = bb;
14596                 MONO_BB_FOR_EACH_INS (bb, ins) {
14597                         const char *spec = INS_INFO (ins->opcode);
14598                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
14599                         gboolean store, no_lvreg;
14600                         int sregs [MONO_MAX_SRC_REGS];
14601
14602                         if (G_UNLIKELY (cfg->verbose_level > 2))
14603                                 mono_print_ins (ins);
14604
14605                         if (ins->opcode == OP_NOP)
14606                                 continue;
14607
14608                         /* 
14609                          * We handle LDADDR here as well, since it can only be decomposed
14610                          * when variable addresses are known.
14611                          */
14612                         if (ins->opcode == OP_LDADDR) {
14613                                 MonoInst *var = (MonoInst *)ins->inst_p0;
14614
14615                                 if (var->opcode == OP_VTARG_ADDR) {
14616                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
14617                                         MonoInst *vtaddr = var->inst_left;
14618                                         if (vtaddr->opcode == OP_REGVAR) {
14619                                                 ins->opcode = OP_MOVE;
14620                                                 ins->sreg1 = vtaddr->dreg;
14621                                         }
14622                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
14623                                                 ins->opcode = OP_LOAD_MEMBASE;
14624                                                 ins->inst_basereg = vtaddr->inst_basereg;
14625                                                 ins->inst_offset = vtaddr->inst_offset;
14626                                         } else
14627                                                 NOT_IMPLEMENTED;
14628                                 } else if (cfg->gsharedvt && cfg->gsharedvt_vreg_to_idx [var->dreg] < 0) {
14629                                         /* gsharedvt arg passed by ref */
14630                                         g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
14631
14632                                         ins->opcode = OP_LOAD_MEMBASE;
14633                                         ins->inst_basereg = var->inst_basereg;
14634                                         ins->inst_offset = var->inst_offset;
14635                                 } else if (cfg->gsharedvt && cfg->gsharedvt_vreg_to_idx [var->dreg]) {
14636                                         MonoInst *load, *load2, *load3;
14637                                         int idx = cfg->gsharedvt_vreg_to_idx [var->dreg] - 1;
14638                                         int reg1, reg2, reg3;
14639                                         MonoInst *info_var = cfg->gsharedvt_info_var;
14640                                         MonoInst *locals_var = cfg->gsharedvt_locals_var;
14641
14642                                         /*
14643                                          * gsharedvt local.
14644                                          * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
14645                                          */
14646
14647                                         g_assert (var->opcode == OP_GSHAREDVT_LOCAL);
14648
14649                                         g_assert (info_var);
14650                                         g_assert (locals_var);
14651
14652                                         /* Mark the instruction used to compute the locals var as used */
14653                                         cfg->gsharedvt_locals_var_ins = NULL;
14654
14655                                         /* Load the offset */
14656                                         if (info_var->opcode == OP_REGOFFSET) {
14657                                                 reg1 = alloc_ireg (cfg);
14658                                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, reg1, info_var->inst_basereg, info_var->inst_offset);
14659                                         } else if (info_var->opcode == OP_REGVAR) {
14660                                                 load = NULL;
14661                                                 reg1 = info_var->dreg;
14662                                         } else {
14663                                                 g_assert_not_reached ();
14664                                         }
14665                                         reg2 = alloc_ireg (cfg);
14666                                         NEW_LOAD_MEMBASE (cfg, load2, OP_LOADI4_MEMBASE, reg2, reg1, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
14667                                         /* Load the locals area address */
14668                                         reg3 = alloc_ireg (cfg);
14669                                         if (locals_var->opcode == OP_REGOFFSET) {
14670                                                 NEW_LOAD_MEMBASE (cfg, load3, OP_LOAD_MEMBASE, reg3, locals_var->inst_basereg, locals_var->inst_offset);
14671                                         } else if (locals_var->opcode == OP_REGVAR) {
14672                                                 NEW_UNALU (cfg, load3, OP_MOVE, reg3, locals_var->dreg);
14673                                         } else {
14674                                                 g_assert_not_reached ();
14675                                         }
14676                                         /* Compute the address */
14677                                         ins->opcode = OP_PADD;
14678                                         ins->sreg1 = reg3;
14679                                         ins->sreg2 = reg2;
14680
14681                                         mono_bblock_insert_before_ins (bb, ins, load3);
14682                                         mono_bblock_insert_before_ins (bb, load3, load2);
14683                                         if (load)
14684                                                 mono_bblock_insert_before_ins (bb, load2, load);
14685                                 } else {
14686                                         g_assert (var->opcode == OP_REGOFFSET);
14687
14688                                         ins->opcode = OP_ADD_IMM;
14689                                         ins->sreg1 = var->inst_basereg;
14690                                         ins->inst_imm = var->inst_offset;
14691                                 }
14692
14693                                 *need_local_opts = TRUE;
14694                                 spec = INS_INFO (ins->opcode);
14695                         }
14696
14697                         if (ins->opcode < MONO_CEE_LAST) {
14698                                 mono_print_ins (ins);
14699                                 g_assert_not_reached ();
14700                         }
14701
14702                         /*
14703                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
14704                          * src register.
14705                          * FIXME:
14706                          */
14707                         if (MONO_IS_STORE_MEMBASE (ins)) {
14708                                 tmp_reg = ins->dreg;
14709                                 ins->dreg = ins->sreg2;
14710                                 ins->sreg2 = tmp_reg;
14711                                 store = TRUE;
14712
14713                                 spec2 [MONO_INST_DEST] = ' ';
14714                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14715                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14716                                 spec2 [MONO_INST_SRC3] = ' ';
14717                                 spec = spec2;
14718                         } else if (MONO_IS_STORE_MEMINDEX (ins))
14719                                 g_assert_not_reached ();
14720                         else
14721                                 store = FALSE;
14722                         no_lvreg = FALSE;
14723
14724                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
14725                                 printf ("\t %.3s %d", spec, ins->dreg);
14726                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
14727                                 for (srcindex = 0; srcindex < num_sregs; ++srcindex)
14728                                         printf (" %d", sregs [srcindex]);
14729                                 printf ("\n");
14730                         }
14731
14732                         /***************/
14733                         /*    DREG     */
14734                         /***************/
14735                         regtype = spec [MONO_INST_DEST];
14736                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
14737                         prev_dreg = -1;
14738
14739                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
14740                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
14741                                 MonoInst *store_ins;
14742                                 int store_opcode;
14743                                 MonoInst *def_ins = ins;
14744                                 int dreg = ins->dreg; /* The original vreg */
14745
14746                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
14747
14748                                 if (var->opcode == OP_REGVAR) {
14749                                         ins->dreg = var->dreg;
14750                                 } 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)) {
14751                                         /* 
14752                                          * Instead of emitting a load+store, use a _membase opcode.
14753                                          */
14754                                         g_assert (var->opcode == OP_REGOFFSET);
14755                                         if (ins->opcode == OP_MOVE) {
14756                                                 NULLIFY_INS (ins);
14757                                                 def_ins = NULL;
14758                                         } else {
14759                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
14760                                                 ins->inst_basereg = var->inst_basereg;
14761                                                 ins->inst_offset = var->inst_offset;
14762                                                 ins->dreg = -1;
14763                                         }
14764                                         spec = INS_INFO (ins->opcode);
14765                                 } else {
14766                                         guint32 lvreg;
14767
14768                                         g_assert (var->opcode == OP_REGOFFSET);
14769
14770                                         prev_dreg = ins->dreg;
14771
14772                                         /* Invalidate any previous lvreg for this vreg */
14773                                         vreg_to_lvreg [ins->dreg] = 0;
14774
14775                                         lvreg = 0;
14776
14777                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
14778                                                 regtype = 'l';
14779                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
14780                                         }
14781
14782                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
14783
14784 #if SIZEOF_REGISTER != 8
14785                                         if (regtype == 'l') {
14786                                                 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));
14787                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14788                                                 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));
14789                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14790                                                 def_ins = store_ins;
14791                                         }
14792                                         else
14793 #endif
14794                                         {
14795                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
14796
14797                                                 /* Try to fuse the store into the instruction itself */
14798                                                 /* FIXME: Add more instructions */
14799                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
14800                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
14801                                                         ins->inst_imm = ins->inst_c0;
14802                                                         ins->inst_destbasereg = var->inst_basereg;
14803                                                         ins->inst_offset = var->inst_offset;
14804                                                         spec = INS_INFO (ins->opcode);
14805                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE) || (ins->opcode == OP_RMOVE))) {
14806                                                         ins->opcode = store_opcode;
14807                                                         ins->inst_destbasereg = var->inst_basereg;
14808                                                         ins->inst_offset = var->inst_offset;
14809
14810                                                         no_lvreg = TRUE;
14811
14812                                                         tmp_reg = ins->dreg;
14813                                                         ins->dreg = ins->sreg2;
14814                                                         ins->sreg2 = tmp_reg;
14815                                                         store = TRUE;
14816
14817                                                         spec2 [MONO_INST_DEST] = ' ';
14818                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14819                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14820                                                         spec2 [MONO_INST_SRC3] = ' ';
14821                                                         spec = spec2;
14822                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
14823                                                         // FIXME: The backends expect the base reg to be in inst_basereg
14824                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
14825                                                         ins->dreg = -1;
14826                                                         ins->inst_basereg = var->inst_basereg;
14827                                                         ins->inst_offset = var->inst_offset;
14828                                                         spec = INS_INFO (ins->opcode);
14829                                                 } else {
14830                                                         /* printf ("INS: "); mono_print_ins (ins); */
14831                                                         /* Create a store instruction */
14832                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
14833
14834                                                         /* Insert it after the instruction */
14835                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
14836
14837                                                         def_ins = store_ins;
14838
14839                                                         /* 
14840                                                          * We can't assign ins->dreg to var->dreg here, since the
14841                                                          * sregs could use it. So set a flag, and do it after
14842                                                          * the sregs.
14843                                                          */
14844                                                         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)))
14845                                                                 dest_has_lvreg = TRUE;
14846                                                 }
14847                                         }
14848                                 }
14849
14850                                 if (def_ins && !live_range_start [dreg]) {
14851                                         live_range_start [dreg] = def_ins;
14852                                         live_range_start_bb [dreg] = bb;
14853                                 }
14854
14855                                 if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) {
14856                                         MonoInst *tmp;
14857
14858                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
14859                                         tmp->inst_c1 = dreg;
14860                                         mono_bblock_insert_after_ins (bb, def_ins, tmp);
14861                                 }
14862                         }
14863
14864                         /************/
14865                         /*  SREGS   */
14866                         /************/
14867                         num_sregs = mono_inst_get_src_registers (ins, sregs);
14868                         for (srcindex = 0; srcindex < 3; ++srcindex) {
14869                                 regtype = spec [MONO_INST_SRC1 + srcindex];
14870                                 sreg = sregs [srcindex];
14871
14872                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
14873                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
14874                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
14875                                         MonoInst *use_ins = ins;
14876                                         MonoInst *load_ins;
14877                                         guint32 load_opcode;
14878
14879                                         if (var->opcode == OP_REGVAR) {
14880                                                 sregs [srcindex] = var->dreg;
14881                                                 //mono_inst_set_src_registers (ins, sregs);
14882                                                 live_range_end [sreg] = use_ins;
14883                                                 live_range_end_bb [sreg] = bb;
14884
14885                                                 if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14886                                                         MonoInst *tmp;
14887
14888                                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14889                                                         /* var->dreg is a hreg */
14890                                                         tmp->inst_c1 = sreg;
14891                                                         mono_bblock_insert_after_ins (bb, ins, tmp);
14892                                                 }
14893
14894                                                 continue;
14895                                         }
14896
14897                                         g_assert (var->opcode == OP_REGOFFSET);
14898                                                 
14899                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
14900
14901                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
14902
14903                                         if (vreg_to_lvreg [sreg]) {
14904                                                 g_assert (vreg_to_lvreg [sreg] != -1);
14905
14906                                                 /* The variable is already loaded to an lvreg */
14907                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14908                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
14909                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
14910                                                 //mono_inst_set_src_registers (ins, sregs);
14911                                                 continue;
14912                                         }
14913
14914                                         /* Try to fuse the load into the instruction */
14915                                         if ((srcindex == 0) && (op_to_op_src1_membase (cfg, load_opcode, ins->opcode) != -1)) {
14916                                                 ins->opcode = op_to_op_src1_membase (cfg, load_opcode, ins->opcode);
14917                                                 sregs [0] = var->inst_basereg;
14918                                                 //mono_inst_set_src_registers (ins, sregs);
14919                                                 ins->inst_offset = var->inst_offset;
14920                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (cfg, load_opcode, ins->opcode) != -1)) {
14921                                                 ins->opcode = op_to_op_src2_membase (cfg, load_opcode, ins->opcode);
14922                                                 sregs [1] = var->inst_basereg;
14923                                                 //mono_inst_set_src_registers (ins, sregs);
14924                                                 ins->inst_offset = var->inst_offset;
14925                                         } else {
14926                                                 if (MONO_IS_REAL_MOVE (ins)) {
14927                                                         ins->opcode = OP_NOP;
14928                                                         sreg = ins->dreg;
14929                                                 } else {
14930                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
14931
14932                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
14933
14934                                                         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) {
14935                                                                 if (var->dreg == prev_dreg) {
14936                                                                         /*
14937                                                                          * sreg refers to the value loaded by the load
14938                                                                          * emitted below, but we need to use ins->dreg
14939                                                                          * since it refers to the store emitted earlier.
14940                                                                          */
14941                                                                         sreg = ins->dreg;
14942                                                                 }
14943                                                                 g_assert (sreg != -1);
14944                                                                 vreg_to_lvreg [var->dreg] = sreg;
14945                                                                 g_assert (lvregs_len < 1024);
14946                                                                 lvregs [lvregs_len ++] = var->dreg;
14947                                                         }
14948                                                 }
14949
14950                                                 sregs [srcindex] = sreg;
14951                                                 //mono_inst_set_src_registers (ins, sregs);
14952
14953 #if SIZEOF_REGISTER != 8
14954                                                 if (regtype == 'l') {
14955                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, MONO_LVREG_MS (sreg), var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
14956                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14957                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, MONO_LVREG_LS (sreg), var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
14958                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14959                                                         use_ins = load_ins;
14960                                                 }
14961                                                 else
14962 #endif
14963                                                 {
14964 #if SIZEOF_REGISTER == 4
14965                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
14966 #endif
14967                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
14968                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14969                                                         use_ins = load_ins;
14970                                                 }
14971                                         }
14972
14973                                         if (var->dreg < orig_next_vreg) {
14974                                                 live_range_end [var->dreg] = use_ins;
14975                                                 live_range_end_bb [var->dreg] = bb;
14976                                         }
14977
14978                                         if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14979                                                 MonoInst *tmp;
14980
14981                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14982                                                 tmp->inst_c1 = var->dreg;
14983                                                 mono_bblock_insert_after_ins (bb, ins, tmp);
14984                                         }
14985                                 }
14986                         }
14987                         mono_inst_set_src_registers (ins, sregs);
14988
14989                         if (dest_has_lvreg) {
14990                                 g_assert (ins->dreg != -1);
14991                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
14992                                 g_assert (lvregs_len < 1024);
14993                                 lvregs [lvregs_len ++] = prev_dreg;
14994                                 dest_has_lvreg = FALSE;
14995                         }
14996
14997                         if (store) {
14998                                 tmp_reg = ins->dreg;
14999                                 ins->dreg = ins->sreg2;
15000                                 ins->sreg2 = tmp_reg;
15001                         }
15002
15003                         if (MONO_IS_CALL (ins)) {
15004                                 /* Clear vreg_to_lvreg array */
15005                                 for (i = 0; i < lvregs_len; i++)
15006                                         vreg_to_lvreg [lvregs [i]] = 0;
15007                                 lvregs_len = 0;
15008                         } else if (ins->opcode == OP_NOP) {
15009                                 ins->dreg = -1;
15010                                 MONO_INST_NULLIFY_SREGS (ins);
15011                         }
15012
15013                         if (cfg->verbose_level > 2)
15014                                 mono_print_ins_index (1, ins);
15015                 }
15016
15017                 /* Extend the live range based on the liveness info */
15018                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
15019                         for (i = 0; i < cfg->num_varinfo; i ++) {
15020                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
15021
15022                                 if (vreg_is_volatile (cfg, vi->vreg))
15023                                         /* The liveness info is incomplete */
15024                                         continue;
15025
15026                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
15027                                         /* Live from at least the first ins of this bb */
15028                                         live_range_start [vi->vreg] = bb->code;
15029                                         live_range_start_bb [vi->vreg] = bb;
15030                                 }
15031
15032                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
15033                                         /* Live at least until the last ins of this bb */
15034                                         live_range_end [vi->vreg] = bb->last_ins;
15035                                         live_range_end_bb [vi->vreg] = bb;
15036                                 }
15037                         }
15038                 }
15039         }
15040         
15041         /*
15042          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
15043          * by storing the current native offset into MonoMethodVar->live_range_start/end.
15044          */
15045         if (cfg->backend->have_liverange_ops && cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
15046                 for (i = 0; i < cfg->num_varinfo; ++i) {
15047                         int vreg = MONO_VARINFO (cfg, i)->vreg;
15048                         MonoInst *ins;
15049
15050                         if (live_range_start [vreg]) {
15051                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
15052                                 ins->inst_c0 = i;
15053                                 ins->inst_c1 = vreg;
15054                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
15055                         }
15056                         if (live_range_end [vreg]) {
15057                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
15058                                 ins->inst_c0 = i;
15059                                 ins->inst_c1 = vreg;
15060                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
15061                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
15062                                 else
15063                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
15064                         }
15065                 }
15066         }
15067
15068         if (cfg->gsharedvt_locals_var_ins) {
15069                 /* Nullify if unused */
15070                 cfg->gsharedvt_locals_var_ins->opcode = OP_PCONST;
15071                 cfg->gsharedvt_locals_var_ins->inst_imm = 0;
15072         }
15073
15074         g_free (live_range_start);
15075         g_free (live_range_end);
15076         g_free (live_range_start_bb);
15077         g_free (live_range_end_bb);
15078 }
15079
15080 static void
15081 mono_decompose_typecheck (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins)
15082 {
15083         MonoInst *ret, *move, *source;
15084         MonoClass *klass = ins->klass;
15085         int context_used = mini_class_check_context_used (cfg, klass);
15086         int is_isinst = ins->opcode == OP_ISINST;
15087         g_assert (is_isinst || ins->opcode == OP_CASTCLASS);
15088         source = get_vreg_to_inst (cfg, ins->sreg1);
15089         if (!source || source == (MonoInst *) -1)
15090                 source = mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, ins->sreg1);
15091         g_assert (source && source != (MonoInst *) -1);
15092
15093         MonoBasicBlock *first_bb;
15094         NEW_BBLOCK (cfg, first_bb);
15095         cfg->cbb = first_bb;
15096
15097         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
15098                 if (is_isinst)
15099                         ret = emit_isinst_with_cache_nonshared (cfg, source, klass);
15100                 else
15101                         ret = emit_castclass_with_cache_nonshared (cfg, source, klass);
15102         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
15103                 MonoInst *iargs [1];
15104                 int costs;
15105
15106                 iargs [0] = source;
15107                 if (is_isinst) {
15108                         MonoMethod *wrapper = mono_marshal_get_isinst (klass);
15109                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), iargs, 0, 0, TRUE);
15110                 } else {
15111                         MonoMethod *wrapper = mono_marshal_get_castclass (klass);
15112                         save_cast_details (cfg, klass, source->dreg, TRUE);
15113                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), iargs, 0, 0, TRUE);
15114                         reset_cast_details (cfg);
15115                 }
15116                 g_assert (costs > 0);
15117                 ret = iargs [0];
15118         } else {
15119                 if (is_isinst)
15120                         ret = handle_isinst (cfg, klass, source, context_used);
15121                 else
15122                         ret = handle_castclass (cfg, klass, source, context_used);
15123         }
15124         EMIT_NEW_UNALU (cfg, move, OP_MOVE, ins->dreg, ret->dreg);
15125
15126         g_assert (cfg->cbb->code || first_bb->code);
15127         MonoInst *prev = ins->prev;
15128         mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
15129 }
15130
15131 void
15132 mono_decompose_typechecks (MonoCompile *cfg)
15133 {
15134         for (MonoBasicBlock *bb = cfg->bb_entry; bb; bb = bb->next_bb) {
15135                 MonoInst *ins;
15136                 MONO_BB_FOR_EACH_INS (bb, ins) {
15137                         switch (ins->opcode) {
15138                         case OP_ISINST:
15139                         case OP_CASTCLASS:
15140                                 mono_decompose_typecheck (cfg, bb, ins);
15141                                 break;
15142                         }
15143                 }
15144         }
15145 }
15146
15147
15148 /**
15149  * FIXME:
15150  * - use 'iadd' instead of 'int_add'
15151  * - handling ovf opcodes: decompose in method_to_ir.
15152  * - unify iregs/fregs
15153  *   -> partly done, the missing parts are:
15154  *   - a more complete unification would involve unifying the hregs as well, so
15155  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
15156  *     would no longer map to the machine hregs, so the code generators would need to
15157  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
15158  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
15159  *     fp/non-fp branches speeds it up by about 15%.
15160  * - use sext/zext opcodes instead of shifts
15161  * - add OP_ICALL
15162  * - get rid of TEMPLOADs if possible and use vregs instead
15163  * - clean up usage of OP_P/OP_ opcodes
15164  * - cleanup usage of DUMMY_USE
15165  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
15166  *   stack
15167  * - set the stack type and allocate a dreg in the EMIT_NEW macros
15168  * - get rid of all the <foo>2 stuff when the new JIT is ready.
15169  * - make sure handle_stack_args () is called before the branch is emitted
15170  * - when the new IR is done, get rid of all unused stuff
15171  * - COMPARE/BEQ as separate instructions or unify them ?
15172  *   - keeping them separate allows specialized compare instructions like
15173  *     compare_imm, compare_membase
15174  *   - most back ends unify fp compare+branch, fp compare+ceq
15175  * - integrate mono_save_args into inline_method
15176  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
15177  * - handle long shift opts on 32 bit platforms somehow: they require 
15178  *   3 sregs (2 for arg1 and 1 for arg2)
15179  * - make byref a 'normal' type.
15180  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
15181  *   variable if needed.
15182  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
15183  *   like inline_method.
15184  * - remove inlining restrictions
15185  * - fix LNEG and enable cfold of INEG
15186  * - generalize x86 optimizations like ldelema as a peephole optimization
15187  * - add store_mem_imm for amd64
15188  * - optimize the loading of the interruption flag in the managed->native wrappers
15189  * - avoid special handling of OP_NOP in passes
15190  * - move code inserting instructions into one function/macro.
15191  * - try a coalescing phase after liveness analysis
15192  * - add float -> vreg conversion + local optimizations on !x86
15193  * - figure out how to handle decomposed branches during optimizations, ie.
15194  *   compare+branch, op_jump_table+op_br etc.
15195  * - promote RuntimeXHandles to vregs
15196  * - vtype cleanups:
15197  *   - add a NEW_VARLOADA_VREG macro
15198  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
15199  *   accessing vtype fields.
15200  * - get rid of I8CONST on 64 bit platforms
15201  * - dealing with the increase in code size due to branches created during opcode
15202  *   decomposition:
15203  *   - use extended basic blocks
15204  *     - all parts of the JIT
15205  *     - handle_global_vregs () && local regalloc
15206  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
15207  * - sources of increase in code size:
15208  *   - vtypes
15209  *   - long compares
15210  *   - isinst and castclass
15211  *   - lvregs not allocated to global registers even if used multiple times
15212  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
15213  *   meaningful.
15214  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
15215  * - add all micro optimizations from the old JIT
15216  * - put tree optimizations into the deadce pass
15217  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
15218  *   specific function.
15219  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
15220  *   fcompare + branchCC.
15221  * - create a helper function for allocating a stack slot, taking into account 
15222  *   MONO_CFG_HAS_SPILLUP.
15223  * - merge r68207.
15224  * - merge the ia64 switch changes.
15225  * - optimize mono_regstate2_alloc_int/float.
15226  * - fix the pessimistic handling of variables accessed in exception handler blocks.
15227  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
15228  *   parts of the tree could be separated by other instructions, killing the tree
15229  *   arguments, or stores killing loads etc. Also, should we fold loads into other
15230  *   instructions if the result of the load is used multiple times ?
15231  * - make the REM_IMM optimization in mini-x86.c arch-independent.
15232  * - LAST MERGE: 108395.
15233  * - when returning vtypes in registers, generate IR and append it to the end of the
15234  *   last bb instead of doing it in the epilog.
15235  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
15236  */
15237
15238 /*
15239
15240 NOTES
15241 -----
15242
15243 - When to decompose opcodes:
15244   - earlier: this makes some optimizations hard to implement, since the low level IR
15245   no longer contains the neccessary information. But it is easier to do.
15246   - later: harder to implement, enables more optimizations.
15247 - Branches inside bblocks:
15248   - created when decomposing complex opcodes. 
15249     - branches to another bblock: harmless, but not tracked by the branch 
15250       optimizations, so need to branch to a label at the start of the bblock.
15251     - branches to inside the same bblock: very problematic, trips up the local
15252       reg allocator. Can be fixed by spitting the current bblock, but that is a
15253       complex operation, since some local vregs can become global vregs etc.
15254 - Local/global vregs:
15255   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
15256     local register allocator.
15257   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
15258     structure, created by mono_create_var (). Assigned to hregs or the stack by
15259     the global register allocator.
15260 - When to do optimizations like alu->alu_imm:
15261   - earlier -> saves work later on since the IR will be smaller/simpler
15262   - later -> can work on more instructions
15263 - Handling of valuetypes:
15264   - When a vtype is pushed on the stack, a new temporary is created, an 
15265     instruction computing its address (LDADDR) is emitted and pushed on
15266     the stack. Need to optimize cases when the vtype is used immediately as in
15267     argument passing, stloc etc.
15268 - Instead of the to_end stuff in the old JIT, simply call the function handling
15269   the values on the stack before emitting the last instruction of the bb.
15270 */
15271
15272 #endif /* DISABLE_JIT */