Merge pull request #3716 from vargaz/unbox-stobj-null
[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 (MONO_INS_IS_PCONST_NULL (src))
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 (!MONO_INS_IS_PCONST_NULL (target)) {
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                 !(MONO_INS_IS_PCONST_NULL (sp [2]))) {
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                 gboolean is_v4 = FALSE;
6129
6130                 if (!strcmp (cmethod->name, "Enter") && fsig->param_count == 2 && fsig->params [1]->byref) {
6131                         is_enter = TRUE;
6132                         is_v4 = TRUE;
6133                 }
6134                 if (!strcmp (cmethod->name, "Enter") && fsig->param_count == 1)
6135                         is_enter = TRUE;
6136
6137                 if (is_enter) {
6138                         /*
6139                          * To make async stack traces work, icalls which can block should have a wrapper.
6140                          * For Monitor.Enter, emit two calls: a fastpath which doesn't have a wrapper, and a slowpath, which does.
6141                          */
6142                         MonoBasicBlock *end_bb;
6143
6144                         NEW_BBLOCK (cfg, end_bb);
6145
6146                         ins = mono_emit_jit_icall (cfg, is_v4 ? (gpointer)mono_monitor_enter_v4_fast : (gpointer)mono_monitor_enter_fast, args);
6147                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, ins->dreg, 0);
6148                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, end_bb);
6149                         ins = mono_emit_jit_icall (cfg, is_v4 ? (gpointer)mono_monitor_enter_v4 : (gpointer)mono_monitor_enter, args);
6150                         MONO_START_BB (cfg, end_bb);
6151                         return ins;
6152                 }
6153         } else if (cmethod->klass == mono_defaults.thread_class) {
6154                 if (strcmp (cmethod->name, "SpinWait_nop") == 0 && fsig->param_count == 0) {
6155                         MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
6156                         MONO_ADD_INS (cfg->cbb, ins);
6157                         return ins;
6158                 } else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0) {
6159                         return emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6160                 } else if (!strcmp (cmethod->name, "VolatileRead") && fsig->param_count == 1) {
6161                         guint32 opcode = 0;
6162                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6163
6164                         if (fsig->params [0]->type == MONO_TYPE_I1)
6165                                 opcode = OP_LOADI1_MEMBASE;
6166                         else if (fsig->params [0]->type == MONO_TYPE_U1)
6167                                 opcode = OP_LOADU1_MEMBASE;
6168                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6169                                 opcode = OP_LOADI2_MEMBASE;
6170                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6171                                 opcode = OP_LOADU2_MEMBASE;
6172                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6173                                 opcode = OP_LOADI4_MEMBASE;
6174                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6175                                 opcode = OP_LOADU4_MEMBASE;
6176                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
6177                                 opcode = OP_LOADI8_MEMBASE;
6178                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6179                                 opcode = OP_LOADR4_MEMBASE;
6180                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6181                                 opcode = OP_LOADR8_MEMBASE;
6182                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
6183                                 opcode = OP_LOAD_MEMBASE;
6184
6185                         if (opcode) {
6186                                 MONO_INST_NEW (cfg, ins, opcode);
6187                                 ins->inst_basereg = args [0]->dreg;
6188                                 ins->inst_offset = 0;
6189                                 MONO_ADD_INS (cfg->cbb, ins);
6190
6191                                 switch (fsig->params [0]->type) {
6192                                 case MONO_TYPE_I1:
6193                                 case MONO_TYPE_U1:
6194                                 case MONO_TYPE_I2:
6195                                 case MONO_TYPE_U2:
6196                                 case MONO_TYPE_I4:
6197                                 case MONO_TYPE_U4:
6198                                         ins->dreg = mono_alloc_ireg (cfg);
6199                                         ins->type = STACK_I4;
6200                                         break;
6201                                 case MONO_TYPE_I8:
6202                                 case MONO_TYPE_U8:
6203                                         ins->dreg = mono_alloc_lreg (cfg);
6204                                         ins->type = STACK_I8;
6205                                         break;
6206                                 case MONO_TYPE_I:
6207                                 case MONO_TYPE_U:
6208                                         ins->dreg = mono_alloc_ireg (cfg);
6209 #if SIZEOF_REGISTER == 8
6210                                         ins->type = STACK_I8;
6211 #else
6212                                         ins->type = STACK_I4;
6213 #endif
6214                                         break;
6215                                 case MONO_TYPE_R4:
6216                                 case MONO_TYPE_R8:
6217                                         ins->dreg = mono_alloc_freg (cfg);
6218                                         ins->type = STACK_R8;
6219                                         break;
6220                                 default:
6221                                         g_assert (mini_type_is_reference (fsig->params [0]));
6222                                         ins->dreg = mono_alloc_ireg_ref (cfg);
6223                                         ins->type = STACK_OBJ;
6224                                         break;
6225                                 }
6226
6227                                 if (opcode == OP_LOADI8_MEMBASE)
6228                                         ins = mono_decompose_opcode (cfg, ins);
6229
6230                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6231
6232                                 return ins;
6233                         }
6234                 } else if (!strcmp (cmethod->name, "VolatileWrite") && fsig->param_count == 2) {
6235                         guint32 opcode = 0;
6236                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6237
6238                         if (fsig->params [0]->type == MONO_TYPE_I1 || fsig->params [0]->type == MONO_TYPE_U1)
6239                                 opcode = OP_STOREI1_MEMBASE_REG;
6240                         else if (fsig->params [0]->type == MONO_TYPE_I2 || fsig->params [0]->type == MONO_TYPE_U2)
6241                                 opcode = OP_STOREI2_MEMBASE_REG;
6242                         else if (fsig->params [0]->type == MONO_TYPE_I4 || fsig->params [0]->type == MONO_TYPE_U4)
6243                                 opcode = OP_STOREI4_MEMBASE_REG;
6244                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
6245                                 opcode = OP_STOREI8_MEMBASE_REG;
6246                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6247                                 opcode = OP_STORER4_MEMBASE_REG;
6248                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6249                                 opcode = OP_STORER8_MEMBASE_REG;
6250                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
6251                                 opcode = OP_STORE_MEMBASE_REG;
6252
6253                         if (opcode) {
6254                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6255
6256                                 MONO_INST_NEW (cfg, ins, opcode);
6257                                 ins->sreg1 = args [1]->dreg;
6258                                 ins->inst_destbasereg = args [0]->dreg;
6259                                 ins->inst_offset = 0;
6260                                 MONO_ADD_INS (cfg->cbb, ins);
6261
6262                                 if (opcode == OP_STOREI8_MEMBASE_REG)
6263                                         ins = mono_decompose_opcode (cfg, ins);
6264
6265                                 return ins;
6266                         }
6267                 }
6268         } else if (cmethod->klass->image == mono_defaults.corlib &&
6269                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6270                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
6271                 ins = NULL;
6272
6273 #if SIZEOF_REGISTER == 8
6274                 if (!cfg->llvm_only && strcmp (cmethod->name, "Read") == 0 && fsig->param_count == 1 && (fsig->params [0]->type == MONO_TYPE_I8)) {
6275                         if (!cfg->llvm_only && mono_arch_opcode_supported (OP_ATOMIC_LOAD_I8)) {
6276                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_LOAD_I8);
6277                                 ins->dreg = mono_alloc_preg (cfg);
6278                                 ins->sreg1 = args [0]->dreg;
6279                                 ins->type = STACK_I8;
6280                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_SEQ;
6281                                 MONO_ADD_INS (cfg->cbb, ins);
6282                         } else {
6283                                 MonoInst *load_ins;
6284
6285                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6286
6287                                 /* 64 bit reads are already atomic */
6288                                 MONO_INST_NEW (cfg, load_ins, OP_LOADI8_MEMBASE);
6289                                 load_ins->dreg = mono_alloc_preg (cfg);
6290                                 load_ins->inst_basereg = args [0]->dreg;
6291                                 load_ins->inst_offset = 0;
6292                                 load_ins->type = STACK_I8;
6293                                 MONO_ADD_INS (cfg->cbb, load_ins);
6294
6295                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6296
6297                                 ins = load_ins;
6298                         }
6299                 }
6300 #endif
6301
6302                 if (strcmp (cmethod->name, "Increment") == 0 && fsig->param_count == 1) {
6303                         MonoInst *ins_iconst;
6304                         guint32 opcode = 0;
6305
6306                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6307                                 opcode = OP_ATOMIC_ADD_I4;
6308                                 cfg->has_atomic_add_i4 = TRUE;
6309                         }
6310 #if SIZEOF_REGISTER == 8
6311                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6312                                 opcode = OP_ATOMIC_ADD_I8;
6313 #endif
6314                         if (opcode) {
6315                                 if (!mono_arch_opcode_supported (opcode))
6316                                         return NULL;
6317                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6318                                 ins_iconst->inst_c0 = 1;
6319                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6320                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6321
6322                                 MONO_INST_NEW (cfg, ins, opcode);
6323                                 ins->dreg = mono_alloc_ireg (cfg);
6324                                 ins->inst_basereg = args [0]->dreg;
6325                                 ins->inst_offset = 0;
6326                                 ins->sreg2 = ins_iconst->dreg;
6327                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6328                                 MONO_ADD_INS (cfg->cbb, ins);
6329                         }
6330                 } else if (strcmp (cmethod->name, "Decrement") == 0 && fsig->param_count == 1) {
6331                         MonoInst *ins_iconst;
6332                         guint32 opcode = 0;
6333
6334                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6335                                 opcode = OP_ATOMIC_ADD_I4;
6336                                 cfg->has_atomic_add_i4 = TRUE;
6337                         }
6338 #if SIZEOF_REGISTER == 8
6339                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6340                                 opcode = OP_ATOMIC_ADD_I8;
6341 #endif
6342                         if (opcode) {
6343                                 if (!mono_arch_opcode_supported (opcode))
6344                                         return NULL;
6345                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6346                                 ins_iconst->inst_c0 = -1;
6347                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6348                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6349
6350                                 MONO_INST_NEW (cfg, ins, opcode);
6351                                 ins->dreg = mono_alloc_ireg (cfg);
6352                                 ins->inst_basereg = args [0]->dreg;
6353                                 ins->inst_offset = 0;
6354                                 ins->sreg2 = ins_iconst->dreg;
6355                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6356                                 MONO_ADD_INS (cfg->cbb, ins);
6357                         }
6358                 } else if (strcmp (cmethod->name, "Add") == 0 && fsig->param_count == 2) {
6359                         guint32 opcode = 0;
6360
6361                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6362                                 opcode = OP_ATOMIC_ADD_I4;
6363                                 cfg->has_atomic_add_i4 = TRUE;
6364                         }
6365 #if SIZEOF_REGISTER == 8
6366                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6367                                 opcode = OP_ATOMIC_ADD_I8;
6368 #endif
6369                         if (opcode) {
6370                                 if (!mono_arch_opcode_supported (opcode))
6371                                         return NULL;
6372                                 MONO_INST_NEW (cfg, ins, opcode);
6373                                 ins->dreg = mono_alloc_ireg (cfg);
6374                                 ins->inst_basereg = args [0]->dreg;
6375                                 ins->inst_offset = 0;
6376                                 ins->sreg2 = args [1]->dreg;
6377                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6378                                 MONO_ADD_INS (cfg->cbb, ins);
6379                         }
6380                 }
6381                 else if (strcmp (cmethod->name, "Exchange") == 0 && fsig->param_count == 2) {
6382                         MonoInst *f2i = NULL, *i2f;
6383                         guint32 opcode, f2i_opcode, i2f_opcode;
6384                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6385                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
6386
6387                         if (fsig->params [0]->type == MONO_TYPE_I4 ||
6388                             fsig->params [0]->type == MONO_TYPE_R4) {
6389                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6390                                 f2i_opcode = OP_MOVE_F_TO_I4;
6391                                 i2f_opcode = OP_MOVE_I4_TO_F;
6392                                 cfg->has_atomic_exchange_i4 = TRUE;
6393                         }
6394 #if SIZEOF_REGISTER == 8
6395                         else if (is_ref ||
6396                                  fsig->params [0]->type == MONO_TYPE_I8 ||
6397                                  fsig->params [0]->type == MONO_TYPE_R8 ||
6398                                  fsig->params [0]->type == MONO_TYPE_I) {
6399                                 opcode = OP_ATOMIC_EXCHANGE_I8;
6400                                 f2i_opcode = OP_MOVE_F_TO_I8;
6401                                 i2f_opcode = OP_MOVE_I8_TO_F;
6402                         }
6403 #else
6404                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I) {
6405                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6406                                 cfg->has_atomic_exchange_i4 = TRUE;
6407                         }
6408 #endif
6409                         else
6410                                 return NULL;
6411
6412                         if (!mono_arch_opcode_supported (opcode))
6413                                 return NULL;
6414
6415                         if (is_float) {
6416                                 /* TODO: Decompose these opcodes instead of bailing here. */
6417                                 if (COMPILE_SOFT_FLOAT (cfg))
6418                                         return NULL;
6419
6420                                 MONO_INST_NEW (cfg, f2i, f2i_opcode);
6421                                 f2i->dreg = mono_alloc_ireg (cfg);
6422                                 f2i->sreg1 = args [1]->dreg;
6423                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6424                                         f2i->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6425                                 MONO_ADD_INS (cfg->cbb, f2i);
6426                         }
6427
6428                         MONO_INST_NEW (cfg, ins, opcode);
6429                         ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : mono_alloc_ireg (cfg);
6430                         ins->inst_basereg = args [0]->dreg;
6431                         ins->inst_offset = 0;
6432                         ins->sreg2 = is_float ? f2i->dreg : args [1]->dreg;
6433                         MONO_ADD_INS (cfg->cbb, ins);
6434
6435                         switch (fsig->params [0]->type) {
6436                         case MONO_TYPE_I4:
6437                                 ins->type = STACK_I4;
6438                                 break;
6439                         case MONO_TYPE_I8:
6440                                 ins->type = STACK_I8;
6441                                 break;
6442                         case MONO_TYPE_I:
6443 #if SIZEOF_REGISTER == 8
6444                                 ins->type = STACK_I8;
6445 #else
6446                                 ins->type = STACK_I4;
6447 #endif
6448                                 break;
6449                         case MONO_TYPE_R4:
6450                         case MONO_TYPE_R8:
6451                                 ins->type = STACK_R8;
6452                                 break;
6453                         default:
6454                                 g_assert (mini_type_is_reference (fsig->params [0]));
6455                                 ins->type = STACK_OBJ;
6456                                 break;
6457                         }
6458
6459                         if (is_float) {
6460                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6461                                 i2f->dreg = mono_alloc_freg (cfg);
6462                                 i2f->sreg1 = ins->dreg;
6463                                 i2f->type = STACK_R8;
6464                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6465                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6466                                 MONO_ADD_INS (cfg->cbb, i2f);
6467
6468                                 ins = i2f;
6469                         }
6470
6471                         if (cfg->gen_write_barriers && is_ref)
6472                                 emit_write_barrier (cfg, args [0], args [1]);
6473                 }
6474                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 3) {
6475                         MonoInst *f2i_new = NULL, *f2i_cmp = NULL, *i2f;
6476                         guint32 opcode, f2i_opcode, i2f_opcode;
6477                         gboolean is_ref = mini_type_is_reference (fsig->params [1]);
6478                         gboolean is_float = fsig->params [1]->type == MONO_TYPE_R4 || fsig->params [1]->type == MONO_TYPE_R8;
6479
6480                         if (fsig->params [1]->type == MONO_TYPE_I4 ||
6481                             fsig->params [1]->type == MONO_TYPE_R4) {
6482                                 opcode = OP_ATOMIC_CAS_I4;
6483                                 f2i_opcode = OP_MOVE_F_TO_I4;
6484                                 i2f_opcode = OP_MOVE_I4_TO_F;
6485                                 cfg->has_atomic_cas_i4 = TRUE;
6486                         }
6487 #if SIZEOF_REGISTER == 8
6488                         else if (is_ref ||
6489                                  fsig->params [1]->type == MONO_TYPE_I8 ||
6490                                  fsig->params [1]->type == MONO_TYPE_R8 ||
6491                                  fsig->params [1]->type == MONO_TYPE_I) {
6492                                 opcode = OP_ATOMIC_CAS_I8;
6493                                 f2i_opcode = OP_MOVE_F_TO_I8;
6494                                 i2f_opcode = OP_MOVE_I8_TO_F;
6495                         }
6496 #else
6497                         else if (is_ref || fsig->params [1]->type == MONO_TYPE_I) {
6498                                 opcode = OP_ATOMIC_CAS_I4;
6499                                 cfg->has_atomic_cas_i4 = TRUE;
6500                         }
6501 #endif
6502                         else
6503                                 return NULL;
6504
6505                         if (!mono_arch_opcode_supported (opcode))
6506                                 return NULL;
6507
6508                         if (is_float) {
6509                                 /* TODO: Decompose these opcodes instead of bailing here. */
6510                                 if (COMPILE_SOFT_FLOAT (cfg))
6511                                         return NULL;
6512
6513                                 MONO_INST_NEW (cfg, f2i_new, f2i_opcode);
6514                                 f2i_new->dreg = mono_alloc_ireg (cfg);
6515                                 f2i_new->sreg1 = args [1]->dreg;
6516                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6517                                         f2i_new->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6518                                 MONO_ADD_INS (cfg->cbb, f2i_new);
6519
6520                                 MONO_INST_NEW (cfg, f2i_cmp, f2i_opcode);
6521                                 f2i_cmp->dreg = mono_alloc_ireg (cfg);
6522                                 f2i_cmp->sreg1 = args [2]->dreg;
6523                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6524                                         f2i_cmp->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6525                                 MONO_ADD_INS (cfg->cbb, f2i_cmp);
6526                         }
6527
6528                         MONO_INST_NEW (cfg, ins, opcode);
6529                         ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
6530                         ins->sreg1 = args [0]->dreg;
6531                         ins->sreg2 = is_float ? f2i_new->dreg : args [1]->dreg;
6532                         ins->sreg3 = is_float ? f2i_cmp->dreg : args [2]->dreg;
6533                         MONO_ADD_INS (cfg->cbb, ins);
6534
6535                         switch (fsig->params [1]->type) {
6536                         case MONO_TYPE_I4:
6537                                 ins->type = STACK_I4;
6538                                 break;
6539                         case MONO_TYPE_I8:
6540                                 ins->type = STACK_I8;
6541                                 break;
6542                         case MONO_TYPE_I:
6543 #if SIZEOF_REGISTER == 8
6544                                 ins->type = STACK_I8;
6545 #else
6546                                 ins->type = STACK_I4;
6547 #endif
6548                                 break;
6549                         case MONO_TYPE_R4:
6550                                 ins->type = cfg->r4_stack_type;
6551                                 break;
6552                         case MONO_TYPE_R8:
6553                                 ins->type = STACK_R8;
6554                                 break;
6555                         default:
6556                                 g_assert (mini_type_is_reference (fsig->params [1]));
6557                                 ins->type = STACK_OBJ;
6558                                 break;
6559                         }
6560
6561                         if (is_float) {
6562                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6563                                 i2f->dreg = mono_alloc_freg (cfg);
6564                                 i2f->sreg1 = ins->dreg;
6565                                 i2f->type = STACK_R8;
6566                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6567                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6568                                 MONO_ADD_INS (cfg->cbb, i2f);
6569
6570                                 ins = i2f;
6571                         }
6572
6573                         if (cfg->gen_write_barriers && is_ref)
6574                                 emit_write_barrier (cfg, args [0], args [1]);
6575                 }
6576                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 4 &&
6577                          fsig->params [1]->type == MONO_TYPE_I4) {
6578                         MonoInst *cmp, *ceq;
6579
6580                         if (!mono_arch_opcode_supported (OP_ATOMIC_CAS_I4))
6581                                 return NULL;
6582
6583                         /* int32 r = CAS (location, value, comparand); */
6584                         MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
6585                         ins->dreg = alloc_ireg (cfg);
6586                         ins->sreg1 = args [0]->dreg;
6587                         ins->sreg2 = args [1]->dreg;
6588                         ins->sreg3 = args [2]->dreg;
6589                         ins->type = STACK_I4;
6590                         MONO_ADD_INS (cfg->cbb, ins);
6591
6592                         /* bool result = r == comparand; */
6593                         MONO_INST_NEW (cfg, cmp, OP_ICOMPARE);
6594                         cmp->sreg1 = ins->dreg;
6595                         cmp->sreg2 = args [2]->dreg;
6596                         cmp->type = STACK_I4;
6597                         MONO_ADD_INS (cfg->cbb, cmp);
6598
6599                         MONO_INST_NEW (cfg, ceq, OP_ICEQ);
6600                         ceq->dreg = alloc_ireg (cfg);
6601                         ceq->type = STACK_I4;
6602                         MONO_ADD_INS (cfg->cbb, ceq);
6603
6604                         /* *success = result; */
6605                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, args [3]->dreg, 0, ceq->dreg);
6606
6607                         cfg->has_atomic_cas_i4 = TRUE;
6608                 }
6609                 else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0)
6610                         ins = emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6611
6612                 if (ins)
6613                         return ins;
6614         } else if (cmethod->klass->image == mono_defaults.corlib &&
6615                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6616                            (strcmp (cmethod->klass->name, "Volatile") == 0)) {
6617                 ins = NULL;
6618
6619                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Read") && fsig->param_count == 1) {
6620                         guint32 opcode = 0;
6621                         MonoType *t = fsig->params [0];
6622                         gboolean is_ref;
6623                         gboolean is_float = t->type == MONO_TYPE_R4 || t->type == MONO_TYPE_R8;
6624
6625                         g_assert (t->byref);
6626                         /* t is a byref type, so the reference check is more complicated */
6627                         is_ref = mini_type_is_reference (&mono_class_from_mono_type (t)->byval_arg);
6628                         if (t->type == MONO_TYPE_I1)
6629                                 opcode = OP_ATOMIC_LOAD_I1;
6630                         else if (t->type == MONO_TYPE_U1 || t->type == MONO_TYPE_BOOLEAN)
6631                                 opcode = OP_ATOMIC_LOAD_U1;
6632                         else if (t->type == MONO_TYPE_I2)
6633                                 opcode = OP_ATOMIC_LOAD_I2;
6634                         else if (t->type == MONO_TYPE_U2)
6635                                 opcode = OP_ATOMIC_LOAD_U2;
6636                         else if (t->type == MONO_TYPE_I4)
6637                                 opcode = OP_ATOMIC_LOAD_I4;
6638                         else if (t->type == MONO_TYPE_U4)
6639                                 opcode = OP_ATOMIC_LOAD_U4;
6640                         else if (t->type == MONO_TYPE_R4)
6641                                 opcode = OP_ATOMIC_LOAD_R4;
6642                         else if (t->type == MONO_TYPE_R8)
6643                                 opcode = OP_ATOMIC_LOAD_R8;
6644 #if SIZEOF_REGISTER == 8
6645                         else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_I)
6646                                 opcode = OP_ATOMIC_LOAD_I8;
6647                         else if (is_ref || t->type == MONO_TYPE_U8 || t->type == MONO_TYPE_U)
6648                                 opcode = OP_ATOMIC_LOAD_U8;
6649 #else
6650                         else if (t->type == MONO_TYPE_I)
6651                                 opcode = OP_ATOMIC_LOAD_I4;
6652                         else if (is_ref || t->type == MONO_TYPE_U)
6653                                 opcode = OP_ATOMIC_LOAD_U4;
6654 #endif
6655
6656                         if (opcode) {
6657                                 if (!mono_arch_opcode_supported (opcode))
6658                                         return NULL;
6659
6660                                 MONO_INST_NEW (cfg, ins, opcode);
6661                                 ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : (is_float ? mono_alloc_freg (cfg) : mono_alloc_ireg (cfg));
6662                                 ins->sreg1 = args [0]->dreg;
6663                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_ACQ;
6664                                 MONO_ADD_INS (cfg->cbb, ins);
6665
6666                                 switch (t->type) {
6667                                 case MONO_TYPE_BOOLEAN:
6668                                 case MONO_TYPE_I1:
6669                                 case MONO_TYPE_U1:
6670                                 case MONO_TYPE_I2:
6671                                 case MONO_TYPE_U2:
6672                                 case MONO_TYPE_I4:
6673                                 case MONO_TYPE_U4:
6674                                         ins->type = STACK_I4;
6675                                         break;
6676                                 case MONO_TYPE_I8:
6677                                 case MONO_TYPE_U8:
6678                                         ins->type = STACK_I8;
6679                                         break;
6680                                 case MONO_TYPE_I:
6681                                 case MONO_TYPE_U:
6682 #if SIZEOF_REGISTER == 8
6683                                         ins->type = STACK_I8;
6684 #else
6685                                         ins->type = STACK_I4;
6686 #endif
6687                                         break;
6688                                 case MONO_TYPE_R4:
6689                                         ins->type = cfg->r4_stack_type;
6690                                         break;
6691                                 case MONO_TYPE_R8:
6692                                         ins->type = STACK_R8;
6693                                         break;
6694                                 default:
6695                                         g_assert (is_ref);
6696                                         ins->type = STACK_OBJ;
6697                                         break;
6698                                 }
6699                         }
6700                 }
6701
6702                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Write") && fsig->param_count == 2) {
6703                         guint32 opcode = 0;
6704                         MonoType *t = fsig->params [0];
6705                         gboolean is_ref;
6706
6707                         g_assert (t->byref);
6708                         is_ref = mini_type_is_reference (&mono_class_from_mono_type (t)->byval_arg);
6709                         if (t->type == MONO_TYPE_I1)
6710                                 opcode = OP_ATOMIC_STORE_I1;
6711                         else if (t->type == MONO_TYPE_U1 || t->type == MONO_TYPE_BOOLEAN)
6712                                 opcode = OP_ATOMIC_STORE_U1;
6713                         else if (t->type == MONO_TYPE_I2)
6714                                 opcode = OP_ATOMIC_STORE_I2;
6715                         else if (t->type == MONO_TYPE_U2)
6716                                 opcode = OP_ATOMIC_STORE_U2;
6717                         else if (t->type == MONO_TYPE_I4)
6718                                 opcode = OP_ATOMIC_STORE_I4;
6719                         else if (t->type == MONO_TYPE_U4)
6720                                 opcode = OP_ATOMIC_STORE_U4;
6721                         else if (t->type == MONO_TYPE_R4)
6722                                 opcode = OP_ATOMIC_STORE_R4;
6723                         else if (t->type == MONO_TYPE_R8)
6724                                 opcode = OP_ATOMIC_STORE_R8;
6725 #if SIZEOF_REGISTER == 8
6726                         else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_I)
6727                                 opcode = OP_ATOMIC_STORE_I8;
6728                         else if (is_ref || t->type == MONO_TYPE_U8 || t->type == MONO_TYPE_U)
6729                                 opcode = OP_ATOMIC_STORE_U8;
6730 #else
6731                         else if (t->type == MONO_TYPE_I)
6732                                 opcode = OP_ATOMIC_STORE_I4;
6733                         else if (is_ref || t->type == MONO_TYPE_U)
6734                                 opcode = OP_ATOMIC_STORE_U4;
6735 #endif
6736
6737                         if (opcode) {
6738                                 if (!mono_arch_opcode_supported (opcode))
6739                                         return NULL;
6740
6741                                 MONO_INST_NEW (cfg, ins, opcode);
6742                                 ins->dreg = args [0]->dreg;
6743                                 ins->sreg1 = args [1]->dreg;
6744                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_REL;
6745                                 MONO_ADD_INS (cfg->cbb, ins);
6746
6747                                 if (cfg->gen_write_barriers && is_ref)
6748                                         emit_write_barrier (cfg, args [0], args [1]);
6749                         }
6750                 }
6751
6752                 if (ins)
6753                         return ins;
6754         } else if (cmethod->klass->image == mono_defaults.corlib &&
6755                            (strcmp (cmethod->klass->name_space, "System.Diagnostics") == 0) &&
6756                            (strcmp (cmethod->klass->name, "Debugger") == 0)) {
6757                 if (!strcmp (cmethod->name, "Break") && fsig->param_count == 0) {
6758                         if (should_insert_brekpoint (cfg->method)) {
6759                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
6760                         } else {
6761                                 MONO_INST_NEW (cfg, ins, OP_NOP);
6762                                 MONO_ADD_INS (cfg->cbb, ins);
6763                         }
6764                         return ins;
6765                 }
6766         } else if (cmethod->klass->image == mono_defaults.corlib &&
6767                    (strcmp (cmethod->klass->name_space, "System") == 0) &&
6768                    (strcmp (cmethod->klass->name, "Environment") == 0)) {
6769                 if (!strcmp (cmethod->name, "get_IsRunningOnWindows") && fsig->param_count == 0) {
6770 #ifdef TARGET_WIN32
6771                         EMIT_NEW_ICONST (cfg, ins, 1);
6772 #else
6773                         EMIT_NEW_ICONST (cfg, ins, 0);
6774 #endif
6775                 }
6776         } else if (cmethod->klass->image == mono_defaults.corlib &&
6777                            (strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
6778                            (strcmp (cmethod->klass->name, "Assembly") == 0)) {
6779                 if (cfg->llvm_only && !strcmp (cmethod->name, "GetExecutingAssembly")) {
6780                         /* No stack walks are currently available, so implement this as an intrinsic */
6781                         MonoInst *assembly_ins;
6782
6783                         EMIT_NEW_AOTCONST (cfg, assembly_ins, MONO_PATCH_INFO_IMAGE, cfg->method->klass->image);
6784                         ins = mono_emit_jit_icall (cfg, mono_get_assembly_object, &assembly_ins);
6785                         return ins;
6786                 }
6787         } else if (cmethod->klass->image == mono_defaults.corlib &&
6788                            (strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
6789                            (strcmp (cmethod->klass->name, "MethodBase") == 0)) {
6790                 if (cfg->llvm_only && !strcmp (cmethod->name, "GetCurrentMethod")) {
6791                         /* No stack walks are currently available, so implement this as an intrinsic */
6792                         MonoInst *method_ins;
6793                         MonoMethod *declaring = cfg->method;
6794
6795                         /* This returns the declaring generic method */
6796                         if (declaring->is_inflated)
6797                                 declaring = ((MonoMethodInflated*)cfg->method)->declaring;
6798                         EMIT_NEW_AOTCONST (cfg, method_ins, MONO_PATCH_INFO_METHODCONST, declaring);
6799                         ins = mono_emit_jit_icall (cfg, mono_get_method_object, &method_ins);
6800                         cfg->no_inline = TRUE;
6801                         if (cfg->method != cfg->current_method)
6802                                 inline_failure (cfg, "MethodBase:GetCurrentMethod ()");
6803                         return ins;
6804                 }
6805         } else if (cmethod->klass == mono_defaults.math_class) {
6806                 /* 
6807                  * There is general branchless code for Min/Max, but it does not work for 
6808                  * all inputs:
6809                  * http://everything2.com/?node_id=1051618
6810                  */
6811         } else if (((!strcmp (cmethod->klass->image->assembly->aname.name, "MonoMac") ||
6812                     !strcmp (cmethod->klass->image->assembly->aname.name, "monotouch")) &&
6813                                 !strcmp (cmethod->klass->name_space, "XamCore.ObjCRuntime") &&
6814                                 !strcmp (cmethod->klass->name, "Selector")) ||
6815                            ((!strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.iOS") ||
6816                                  !strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.Mac")) &&
6817                                 !strcmp (cmethod->klass->name_space, "ObjCRuntime") &&
6818                                 !strcmp (cmethod->klass->name, "Selector"))
6819                            ) {
6820                 if ((cfg->backend->have_objc_get_selector || cfg->compile_llvm) &&
6821                         !strcmp (cmethod->name, "GetHandle") && fsig->param_count == 1 &&
6822                     (args [0]->opcode == OP_GOT_ENTRY || args [0]->opcode == OP_AOTCONST) &&
6823                     cfg->compile_aot) {
6824                         MonoInst *pi;
6825                         MonoJumpInfoToken *ji;
6826                         char *s;
6827
6828                         if (args [0]->opcode == OP_GOT_ENTRY) {
6829                                 pi = (MonoInst *)args [0]->inst_p1;
6830                                 g_assert (pi->opcode == OP_PATCH_INFO);
6831                                 g_assert (GPOINTER_TO_INT (pi->inst_p1) == MONO_PATCH_INFO_LDSTR);
6832                                 ji = (MonoJumpInfoToken *)pi->inst_p0;
6833                         } else {
6834                                 g_assert (GPOINTER_TO_INT (args [0]->inst_p1) == MONO_PATCH_INFO_LDSTR);
6835                                 ji = (MonoJumpInfoToken *)args [0]->inst_p0;
6836                         }
6837
6838                         NULLIFY_INS (args [0]);
6839
6840                         s = mono_ldstr_utf8 (ji->image, mono_metadata_token_index (ji->token), &cfg->error);
6841                         return_val_if_nok (&cfg->error, NULL);
6842
6843                         MONO_INST_NEW (cfg, ins, OP_OBJC_GET_SELECTOR);
6844                         ins->dreg = mono_alloc_ireg (cfg);
6845                         // FIXME: Leaks
6846                         ins->inst_p0 = s;
6847                         MONO_ADD_INS (cfg->cbb, ins);
6848                         return ins;
6849                 }
6850         }
6851
6852 #ifdef MONO_ARCH_SIMD_INTRINSICS
6853         if (cfg->opt & MONO_OPT_SIMD) {
6854                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
6855                 if (ins)
6856                         return ins;
6857         }
6858 #endif
6859
6860         ins = mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
6861         if (ins)
6862                 return ins;
6863
6864         if (COMPILE_LLVM (cfg)) {
6865                 ins = llvm_emit_inst_for_method (cfg, cmethod, fsig, args);
6866                 if (ins)
6867                         return ins;
6868         }
6869
6870         return mono_arch_emit_inst_for_method (cfg, cmethod, fsig, args);
6871 }
6872
6873 /*
6874  * This entry point could be used later for arbitrary method
6875  * redirection.
6876  */
6877 inline static MonoInst*
6878 mini_redirect_call (MonoCompile *cfg, MonoMethod *method,  
6879                                         MonoMethodSignature *signature, MonoInst **args, MonoInst *this_ins)
6880 {
6881         if (method->klass == mono_defaults.string_class) {
6882                 /* managed string allocation support */
6883                 if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && !(cfg->opt & MONO_OPT_SHARED)) {
6884                         MonoInst *iargs [2];
6885                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
6886                         MonoMethod *managed_alloc = NULL;
6887
6888                         g_assert (vtable); /*Should not fail since it System.String*/
6889 #ifndef MONO_CROSS_COMPILE
6890                         managed_alloc = mono_gc_get_managed_allocator (method->klass, FALSE, FALSE);
6891 #endif
6892                         if (!managed_alloc)
6893                                 return NULL;
6894                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
6895                         iargs [1] = args [0];
6896                         return mono_emit_method_call (cfg, managed_alloc, iargs, this_ins);
6897                 }
6898         }
6899         return NULL;
6900 }
6901
6902 static void
6903 mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp)
6904 {
6905         MonoInst *store, *temp;
6906         int i;
6907
6908         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
6909                 MonoType *argtype = (sig->hasthis && (i == 0)) ? type_from_stack_type (*sp) : sig->params [i - sig->hasthis];
6910
6911                 /*
6912                  * FIXME: We should use *args++ = sp [0], but that would mean the arg
6913                  * would be different than the MonoInst's used to represent arguments, and
6914                  * the ldelema implementation can't deal with that.
6915                  * Solution: When ldelema is used on an inline argument, create a var for 
6916                  * it, emit ldelema on that var, and emit the saving code below in
6917                  * inline_method () if needed.
6918                  */
6919                 temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
6920                 cfg->args [i] = temp;
6921                 /* This uses cfg->args [i] which is set by the preceeding line */
6922                 EMIT_NEW_ARGSTORE (cfg, store, i, *sp);
6923                 store->cil_code = sp [0]->cil_code;
6924                 sp++;
6925         }
6926 }
6927
6928 #define MONO_INLINE_CALLED_LIMITED_METHODS 1
6929 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
6930
6931 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6932 static gboolean
6933 check_inline_called_method_name_limit (MonoMethod *called_method)
6934 {
6935         int strncmp_result;
6936         static const char *limit = NULL;
6937         
6938         if (limit == NULL) {
6939                 const char *limit_string = g_getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
6940
6941                 if (limit_string != NULL)
6942                         limit = limit_string;
6943                 else
6944                         limit = "";
6945         }
6946
6947         if (limit [0] != '\0') {
6948                 char *called_method_name = mono_method_full_name (called_method, TRUE);
6949
6950                 strncmp_result = strncmp (called_method_name, limit, strlen (limit));
6951                 g_free (called_method_name);
6952         
6953                 //return (strncmp_result <= 0);
6954                 return (strncmp_result == 0);
6955         } else {
6956                 return TRUE;
6957         }
6958 }
6959 #endif
6960
6961 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6962 static gboolean
6963 check_inline_caller_method_name_limit (MonoMethod *caller_method)
6964 {
6965         int strncmp_result;
6966         static const char *limit = NULL;
6967         
6968         if (limit == NULL) {
6969                 const char *limit_string = g_getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
6970                 if (limit_string != NULL) {
6971                         limit = limit_string;
6972                 } else {
6973                         limit = "";
6974                 }
6975         }
6976
6977         if (limit [0] != '\0') {
6978                 char *caller_method_name = mono_method_full_name (caller_method, TRUE);
6979
6980                 strncmp_result = strncmp (caller_method_name, limit, strlen (limit));
6981                 g_free (caller_method_name);
6982         
6983                 //return (strncmp_result <= 0);
6984                 return (strncmp_result == 0);
6985         } else {
6986                 return TRUE;
6987         }
6988 }
6989 #endif
6990
6991 static void
6992 emit_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6993 {
6994         static double r8_0 = 0.0;
6995         static float r4_0 = 0.0;
6996         MonoInst *ins;
6997         int t;
6998
6999         rtype = mini_get_underlying_type (rtype);
7000         t = rtype->type;
7001
7002         if (rtype->byref) {
7003                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
7004         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
7005                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
7006         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
7007                 MONO_EMIT_NEW_I8CONST (cfg, dreg, 0);
7008         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
7009                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
7010                 ins->type = STACK_R4;
7011                 ins->inst_p0 = (void*)&r4_0;
7012                 ins->dreg = dreg;
7013                 MONO_ADD_INS (cfg->cbb, ins);
7014         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
7015                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
7016                 ins->type = STACK_R8;
7017                 ins->inst_p0 = (void*)&r8_0;
7018                 ins->dreg = dreg;
7019                 MONO_ADD_INS (cfg->cbb, ins);
7020         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
7021                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
7022                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
7023         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
7024                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
7025         } else {
7026                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
7027         }
7028 }
7029
7030 static void
7031 emit_dummy_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
7032 {
7033         int t;
7034
7035         rtype = mini_get_underlying_type (rtype);
7036         t = rtype->type;
7037
7038         if (rtype->byref) {
7039                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_PCONST);
7040         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
7041                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_ICONST);
7042         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
7043                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_I8CONST);
7044         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
7045                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R4CONST);
7046         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
7047                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R8CONST);
7048         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
7049                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
7050                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
7051         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
7052                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
7053         } else {
7054                 emit_init_rvar (cfg, dreg, rtype);
7055         }
7056 }
7057
7058 /* If INIT is FALSE, emit dummy initialization statements to keep the IR valid */
7059 static void
7060 emit_init_local (MonoCompile *cfg, int local, MonoType *type, gboolean init)
7061 {
7062         MonoInst *var = cfg->locals [local];
7063         if (COMPILE_SOFT_FLOAT (cfg)) {
7064                 MonoInst *store;
7065                 int reg = alloc_dreg (cfg, (MonoStackType)var->type);
7066                 emit_init_rvar (cfg, reg, type);
7067                 EMIT_NEW_LOCSTORE (cfg, store, local, cfg->cbb->last_ins);
7068         } else {
7069                 if (init)
7070                         emit_init_rvar (cfg, var->dreg, type);
7071                 else
7072                         emit_dummy_init_rvar (cfg, var->dreg, type);
7073         }
7074 }
7075
7076 /*
7077  * inline_method:
7078  *
7079  *   Return the cost of inlining CMETHOD.
7080  */
7081 static int
7082 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
7083                            guchar *ip, guint real_offset, gboolean inline_always)
7084 {
7085         MonoError error;
7086         MonoInst *ins, *rvar = NULL;
7087         MonoMethodHeader *cheader;
7088         MonoBasicBlock *ebblock, *sbblock;
7089         int i, costs;
7090         MonoMethod *prev_inlined_method;
7091         MonoInst **prev_locals, **prev_args;
7092         MonoType **prev_arg_types;
7093         guint prev_real_offset;
7094         GHashTable *prev_cbb_hash;
7095         MonoBasicBlock **prev_cil_offset_to_bb;
7096         MonoBasicBlock *prev_cbb;
7097         const unsigned char *prev_ip;
7098         unsigned char *prev_cil_start;
7099         guint32 prev_cil_offset_to_bb_len;
7100         MonoMethod *prev_current_method;
7101         MonoGenericContext *prev_generic_context;
7102         gboolean ret_var_set, prev_ret_var_set, prev_disable_inline, virtual_ = FALSE;
7103
7104         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
7105
7106 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
7107         if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod))
7108                 return 0;
7109 #endif
7110 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
7111         if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method))
7112                 return 0;
7113 #endif
7114
7115         if (!fsig)
7116                 fsig = mono_method_signature (cmethod);
7117
7118         if (cfg->verbose_level > 2)
7119                 printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
7120
7121         if (!cmethod->inline_info) {
7122                 cfg->stat_inlineable_methods++;
7123                 cmethod->inline_info = 1;
7124         }
7125
7126         /* allocate local variables */
7127         cheader = mono_method_get_header_checked (cmethod, &error);
7128         if (!cheader) {
7129                 if (inline_always) {
7130                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
7131                         mono_error_move (&cfg->error, &error);
7132                 } else {
7133                         mono_error_cleanup (&error);
7134                 }
7135                 return 0;
7136         }
7137
7138         /*Must verify before creating locals as it can cause the JIT to assert.*/
7139         if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
7140                 mono_metadata_free_mh (cheader);
7141                 return 0;
7142         }
7143
7144         /* allocate space to store the return value */
7145         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
7146                 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
7147         }
7148
7149         prev_locals = cfg->locals;
7150         cfg->locals = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));
7151         for (i = 0; i < cheader->num_locals; ++i)
7152                 cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
7153
7154         /* allocate start and end blocks */
7155         /* This is needed so if the inline is aborted, we can clean up */
7156         NEW_BBLOCK (cfg, sbblock);
7157         sbblock->real_offset = real_offset;
7158
7159         NEW_BBLOCK (cfg, ebblock);
7160         ebblock->block_num = cfg->num_bblocks++;
7161         ebblock->real_offset = real_offset;
7162
7163         prev_args = cfg->args;
7164         prev_arg_types = cfg->arg_types;
7165         prev_inlined_method = cfg->inlined_method;
7166         cfg->inlined_method = cmethod;
7167         cfg->ret_var_set = FALSE;
7168         cfg->inline_depth ++;
7169         prev_real_offset = cfg->real_offset;
7170         prev_cbb_hash = cfg->cbb_hash;
7171         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
7172         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
7173         prev_cil_start = cfg->cil_start;
7174         prev_ip = cfg->ip;
7175         prev_cbb = cfg->cbb;
7176         prev_current_method = cfg->current_method;
7177         prev_generic_context = cfg->generic_context;
7178         prev_ret_var_set = cfg->ret_var_set;
7179         prev_disable_inline = cfg->disable_inline;
7180
7181         if (ip && *ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
7182                 virtual_ = TRUE;
7183
7184         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, sp, real_offset, virtual_);
7185
7186         ret_var_set = cfg->ret_var_set;
7187
7188         cfg->inlined_method = prev_inlined_method;
7189         cfg->real_offset = prev_real_offset;
7190         cfg->cbb_hash = prev_cbb_hash;
7191         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
7192         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
7193         cfg->cil_start = prev_cil_start;
7194         cfg->ip = prev_ip;
7195         cfg->locals = prev_locals;
7196         cfg->args = prev_args;
7197         cfg->arg_types = prev_arg_types;
7198         cfg->current_method = prev_current_method;
7199         cfg->generic_context = prev_generic_context;
7200         cfg->ret_var_set = prev_ret_var_set;
7201         cfg->disable_inline = prev_disable_inline;
7202         cfg->inline_depth --;
7203
7204         if ((costs >= 0 && costs < 60) || inline_always || (costs >= 0 && (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))) {
7205                 if (cfg->verbose_level > 2)
7206                         printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
7207                 
7208                 cfg->stat_inlined_methods++;
7209
7210                 /* always add some code to avoid block split failures */
7211                 MONO_INST_NEW (cfg, ins, OP_NOP);
7212                 MONO_ADD_INS (prev_cbb, ins);
7213
7214                 prev_cbb->next_bb = sbblock;
7215                 link_bblock (cfg, prev_cbb, sbblock);
7216
7217                 /* 
7218                  * Get rid of the begin and end bblocks if possible to aid local
7219                  * optimizations.
7220                  */
7221                 mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
7222
7223                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
7224                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
7225
7226                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
7227                         MonoBasicBlock *prev = ebblock->in_bb [0];
7228
7229                         if (prev->next_bb == ebblock) {
7230                                 mono_merge_basic_blocks (cfg, prev, ebblock);
7231                                 cfg->cbb = prev;
7232                                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
7233                                         mono_merge_basic_blocks (cfg, prev_cbb, prev);
7234                                         cfg->cbb = prev_cbb;
7235                                 }
7236                         } else {
7237                                 /* There could be a bblock after 'prev', and making 'prev' the current bb could cause problems */
7238                                 cfg->cbb = ebblock;
7239                         }
7240                 } else {
7241                         /* 
7242                          * Its possible that the rvar is set in some prev bblock, but not in others.
7243                          * (#1835).
7244                          */
7245                         if (rvar) {
7246                                 MonoBasicBlock *bb;
7247
7248                                 for (i = 0; i < ebblock->in_count; ++i) {
7249                                         bb = ebblock->in_bb [i];
7250
7251                                         if (bb->last_ins && bb->last_ins->opcode == OP_NOT_REACHED) {
7252                                                 cfg->cbb = bb;
7253
7254                                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
7255                                         }
7256                                 }
7257                         }
7258
7259                         cfg->cbb = ebblock;
7260                 }
7261
7262                 if (rvar) {
7263                         /*
7264                          * If the inlined method contains only a throw, then the ret var is not 
7265                          * set, so set it to a dummy value.
7266                          */
7267                         if (!ret_var_set)
7268                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
7269
7270                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
7271                         *sp++ = ins;
7272                 }
7273                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
7274                 return costs + 1;
7275         } else {
7276                 if (cfg->verbose_level > 2)
7277                         printf ("INLINE ABORTED %s (cost %d)\n", mono_method_full_name (cmethod, TRUE), costs);
7278                 cfg->exception_type = MONO_EXCEPTION_NONE;
7279
7280                 /* This gets rid of the newly added bblocks */
7281                 cfg->cbb = prev_cbb;
7282         }
7283         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
7284         return 0;
7285 }
7286
7287 /*
7288  * Some of these comments may well be out-of-date.
7289  * Design decisions: we do a single pass over the IL code (and we do bblock 
7290  * splitting/merging in the few cases when it's required: a back jump to an IL
7291  * address that was not already seen as bblock starting point).
7292  * Code is validated as we go (full verification is still better left to metadata/verify.c).
7293  * Complex operations are decomposed in simpler ones right away. We need to let the 
7294  * arch-specific code peek and poke inside this process somehow (except when the 
7295  * optimizations can take advantage of the full semantic info of coarse opcodes).
7296  * All the opcodes of the form opcode.s are 'normalized' to opcode.
7297  * MonoInst->opcode initially is the IL opcode or some simplification of that 
7298  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
7299  * opcode with value bigger than OP_LAST.
7300  * At this point the IR can be handed over to an interpreter, a dumb code generator
7301  * or to the optimizing code generator that will translate it to SSA form.
7302  *
7303  * Profiling directed optimizations.
7304  * We may compile by default with few or no optimizations and instrument the code
7305  * or the user may indicate what methods to optimize the most either in a config file
7306  * or through repeated runs where the compiler applies offline the optimizations to 
7307  * each method and then decides if it was worth it.
7308  */
7309
7310 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
7311 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
7312 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
7313 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
7314 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
7315 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
7316 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
7317 #define CHECK_TYPELOAD(klass) if (!(klass) || mono_class_has_failure (klass)) TYPE_LOAD_ERROR ((klass))
7318
7319 /* offset from br.s -> br like opcodes */
7320 #define BIG_BRANCH_OFFSET 13
7321
7322 static gboolean
7323 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
7324 {
7325         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
7326
7327         return b == NULL || b == bb;
7328 }
7329
7330 static int
7331 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
7332 {
7333         unsigned char *ip = start;
7334         unsigned char *target;
7335         int i;
7336         guint cli_addr;
7337         MonoBasicBlock *bblock;
7338         const MonoOpcode *opcode;
7339
7340         while (ip < end) {
7341                 cli_addr = ip - start;
7342                 i = mono_opcode_value ((const guint8 **)&ip, end);
7343                 if (i < 0)
7344                         UNVERIFIED;
7345                 opcode = &mono_opcodes [i];
7346                 switch (opcode->argument) {
7347                 case MonoInlineNone:
7348                         ip++; 
7349                         break;
7350                 case MonoInlineString:
7351                 case MonoInlineType:
7352                 case MonoInlineField:
7353                 case MonoInlineMethod:
7354                 case MonoInlineTok:
7355                 case MonoInlineSig:
7356                 case MonoShortInlineR:
7357                 case MonoInlineI:
7358                         ip += 5;
7359                         break;
7360                 case MonoInlineVar:
7361                         ip += 3;
7362                         break;
7363                 case MonoShortInlineVar:
7364                 case MonoShortInlineI:
7365                         ip += 2;
7366                         break;
7367                 case MonoShortInlineBrTarget:
7368                         target = start + cli_addr + 2 + (signed char)ip [1];
7369                         GET_BBLOCK (cfg, bblock, target);
7370                         ip += 2;
7371                         if (ip < end)
7372                                 GET_BBLOCK (cfg, bblock, ip);
7373                         break;
7374                 case MonoInlineBrTarget:
7375                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
7376                         GET_BBLOCK (cfg, bblock, target);
7377                         ip += 5;
7378                         if (ip < end)
7379                                 GET_BBLOCK (cfg, bblock, ip);
7380                         break;
7381                 case MonoInlineSwitch: {
7382                         guint32 n = read32 (ip + 1);
7383                         guint32 j;
7384                         ip += 5;
7385                         cli_addr += 5 + 4 * n;
7386                         target = start + cli_addr;
7387                         GET_BBLOCK (cfg, bblock, target);
7388                         
7389                         for (j = 0; j < n; ++j) {
7390                                 target = start + cli_addr + (gint32)read32 (ip);
7391                                 GET_BBLOCK (cfg, bblock, target);
7392                                 ip += 4;
7393                         }
7394                         break;
7395                 }
7396                 case MonoInlineR:
7397                 case MonoInlineI8:
7398                         ip += 9;
7399                         break;
7400                 default:
7401                         g_assert_not_reached ();
7402                 }
7403
7404                 if (i == CEE_THROW) {
7405                         unsigned char *bb_start = ip - 1;
7406                         
7407                         /* Find the start of the bblock containing the throw */
7408                         bblock = NULL;
7409                         while ((bb_start >= start) && !bblock) {
7410                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
7411                                 bb_start --;
7412                         }
7413                         if (bblock)
7414                                 bblock->out_of_line = 1;
7415                 }
7416         }
7417         return 0;
7418 unverified:
7419 exception_exit:
7420         *pos = ip;
7421         return 1;
7422 }
7423
7424 static inline MonoMethod *
7425 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context, MonoError *error)
7426 {
7427         MonoMethod *method;
7428
7429         mono_error_init (error);
7430
7431         if (m->wrapper_type != MONO_WRAPPER_NONE) {
7432                 method = (MonoMethod *)mono_method_get_wrapper_data (m, token);
7433                 if (context) {
7434                         method = mono_class_inflate_generic_method_checked (method, context, error);
7435                 }
7436         } else {
7437                 method = mono_get_method_checked (m->klass->image, token, klass, context, error);
7438         }
7439
7440         return method;
7441 }
7442
7443 static inline MonoMethod *
7444 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
7445 {
7446         MonoError error;
7447         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context, cfg ? &cfg->error : &error);
7448
7449         if (method && cfg && !cfg->gshared && mono_class_is_open_constructed_type (&method->klass->byval_arg)) {
7450                 mono_error_set_bad_image (&cfg->error, cfg->method->klass->image, "Method with open type while not compiling gshared");
7451                 method = NULL;
7452         }
7453
7454         if (!method && !cfg)
7455                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
7456
7457         return method;
7458 }
7459
7460 static inline MonoClass*
7461 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
7462 {
7463         MonoError error;
7464         MonoClass *klass;
7465
7466         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7467                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
7468                 if (context) {
7469                         klass = mono_class_inflate_generic_class_checked (klass, context, &error);
7470                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7471                 }
7472         } else {
7473                 klass = mono_class_get_and_inflate_typespec_checked (method->klass->image, token, context, &error);
7474                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
7475         }
7476         if (klass)
7477                 mono_class_init (klass);
7478         return klass;
7479 }
7480
7481 static inline MonoMethodSignature*
7482 mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context, MonoError *error)
7483 {
7484         MonoMethodSignature *fsig;
7485
7486         mono_error_init (error);
7487         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7488                 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
7489         } else {
7490                 fsig = mono_metadata_parse_signature_checked (method->klass->image, token, error);
7491                 return_val_if_nok (error, NULL);
7492         }
7493         if (context) {
7494                 fsig = mono_inflate_generic_signature(fsig, context, error);
7495         }
7496         return fsig;
7497 }
7498
7499 static MonoMethod*
7500 throw_exception (void)
7501 {
7502         static MonoMethod *method = NULL;
7503
7504         if (!method) {
7505                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
7506                 method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
7507         }
7508         g_assert (method);
7509         return method;
7510 }
7511
7512 static void
7513 emit_throw_exception (MonoCompile *cfg, MonoException *ex)
7514 {
7515         MonoMethod *thrower = throw_exception ();
7516         MonoInst *args [1];
7517
7518         EMIT_NEW_PCONST (cfg, args [0], ex);
7519         mono_emit_method_call (cfg, thrower, args, NULL);
7520 }
7521
7522 /*
7523  * Return the original method is a wrapper is specified. We can only access 
7524  * the custom attributes from the original method.
7525  */
7526 static MonoMethod*
7527 get_original_method (MonoMethod *method)
7528 {
7529         if (method->wrapper_type == MONO_WRAPPER_NONE)
7530                 return method;
7531
7532         /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
7533         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
7534                 return NULL;
7535
7536         /* in other cases we need to find the original method */
7537         return mono_marshal_method_from_wrapper (method);
7538 }
7539
7540 static void
7541 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field)
7542 {
7543         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7544         MonoException *ex = mono_security_core_clr_is_field_access_allowed (get_original_method (caller), field);
7545         if (ex)
7546                 emit_throw_exception (cfg, ex);
7547 }
7548
7549 static void
7550 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
7551 {
7552         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7553         MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
7554         if (ex)
7555                 emit_throw_exception (cfg, ex);
7556 }
7557
7558 /*
7559  * Check that the IL instructions at ip are the array initialization
7560  * sequence and return the pointer to the data and the size.
7561  */
7562 static const char*
7563 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
7564 {
7565         /*
7566          * newarr[System.Int32]
7567          * dup
7568          * ldtoken field valuetype ...
7569          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
7570          */
7571         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
7572                 MonoError error;
7573                 guint32 token = read32 (ip + 7);
7574                 guint32 field_token = read32 (ip + 2);
7575                 guint32 field_index = field_token & 0xffffff;
7576                 guint32 rva;
7577                 const char *data_ptr;
7578                 int size = 0;
7579                 MonoMethod *cmethod;
7580                 MonoClass *dummy_class;
7581                 MonoClassField *field = mono_field_from_token_checked (method->klass->image, field_token, &dummy_class, NULL, &error);
7582                 int dummy_align;
7583
7584                 if (!field) {
7585                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7586                         return NULL;
7587                 }
7588
7589                 *out_field_token = field_token;
7590
7591                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
7592                 if (!cmethod)
7593                         return NULL;
7594                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
7595                         return NULL;
7596                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
7597                 case MONO_TYPE_BOOLEAN:
7598                 case MONO_TYPE_I1:
7599                 case MONO_TYPE_U1:
7600                         size = 1; break;
7601                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
7602 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
7603                 case MONO_TYPE_CHAR:
7604                 case MONO_TYPE_I2:
7605                 case MONO_TYPE_U2:
7606                         size = 2; break;
7607                 case MONO_TYPE_I4:
7608                 case MONO_TYPE_U4:
7609                 case MONO_TYPE_R4:
7610                         size = 4; break;
7611                 case MONO_TYPE_R8:
7612                 case MONO_TYPE_I8:
7613                 case MONO_TYPE_U8:
7614                         size = 8; break;
7615 #endif
7616                 default:
7617                         return NULL;
7618                 }
7619                 size *= len;
7620                 if (size > mono_type_size (field->type, &dummy_align))
7621                     return NULL;
7622                 *out_size = size;
7623                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
7624                 if (!image_is_dynamic (method->klass->image)) {
7625                         field_index = read32 (ip + 2) & 0xffffff;
7626                         mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
7627                         data_ptr = mono_image_rva_map (method->klass->image, rva);
7628                         /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
7629                         /* for aot code we do the lookup on load */
7630                         if (aot && data_ptr)
7631                                 return (const char *)GUINT_TO_POINTER (rva);
7632                 } else {
7633                         /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
7634                         g_assert (!aot);
7635                         data_ptr = mono_field_get_data (field);
7636                 }
7637                 return data_ptr;
7638         }
7639         return NULL;
7640 }
7641
7642 static void
7643 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
7644 {
7645         MonoError error;
7646         char *method_fname = mono_method_full_name (method, TRUE);
7647         char *method_code;
7648         MonoMethodHeader *header = mono_method_get_header_checked (method, &error);
7649
7650         if (!header) {
7651                 method_code = g_strdup_printf ("could not parse method body due to %s", mono_error_get_message (&error));
7652                 mono_error_cleanup (&error);
7653         } else if (header->code_size == 0)
7654                 method_code = g_strdup ("method body is empty.");
7655         else
7656                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
7657         mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code));
7658         g_free (method_fname);
7659         g_free (method_code);
7660         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
7661 }
7662
7663 static void
7664 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
7665 {
7666         MonoInst *ins;
7667         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
7668         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
7669                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
7670                 /* Optimize reg-reg moves away */
7671                 /* 
7672                  * Can't optimize other opcodes, since sp[0] might point to
7673                  * the last ins of a decomposed opcode.
7674                  */
7675                 sp [0]->dreg = (cfg)->locals [n]->dreg;
7676         } else {
7677                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
7678         }
7679 }
7680
7681 /*
7682  * ldloca inhibits many optimizations so try to get rid of it in common
7683  * cases.
7684  */
7685 static inline unsigned char *
7686 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
7687 {
7688         int local, token;
7689         MonoClass *klass;
7690         MonoType *type;
7691
7692         if (size == 1) {
7693                 local = ip [1];
7694                 ip += 2;
7695         } else {
7696                 local = read16 (ip + 2);
7697                 ip += 4;
7698         }
7699         
7700         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
7701                 /* From the INITOBJ case */
7702                 token = read32 (ip + 2);
7703                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
7704                 CHECK_TYPELOAD (klass);
7705                 type = mini_get_underlying_type (&klass->byval_arg);
7706                 emit_init_local (cfg, local, type, TRUE);
7707                 return ip + 6;
7708         }
7709  exception_exit:
7710         return NULL;
7711 }
7712
7713 static MonoInst*
7714 emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used, MonoInst **sp)
7715 {
7716         MonoInst *icall_args [16];
7717         MonoInst *call_target, *ins, *vtable_ins;
7718         int arg_reg, this_reg, vtable_reg;
7719         gboolean is_iface = cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE;
7720         gboolean is_gsharedvt = cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig);
7721         gboolean variant_iface = FALSE;
7722         guint32 slot;
7723         int offset;
7724
7725         /*
7726          * In llvm-only mode, vtables contain function descriptors instead of
7727          * method addresses/trampolines.
7728          */
7729         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
7730
7731         if (is_iface)
7732                 slot = mono_method_get_imt_slot (cmethod);
7733         else
7734                 slot = mono_method_get_vtable_index (cmethod);
7735
7736         this_reg = sp [0]->dreg;
7737
7738         if (is_iface && mono_class_has_variant_generic_params (cmethod->klass))
7739                 variant_iface = TRUE;
7740
7741         if (!fsig->generic_param_count && !is_iface && !is_gsharedvt) {
7742                 /*
7743                  * The simplest case, a normal virtual call.
7744                  */
7745                 int slot_reg = alloc_preg (cfg);
7746                 int addr_reg = alloc_preg (cfg);
7747                 int arg_reg = alloc_preg (cfg);
7748                 MonoBasicBlock *non_null_bb;
7749
7750                 vtable_reg = alloc_preg (cfg);
7751                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7752                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) + (slot * SIZEOF_VOID_P);
7753
7754                 /* Load the vtable slot, which contains a function descriptor. */
7755                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7756
7757                 NEW_BBLOCK (cfg, non_null_bb);
7758
7759                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, slot_reg, 0);
7760                 cfg->cbb->last_ins->flags |= MONO_INST_LIKELY;
7761                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, non_null_bb);
7762
7763                 /* Slow path */
7764                 // FIXME: Make the wrapper use the preserveall cconv
7765                 // FIXME: Use one icall per slot for small slot numbers ?
7766                 icall_args [0] = vtable_ins;
7767                 EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7768                 /* Make the icall return the vtable slot value to save some code space */
7769                 ins = mono_emit_jit_icall (cfg, mono_init_vtable_slot, icall_args);
7770                 ins->dreg = slot_reg;
7771                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, non_null_bb);
7772
7773                 /* Fastpath */
7774                 MONO_START_BB (cfg, non_null_bb);
7775                 /* Load the address + arg from the vtable slot */
7776                 EMIT_NEW_LOAD_MEMBASE (cfg, call_target, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7777                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, arg_reg, slot_reg, SIZEOF_VOID_P);
7778
7779                 return emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
7780         }
7781
7782         if (!fsig->generic_param_count && is_iface && !variant_iface && !is_gsharedvt) {
7783                 /*
7784                  * A simple interface call
7785                  *
7786                  * We make a call through an imt slot to obtain the function descriptor we need to call.
7787                  * The imt slot contains a function descriptor for a runtime function + arg.
7788                  */
7789                 int slot_reg = alloc_preg (cfg);
7790                 int addr_reg = alloc_preg (cfg);
7791                 int arg_reg = alloc_preg (cfg);
7792                 MonoInst *thunk_addr_ins, *thunk_arg_ins, *ftndesc_ins;
7793
7794                 vtable_reg = alloc_preg (cfg);
7795                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7796                 offset = ((gint32)slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
7797
7798                 /*
7799                  * The slot is already initialized when the vtable is created so there is no need
7800                  * to check it here.
7801                  */
7802
7803                 /* Load the imt slot, which contains a function descriptor. */
7804                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7805
7806                 /* Load the address + arg of the imt thunk from the imt slot */
7807                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_addr_ins, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7808                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_arg_ins, OP_LOAD_MEMBASE, arg_reg, slot_reg, SIZEOF_VOID_P);
7809                 /*
7810                  * IMT thunks in llvm-only mode are C functions which take an info argument
7811                  * plus the imt method and return the ftndesc to call.
7812                  */
7813                 icall_args [0] = thunk_arg_ins;
7814                 icall_args [1] = emit_get_rgctx_method (cfg, context_used,
7815                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7816                 ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_trampoline, icall_args, thunk_addr_ins, NULL, NULL);
7817
7818                 return emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
7819         }
7820
7821         if ((fsig->generic_param_count || variant_iface) && !is_gsharedvt) {
7822                 /*
7823                  * This is similar to the interface case, the vtable slot points to an imt thunk which is
7824                  * dynamically extended as more instantiations are discovered.
7825                  * This handles generic virtual methods both on classes and interfaces.
7826                  */
7827                 int slot_reg = alloc_preg (cfg);
7828                 int addr_reg = alloc_preg (cfg);
7829                 int arg_reg = alloc_preg (cfg);
7830                 int ftndesc_reg = alloc_preg (cfg);
7831                 MonoInst *thunk_addr_ins, *thunk_arg_ins, *ftndesc_ins;
7832                 MonoBasicBlock *slowpath_bb, *end_bb;
7833
7834                 NEW_BBLOCK (cfg, slowpath_bb);
7835                 NEW_BBLOCK (cfg, end_bb);
7836
7837                 vtable_reg = alloc_preg (cfg);
7838                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7839                 if (is_iface)
7840                         offset = ((gint32)slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
7841                 else
7842                         offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) + (slot * SIZEOF_VOID_P);
7843
7844                 /* Load the slot, which contains a function descriptor. */
7845                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7846
7847                 /* These slots are not initialized, so fall back to the slow path until they are initialized */
7848                 /* That happens when mono_method_add_generic_virtual_invocation () creates an IMT thunk */
7849                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, slot_reg, 0);
7850                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, slowpath_bb);
7851
7852                 /* Fastpath */
7853                 /* Same as with iface calls */
7854                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_addr_ins, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7855                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_arg_ins, OP_LOAD_MEMBASE, arg_reg, slot_reg, SIZEOF_VOID_P);
7856                 icall_args [0] = thunk_arg_ins;
7857                 icall_args [1] = emit_get_rgctx_method (cfg, context_used,
7858                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7859                 ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_trampoline, icall_args, thunk_addr_ins, NULL, NULL);
7860                 ftndesc_ins->dreg = ftndesc_reg;
7861                 /*
7862                  * Unlike normal iface calls, these imt thunks can return NULL, i.e. when they are passed an instantiation
7863                  * they don't know about yet. Fall back to the slowpath in that case.
7864                  */
7865                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ftndesc_reg, 0);
7866                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, slowpath_bb);
7867
7868                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
7869
7870                 /* Slowpath */
7871                 MONO_START_BB (cfg, slowpath_bb);
7872                 icall_args [0] = vtable_ins;
7873                 EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7874                 icall_args [2] = emit_get_rgctx_method (cfg, context_used,
7875                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7876                 if (is_iface)
7877                         ftndesc_ins = mono_emit_jit_icall (cfg, mono_resolve_generic_virtual_iface_call, icall_args);
7878                 else
7879                         ftndesc_ins = mono_emit_jit_icall (cfg, mono_resolve_generic_virtual_call, icall_args);
7880                 ftndesc_ins->dreg = ftndesc_reg;
7881                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
7882
7883                 /* Common case */
7884                 MONO_START_BB (cfg, end_bb);
7885                 return emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
7886         }
7887
7888         /*
7889          * Non-optimized cases
7890          */
7891         icall_args [0] = sp [0];
7892         EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7893
7894         icall_args [2] = emit_get_rgctx_method (cfg, context_used,
7895                                                                                         cmethod, MONO_RGCTX_INFO_METHOD);
7896
7897         arg_reg = alloc_preg (cfg);
7898         MONO_EMIT_NEW_PCONST (cfg, arg_reg, NULL);
7899         EMIT_NEW_VARLOADA_VREG (cfg, icall_args [3], arg_reg, &mono_defaults.int_class->byval_arg);
7900
7901         g_assert (is_gsharedvt);
7902         if (is_iface)
7903                 call_target = mono_emit_jit_icall (cfg, mono_resolve_iface_call_gsharedvt, icall_args);
7904         else
7905                 call_target = mono_emit_jit_icall (cfg, mono_resolve_vcall_gsharedvt, icall_args);
7906
7907         /*
7908          * Pass the extra argument even if the callee doesn't receive it, most
7909          * calling conventions allow this.
7910          */
7911         return emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
7912 }
7913
7914 static gboolean
7915 is_exception_class (MonoClass *klass)
7916 {
7917         while (klass) {
7918                 if (klass == mono_defaults.exception_class)
7919                         return TRUE;
7920                 klass = klass->parent;
7921         }
7922         return FALSE;
7923 }
7924
7925 /*
7926  * is_jit_optimizer_disabled:
7927  *
7928  *   Determine whenever M's assembly has a DebuggableAttribute with the
7929  * IsJITOptimizerDisabled flag set.
7930  */
7931 static gboolean
7932 is_jit_optimizer_disabled (MonoMethod *m)
7933 {
7934         MonoError error;
7935         MonoAssembly *ass = m->klass->image->assembly;
7936         MonoCustomAttrInfo* attrs;
7937         MonoClass *klass;
7938         int i;
7939         gboolean val = FALSE;
7940
7941         g_assert (ass);
7942         if (ass->jit_optimizer_disabled_inited)
7943                 return ass->jit_optimizer_disabled;
7944
7945         klass = mono_class_try_get_debuggable_attribute_class ();
7946
7947         if (!klass) {
7948                 /* Linked away */
7949                 ass->jit_optimizer_disabled = FALSE;
7950                 mono_memory_barrier ();
7951                 ass->jit_optimizer_disabled_inited = TRUE;
7952                 return FALSE;
7953         }
7954
7955         attrs = mono_custom_attrs_from_assembly_checked (ass, &error);
7956         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7957         if (attrs) {
7958                 for (i = 0; i < attrs->num_attrs; ++i) {
7959                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
7960                         const gchar *p;
7961                         MonoMethodSignature *sig;
7962
7963                         if (!attr->ctor || attr->ctor->klass != klass)
7964                                 continue;
7965                         /* Decode the attribute. See reflection.c */
7966                         p = (const char*)attr->data;
7967                         g_assert (read16 (p) == 0x0001);
7968                         p += 2;
7969
7970                         // FIXME: Support named parameters
7971                         sig = mono_method_signature (attr->ctor);
7972                         if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
7973                                 continue;
7974                         /* Two boolean arguments */
7975                         p ++;
7976                         val = *p;
7977                 }
7978                 mono_custom_attrs_free (attrs);
7979         }
7980
7981         ass->jit_optimizer_disabled = val;
7982         mono_memory_barrier ();
7983         ass->jit_optimizer_disabled_inited = TRUE;
7984
7985         return val;
7986 }
7987
7988 static gboolean
7989 is_supported_tail_call (MonoCompile *cfg, MonoMethod *method, MonoMethod *cmethod, MonoMethodSignature *fsig, int call_opcode)
7990 {
7991         gboolean supported_tail_call;
7992         int i;
7993
7994         supported_tail_call = mono_arch_tail_call_supported (cfg, mono_method_signature (method), mono_method_signature (cmethod));
7995
7996         for (i = 0; i < fsig->param_count; ++i) {
7997                 if (fsig->params [i]->byref || fsig->params [i]->type == MONO_TYPE_PTR || fsig->params [i]->type == MONO_TYPE_FNPTR)
7998                         /* These can point to the current method's stack */
7999                         supported_tail_call = FALSE;
8000         }
8001         if (fsig->hasthis && cmethod->klass->valuetype)
8002                 /* this might point to the current method's stack */
8003                 supported_tail_call = FALSE;
8004         if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
8005                 supported_tail_call = FALSE;
8006         if (cfg->method->save_lmf)
8007                 supported_tail_call = FALSE;
8008         if (cmethod->wrapper_type && cmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
8009                 supported_tail_call = FALSE;
8010         if (call_opcode != CEE_CALL)
8011                 supported_tail_call = FALSE;
8012
8013         /* Debugging support */
8014 #if 0
8015         if (supported_tail_call) {
8016                 if (!mono_debug_count ())
8017                         supported_tail_call = FALSE;
8018         }
8019 #endif
8020
8021         return supported_tail_call;
8022 }
8023
8024 /*
8025  * handle_ctor_call:
8026  *
8027  *   Handle calls made to ctors from NEWOBJ opcodes.
8028  */
8029 static void
8030 handle_ctor_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used,
8031                                   MonoInst **sp, guint8 *ip, int *inline_costs)
8032 {
8033         MonoInst *vtable_arg = NULL, *callvirt_this_arg = NULL, *ins;
8034
8035         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
8036                                         mono_method_is_generic_sharable (cmethod, TRUE)) {
8037                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
8038                         mono_class_vtable (cfg->domain, cmethod->klass);
8039                         CHECK_TYPELOAD (cmethod->klass);
8040
8041                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
8042                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
8043                 } else {
8044                         if (context_used) {
8045                                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
8046                                                                                                    cmethod->klass, MONO_RGCTX_INFO_VTABLE);
8047                         } else {
8048                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
8049
8050                                 CHECK_TYPELOAD (cmethod->klass);
8051                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
8052                         }
8053                 }
8054         }
8055
8056         /* Avoid virtual calls to ctors if possible */
8057         if (mono_class_is_marshalbyref (cmethod->klass))
8058                 callvirt_this_arg = sp [0];
8059
8060         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
8061                 g_assert (MONO_TYPE_IS_VOID (fsig->ret));
8062                 CHECK_CFG_EXCEPTION;
8063         } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
8064                            mono_method_check_inlining (cfg, cmethod) &&
8065                            !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE)) {
8066                 int costs;
8067
8068                 if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, FALSE))) {
8069                         cfg->real_offset += 5;
8070
8071                         *inline_costs += costs - 5;
8072                 } else {
8073                         INLINE_FAILURE ("inline failure");
8074                         // FIXME-VT: Clean this up
8075                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
8076                                 GSHAREDVT_FAILURE(*ip);
8077                         mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, callvirt_this_arg, NULL, NULL);
8078                 }
8079         } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
8080                 MonoInst *addr;
8081
8082                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
8083
8084                 if (cfg->llvm_only) {
8085                         // FIXME: Avoid initializing vtable_arg
8086                         emit_llvmonly_calli (cfg, fsig, sp, addr);
8087                 } else {
8088                         mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
8089                 }
8090         } else if (context_used &&
8091                            ((!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
8092                                  !mono_class_generic_sharing_enabled (cmethod->klass)) || cfg->gsharedvt)) {
8093                 MonoInst *cmethod_addr;
8094
8095                 /* Generic calls made out of gsharedvt methods cannot be patched, so use an indirect call */
8096
8097                 if (cfg->llvm_only) {
8098                         MonoInst *addr = emit_get_rgctx_method (cfg, context_used, cmethod,
8099                                                                                                         MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
8100                         emit_llvmonly_calli (cfg, fsig, sp, addr);
8101                 } else {
8102                         cmethod_addr = emit_get_rgctx_method (cfg, context_used,
8103                                                                                                   cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
8104
8105                         mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
8106                 }
8107         } else {
8108                 INLINE_FAILURE ("ctor call");
8109                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
8110                                                                                   callvirt_this_arg, NULL, vtable_arg);
8111         }
8112  exception_exit:
8113         return;
8114 }
8115
8116 static void
8117 emit_setret (MonoCompile *cfg, MonoInst *val)
8118 {
8119         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (cfg->method)->ret);
8120         MonoInst *ins;
8121
8122         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
8123                 MonoInst *ret_addr;
8124
8125                 if (!cfg->vret_addr) {
8126                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, val);
8127                 } else {
8128                         EMIT_NEW_RETLOADA (cfg, ret_addr);
8129
8130                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, val->dreg);
8131                         ins->klass = mono_class_from_mono_type (ret_type);
8132                 }
8133         } else {
8134 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
8135                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
8136                         MonoInst *iargs [1];
8137                         MonoInst *conv;
8138
8139                         iargs [0] = val;
8140                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
8141                         mono_arch_emit_setret (cfg, cfg->method, conv);
8142                 } else {
8143                         mono_arch_emit_setret (cfg, cfg->method, val);
8144                 }
8145 #else
8146                 mono_arch_emit_setret (cfg, cfg->method, val);
8147 #endif
8148         }
8149 }
8150
8151 /*
8152  * mono_method_to_ir:
8153  *
8154  *   Translate the .net IL into linear IR.
8155  */
8156 int
8157 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
8158                    MonoInst *return_var, MonoInst **inline_args, 
8159                    guint inline_offset, gboolean is_virtual_call)
8160 {
8161         MonoError error;
8162         MonoInst *ins, **sp, **stack_start;
8163         MonoBasicBlock *tblock = NULL, *init_localsbb = NULL;
8164         MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
8165         MonoMethod *cmethod, *method_definition;
8166         MonoInst **arg_array;
8167         MonoMethodHeader *header;
8168         MonoImage *image;
8169         guint32 token, ins_flag;
8170         MonoClass *klass;
8171         MonoClass *constrained_class = NULL;
8172         unsigned char *ip, *end, *target, *err_pos;
8173         MonoMethodSignature *sig;
8174         MonoGenericContext *generic_context = NULL;
8175         MonoGenericContainer *generic_container = NULL;
8176         MonoType **param_types;
8177         int i, n, start_new_bblock, dreg;
8178         int num_calls = 0, inline_costs = 0;
8179         int breakpoint_id = 0;
8180         guint num_args;
8181         GSList *class_inits = NULL;
8182         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
8183         int context_used;
8184         gboolean init_locals, seq_points, skip_dead_blocks;
8185         gboolean sym_seq_points = FALSE;
8186         MonoDebugMethodInfo *minfo;
8187         MonoBitSet *seq_point_locs = NULL;
8188         MonoBitSet *seq_point_set_locs = NULL;
8189
8190         cfg->disable_inline = is_jit_optimizer_disabled (method);
8191
8192         /* serialization and xdomain stuff may need access to private fields and methods */
8193         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
8194         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
8195         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
8196         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
8197         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
8198         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
8199
8200         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
8201         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
8202         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
8203         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
8204         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF;
8205
8206         image = method->klass->image;
8207         header = mono_method_get_header_checked (method, &cfg->error);
8208         if (!header) {
8209                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
8210                 goto exception_exit;
8211         } else {
8212                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
8213         }
8214
8215         generic_container = mono_method_get_generic_container (method);
8216         sig = mono_method_signature (method);
8217         num_args = sig->hasthis + sig->param_count;
8218         ip = (unsigned char*)header->code;
8219         cfg->cil_start = ip;
8220         end = ip + header->code_size;
8221         cfg->stat_cil_code_size += header->code_size;
8222
8223         seq_points = cfg->gen_seq_points && cfg->method == method;
8224
8225         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
8226                 /* We could hit a seq point before attaching to the JIT (#8338) */
8227                 seq_points = FALSE;
8228         }
8229
8230         if (cfg->gen_sdb_seq_points && cfg->method == method) {
8231                 minfo = mono_debug_lookup_method (method);
8232                 if (minfo) {
8233                         MonoSymSeqPoint *sps;
8234                         int i, n_il_offsets;
8235
8236                         mono_debug_get_seq_points (minfo, NULL, NULL, NULL, &sps, &n_il_offsets);
8237                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
8238                         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);
8239                         sym_seq_points = TRUE;
8240                         for (i = 0; i < n_il_offsets; ++i) {
8241                                 if (sps [i].il_offset < header->code_size)
8242                                         mono_bitset_set_fast (seq_point_locs, sps [i].il_offset);
8243                         }
8244                         g_free (sps);
8245                 } else if (!method->wrapper_type && !method->dynamic && mono_debug_image_has_debug_info (method->klass->image)) {
8246                         /* Methods without line number info like auto-generated property accessors */
8247                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
8248                         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);
8249                         sym_seq_points = TRUE;
8250                 }
8251         }
8252
8253         /* 
8254          * Methods without init_locals set could cause asserts in various passes
8255          * (#497220). To work around this, we emit dummy initialization opcodes
8256          * (OP_DUMMY_ICONST etc.) which generate no code. These are only supported
8257          * on some platforms.
8258          */
8259         if ((cfg->opt & MONO_OPT_UNSAFE) && cfg->backend->have_dummy_init)
8260                 init_locals = header->init_locals;
8261         else
8262                 init_locals = TRUE;
8263
8264         method_definition = method;
8265         while (method_definition->is_inflated) {
8266                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
8267                 method_definition = imethod->declaring;
8268         }
8269
8270         /* SkipVerification is not allowed if core-clr is enabled */
8271         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
8272                 dont_verify = TRUE;
8273                 dont_verify_stloc = TRUE;
8274         }
8275
8276         if (sig->is_inflated)
8277                 generic_context = mono_method_get_context (method);
8278         else if (generic_container)
8279                 generic_context = &generic_container->context;
8280         cfg->generic_context = generic_context;
8281
8282         if (!cfg->gshared)
8283                 g_assert (!sig->has_type_parameters);
8284
8285         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
8286                 g_assert (method->is_inflated);
8287                 g_assert (mono_method_get_context (method)->method_inst);
8288         }
8289         if (method->is_inflated && mono_method_get_context (method)->method_inst)
8290                 g_assert (sig->generic_param_count);
8291
8292         if (cfg->method == method) {
8293                 cfg->real_offset = 0;
8294         } else {
8295                 cfg->real_offset = inline_offset;
8296         }
8297
8298         cfg->cil_offset_to_bb = (MonoBasicBlock **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
8299         cfg->cil_offset_to_bb_len = header->code_size;
8300
8301         cfg->current_method = method;
8302
8303         if (cfg->verbose_level > 2)
8304                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
8305
8306         param_types = (MonoType **)mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
8307         if (sig->hasthis)
8308                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
8309         for (n = 0; n < sig->param_count; ++n)
8310                 param_types [n + sig->hasthis] = sig->params [n];
8311         cfg->arg_types = param_types;
8312
8313         cfg->dont_inline = g_list_prepend (cfg->dont_inline, method);
8314         if (cfg->method == method) {
8315
8316                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
8317                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
8318
8319                 /* ENTRY BLOCK */
8320                 NEW_BBLOCK (cfg, start_bblock);
8321                 cfg->bb_entry = start_bblock;
8322                 start_bblock->cil_code = NULL;
8323                 start_bblock->cil_length = 0;
8324
8325                 /* EXIT BLOCK */
8326                 NEW_BBLOCK (cfg, end_bblock);
8327                 cfg->bb_exit = end_bblock;
8328                 end_bblock->cil_code = NULL;
8329                 end_bblock->cil_length = 0;
8330                 end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
8331                 g_assert (cfg->num_bblocks == 2);
8332
8333                 arg_array = cfg->args;
8334
8335                 if (header->num_clauses) {
8336                         cfg->spvars = g_hash_table_new (NULL, NULL);
8337                         cfg->exvars = g_hash_table_new (NULL, NULL);
8338                 }
8339                 /* handle exception clauses */
8340                 for (i = 0; i < header->num_clauses; ++i) {
8341                         MonoBasicBlock *try_bb;
8342                         MonoExceptionClause *clause = &header->clauses [i];
8343                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
8344
8345                         try_bb->real_offset = clause->try_offset;
8346                         try_bb->try_start = TRUE;
8347                         try_bb->region = ((i + 1) << 8) | clause->flags;
8348                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
8349                         tblock->real_offset = clause->handler_offset;
8350                         tblock->flags |= BB_EXCEPTION_HANDLER;
8351
8352                         /*
8353                          * Linking the try block with the EH block hinders inlining as we won't be able to 
8354                          * merge the bblocks from inlining and produce an artificial hole for no good reason.
8355                          */
8356                         if (COMPILE_LLVM (cfg))
8357                                 link_bblock (cfg, try_bb, tblock);
8358
8359                         if (*(ip + clause->handler_offset) == CEE_POP)
8360                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
8361
8362                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
8363                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
8364                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
8365                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
8366                                 MONO_ADD_INS (tblock, ins);
8367
8368                                 if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FILTER) {
8369                                         /* finally clauses already have a seq point */
8370                                         /* seq points for filter clauses are emitted below */
8371                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
8372                                         MONO_ADD_INS (tblock, ins);
8373                                 }
8374
8375                                 /* todo: is a fault block unsafe to optimize? */
8376                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
8377                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
8378                         }
8379
8380                         /*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);
8381                           while (p < end) {
8382                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
8383                           }*/
8384                         /* catch and filter blocks get the exception object on the stack */
8385                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
8386                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8387
8388                                 /* mostly like handle_stack_args (), but just sets the input args */
8389                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
8390                                 tblock->in_scount = 1;
8391                                 tblock->in_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
8392                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
8393
8394                                 cfg->cbb = tblock;
8395
8396 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
8397                                 /* The EH code passes in the exception in a register to both JITted and LLVM compiled code */
8398                                 if (!cfg->compile_llvm) {
8399                                         MONO_INST_NEW (cfg, ins, OP_GET_EX_OBJ);
8400                                         ins->dreg = tblock->in_stack [0]->dreg;
8401                                         MONO_ADD_INS (tblock, ins);
8402                                 }
8403 #else
8404                                 MonoInst *dummy_use;
8405
8406                                 /* 
8407                                  * Add a dummy use for the exvar so its liveness info will be
8408                                  * correct.
8409                                  */
8410                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
8411 #endif
8412
8413                                 if (seq_points && clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8414                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
8415                                         MONO_ADD_INS (tblock, ins);
8416                                 }
8417                                 
8418                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8419                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
8420                                         tblock->flags |= BB_EXCEPTION_HANDLER;
8421                                         tblock->real_offset = clause->data.filter_offset;
8422                                         tblock->in_scount = 1;
8423                                         tblock->in_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
8424                                         /* The filter block shares the exvar with the handler block */
8425                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
8426                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
8427                                         MONO_ADD_INS (tblock, ins);
8428                                 }
8429                         }
8430
8431                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
8432                                         clause->data.catch_class &&
8433                                         cfg->gshared &&
8434                                         mono_class_check_context_used (clause->data.catch_class)) {
8435                                 /*
8436                                  * In shared generic code with catch
8437                                  * clauses containing type variables
8438                                  * the exception handling code has to
8439                                  * be able to get to the rgctx.
8440                                  * Therefore we have to make sure that
8441                                  * the vtable/mrgctx argument (for
8442                                  * static or generic methods) or the
8443                                  * "this" argument (for non-static
8444                                  * methods) are live.
8445                                  */
8446                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8447                                                 mini_method_get_context (method)->method_inst ||
8448                                                 method->klass->valuetype) {
8449                                         mono_get_vtable_var (cfg);
8450                                 } else {
8451                                         MonoInst *dummy_use;
8452
8453                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
8454                                 }
8455                         }
8456                 }
8457         } else {
8458                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
8459                 cfg->cbb = start_bblock;
8460                 cfg->args = arg_array;
8461                 mono_save_args (cfg, sig, inline_args);
8462         }
8463
8464         /* FIRST CODE BLOCK */
8465         NEW_BBLOCK (cfg, tblock);
8466         tblock->cil_code = ip;
8467         cfg->cbb = tblock;
8468         cfg->ip = ip;
8469
8470         ADD_BBLOCK (cfg, tblock);
8471
8472         if (cfg->method == method) {
8473                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
8474                 if (breakpoint_id) {
8475                         MONO_INST_NEW (cfg, ins, OP_BREAK);
8476                         MONO_ADD_INS (cfg->cbb, ins);
8477                 }
8478         }
8479
8480         /* we use a separate basic block for the initialization code */
8481         NEW_BBLOCK (cfg, init_localsbb);
8482         if (cfg->method == method)
8483                 cfg->bb_init = init_localsbb;
8484         init_localsbb->real_offset = cfg->real_offset;
8485         start_bblock->next_bb = init_localsbb;
8486         init_localsbb->next_bb = cfg->cbb;
8487         link_bblock (cfg, start_bblock, init_localsbb);
8488         link_bblock (cfg, init_localsbb, cfg->cbb);
8489                 
8490         cfg->cbb = init_localsbb;
8491
8492         if (cfg->gsharedvt && cfg->method == method) {
8493                 MonoGSharedVtMethodInfo *info;
8494                 MonoInst *var, *locals_var;
8495                 int dreg;
8496
8497                 info = (MonoGSharedVtMethodInfo *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoGSharedVtMethodInfo));
8498                 info->method = cfg->method;
8499                 info->count_entries = 16;
8500                 info->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
8501                 cfg->gsharedvt_info = info;
8502
8503                 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8504                 /* prevent it from being register allocated */
8505                 //var->flags |= MONO_INST_VOLATILE;
8506                 cfg->gsharedvt_info_var = var;
8507
8508                 ins = emit_get_rgctx_gsharedvt_method (cfg, mini_method_check_context_used (cfg, method), method, info);
8509                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, var->dreg, ins->dreg);
8510
8511                 /* Allocate locals */
8512                 locals_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8513                 /* prevent it from being register allocated */
8514                 //locals_var->flags |= MONO_INST_VOLATILE;
8515                 cfg->gsharedvt_locals_var = locals_var;
8516
8517                 dreg = alloc_ireg (cfg);
8518                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, dreg, var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, locals_size));
8519
8520                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
8521                 ins->dreg = locals_var->dreg;
8522                 ins->sreg1 = dreg;
8523                 MONO_ADD_INS (cfg->cbb, ins);
8524                 cfg->gsharedvt_locals_var_ins = ins;
8525                 
8526                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
8527                 /*
8528                 if (init_locals)
8529                         ins->flags |= MONO_INST_INIT;
8530                 */
8531         }
8532
8533         if (mono_security_core_clr_enabled ()) {
8534                 /* check if this is native code, e.g. an icall or a p/invoke */
8535                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
8536                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
8537                         if (wrapped) {
8538                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
8539                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
8540
8541                                 /* if this ia a native call then it can only be JITted from platform code */
8542                                 if ((icall || pinvk) && method->klass && method->klass->image) {
8543                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
8544                                                 MonoException *ex = icall ? mono_get_exception_security () : 
8545                                                         mono_get_exception_method_access ();
8546                                                 emit_throw_exception (cfg, ex);
8547                                         }
8548                                 }
8549                         }
8550                 }
8551         }
8552
8553         CHECK_CFG_EXCEPTION;
8554
8555         if (header->code_size == 0)
8556                 UNVERIFIED;
8557
8558         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
8559                 ip = err_pos;
8560                 UNVERIFIED;
8561         }
8562
8563         if (cfg->method == method)
8564                 mono_debug_init_method (cfg, cfg->cbb, breakpoint_id);
8565
8566         for (n = 0; n < header->num_locals; ++n) {
8567                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
8568                         UNVERIFIED;
8569         }
8570         class_inits = NULL;
8571
8572         /* We force the vtable variable here for all shared methods
8573            for the possibility that they might show up in a stack
8574            trace where their exact instantiation is needed. */
8575         if (cfg->gshared && method == cfg->method) {
8576                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8577                                 mini_method_get_context (method)->method_inst ||
8578                                 method->klass->valuetype) {
8579                         mono_get_vtable_var (cfg);
8580                 } else {
8581                         /* FIXME: Is there a better way to do this?
8582                            We need the variable live for the duration
8583                            of the whole method. */
8584                         cfg->args [0]->flags |= MONO_INST_VOLATILE;
8585                 }
8586         }
8587
8588         /* add a check for this != NULL to inlined methods */
8589         if (is_virtual_call) {
8590                 MonoInst *arg_ins;
8591
8592                 NEW_ARGLOAD (cfg, arg_ins, 0);
8593                 MONO_ADD_INS (cfg->cbb, arg_ins);
8594                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
8595         }
8596
8597         skip_dead_blocks = !dont_verify;
8598         if (skip_dead_blocks) {
8599                 original_bb = bb = mono_basic_block_split (method, &cfg->error, header);
8600                 CHECK_CFG_ERROR;
8601                 g_assert (bb);
8602         }
8603
8604         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
8605         stack_start = sp = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
8606
8607         ins_flag = 0;
8608         start_new_bblock = 0;
8609         while (ip < end) {
8610                 if (cfg->method == method)
8611                         cfg->real_offset = ip - header->code;
8612                 else
8613                         cfg->real_offset = inline_offset;
8614                 cfg->ip = ip;
8615
8616                 context_used = 0;
8617
8618                 if (start_new_bblock) {
8619                         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
8620                         if (start_new_bblock == 2) {
8621                                 g_assert (ip == tblock->cil_code);
8622                         } else {
8623                                 GET_BBLOCK (cfg, tblock, ip);
8624                         }
8625                         cfg->cbb->next_bb = tblock;
8626                         cfg->cbb = tblock;
8627                         start_new_bblock = 0;
8628                         for (i = 0; i < cfg->cbb->in_scount; ++i) {
8629                                 if (cfg->verbose_level > 3)
8630                                         printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8631                                 EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8632                                 *sp++ = ins;
8633                         }
8634                         if (class_inits)
8635                                 g_slist_free (class_inits);
8636                         class_inits = NULL;
8637                 } else {
8638                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != cfg->cbb)) {
8639                                 link_bblock (cfg, cfg->cbb, tblock);
8640                                 if (sp != stack_start) {
8641                                         handle_stack_args (cfg, stack_start, sp - stack_start);
8642                                         sp = stack_start;
8643                                         CHECK_UNVERIFIABLE (cfg);
8644                                 }
8645                                 cfg->cbb->next_bb = tblock;
8646                                 cfg->cbb = tblock;
8647                                 for (i = 0; i < cfg->cbb->in_scount; ++i) {
8648                                         if (cfg->verbose_level > 3)
8649                                                 printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8650                                         EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8651                                         *sp++ = ins;
8652                                 }
8653                                 g_slist_free (class_inits);
8654                                 class_inits = NULL;
8655                         }
8656                 }
8657
8658                 if (skip_dead_blocks) {
8659                         int ip_offset = ip - header->code;
8660
8661                         if (ip_offset == bb->end)
8662                                 bb = bb->next;
8663
8664                         if (bb->dead) {
8665                                 int op_size = mono_opcode_size (ip, end);
8666                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
8667
8668                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
8669
8670                                 if (ip_offset + op_size == bb->end) {
8671                                         MONO_INST_NEW (cfg, ins, OP_NOP);
8672                                         MONO_ADD_INS (cfg->cbb, ins);
8673                                         start_new_bblock = 1;
8674                                 }
8675
8676                                 ip += op_size;
8677                                 continue;
8678                         }
8679                 }
8680                 /*
8681                  * Sequence points are points where the debugger can place a breakpoint.
8682                  * Currently, we generate these automatically at points where the IL
8683                  * stack is empty.
8684                  */
8685                 if (seq_points && ((!sym_seq_points && (sp == stack_start)) || (sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code)))) {
8686                         /*
8687                          * Make methods interruptable at the beginning, and at the targets of
8688                          * backward branches.
8689                          * Also, do this at the start of every bblock in methods with clauses too,
8690                          * to be able to handle instructions with inprecise control flow like
8691                          * throw/endfinally.
8692                          * Backward branches are handled at the end of method-to-ir ().
8693                          */
8694                         gboolean intr_loc = ip == header->code || (!cfg->cbb->last_ins && cfg->header->num_clauses);
8695                         gboolean sym_seq_point = sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code);
8696
8697                         /* Avoid sequence points on empty IL like .volatile */
8698                         // FIXME: Enable this
8699                         //if (!(cfg->cbb->last_ins && cfg->cbb->last_ins->opcode == OP_SEQ_POINT)) {
8700                         NEW_SEQ_POINT (cfg, ins, ip - header->code, intr_loc);
8701                         if ((sp != stack_start) && !sym_seq_point)
8702                                 ins->flags |= MONO_INST_NONEMPTY_STACK;
8703                         MONO_ADD_INS (cfg->cbb, ins);
8704
8705                         if (sym_seq_points)
8706                                 mono_bitset_set_fast (seq_point_set_locs, ip - header->code);
8707                 }
8708
8709                 cfg->cbb->real_offset = cfg->real_offset;
8710
8711                 if ((cfg->method == method) && cfg->coverage_info) {
8712                         guint32 cil_offset = ip - header->code;
8713                         cfg->coverage_info->data [cil_offset].cil_code = ip;
8714
8715                         /* TODO: Use an increment here */
8716 #if defined(TARGET_X86)
8717                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
8718                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
8719                         ins->inst_imm = 1;
8720                         MONO_ADD_INS (cfg->cbb, ins);
8721 #else
8722                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
8723                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
8724 #endif
8725                 }
8726
8727                 if (cfg->verbose_level > 3)
8728                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
8729
8730                 switch (*ip) {
8731                 case CEE_NOP:
8732                         if (seq_points && !sym_seq_points && sp != stack_start) {
8733                                 /*
8734                                  * The C# compiler uses these nops to notify the JIT that it should
8735                                  * insert seq points.
8736                                  */
8737                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, FALSE);
8738                                 MONO_ADD_INS (cfg->cbb, ins);
8739                         }
8740                         if (cfg->keep_cil_nops)
8741                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
8742                         else
8743                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8744                         ip++;
8745                         MONO_ADD_INS (cfg->cbb, ins);
8746                         break;
8747                 case CEE_BREAK:
8748                         if (should_insert_brekpoint (cfg->method)) {
8749                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
8750                         } else {
8751                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8752                         }
8753                         ip++;
8754                         MONO_ADD_INS (cfg->cbb, ins);
8755                         break;
8756                 case CEE_LDARG_0:
8757                 case CEE_LDARG_1:
8758                 case CEE_LDARG_2:
8759                 case CEE_LDARG_3:
8760                         CHECK_STACK_OVF (1);
8761                         n = (*ip)-CEE_LDARG_0;
8762                         CHECK_ARG (n);
8763                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8764                         ip++;
8765                         *sp++ = ins;
8766                         break;
8767                 case CEE_LDLOC_0:
8768                 case CEE_LDLOC_1:
8769                 case CEE_LDLOC_2:
8770                 case CEE_LDLOC_3:
8771                         CHECK_STACK_OVF (1);
8772                         n = (*ip)-CEE_LDLOC_0;
8773                         CHECK_LOCAL (n);
8774                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8775                         ip++;
8776                         *sp++ = ins;
8777                         break;
8778                 case CEE_STLOC_0:
8779                 case CEE_STLOC_1:
8780                 case CEE_STLOC_2:
8781                 case CEE_STLOC_3: {
8782                         CHECK_STACK (1);
8783                         n = (*ip)-CEE_STLOC_0;
8784                         CHECK_LOCAL (n);
8785                         --sp;
8786                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
8787                                 UNVERIFIED;
8788                         emit_stloc_ir (cfg, sp, header, n);
8789                         ++ip;
8790                         inline_costs += 1;
8791                         break;
8792                         }
8793                 case CEE_LDARG_S:
8794                         CHECK_OPSIZE (2);
8795                         CHECK_STACK_OVF (1);
8796                         n = ip [1];
8797                         CHECK_ARG (n);
8798                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8799                         *sp++ = ins;
8800                         ip += 2;
8801                         break;
8802                 case CEE_LDARGA_S:
8803                         CHECK_OPSIZE (2);
8804                         CHECK_STACK_OVF (1);
8805                         n = ip [1];
8806                         CHECK_ARG (n);
8807                         NEW_ARGLOADA (cfg, ins, n);
8808                         MONO_ADD_INS (cfg->cbb, ins);
8809                         *sp++ = ins;
8810                         ip += 2;
8811                         break;
8812                 case CEE_STARG_S:
8813                         CHECK_OPSIZE (2);
8814                         CHECK_STACK (1);
8815                         --sp;
8816                         n = ip [1];
8817                         CHECK_ARG (n);
8818                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
8819                                 UNVERIFIED;
8820                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
8821                         ip += 2;
8822                         break;
8823                 case CEE_LDLOC_S:
8824                         CHECK_OPSIZE (2);
8825                         CHECK_STACK_OVF (1);
8826                         n = ip [1];
8827                         CHECK_LOCAL (n);
8828                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8829                         *sp++ = ins;
8830                         ip += 2;
8831                         break;
8832                 case CEE_LDLOCA_S: {
8833                         unsigned char *tmp_ip;
8834                         CHECK_OPSIZE (2);
8835                         CHECK_STACK_OVF (1);
8836                         CHECK_LOCAL (ip [1]);
8837
8838                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
8839                                 ip = tmp_ip;
8840                                 inline_costs += 1;
8841                                 break;
8842                         }
8843
8844                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
8845                         *sp++ = ins;
8846                         ip += 2;
8847                         break;
8848                 }
8849                 case CEE_STLOC_S:
8850                         CHECK_OPSIZE (2);
8851                         CHECK_STACK (1);
8852                         --sp;
8853                         CHECK_LOCAL (ip [1]);
8854                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
8855                                 UNVERIFIED;
8856                         emit_stloc_ir (cfg, sp, header, ip [1]);
8857                         ip += 2;
8858                         inline_costs += 1;
8859                         break;
8860                 case CEE_LDNULL:
8861                         CHECK_STACK_OVF (1);
8862                         EMIT_NEW_PCONST (cfg, ins, NULL);
8863                         ins->type = STACK_OBJ;
8864                         ++ip;
8865                         *sp++ = ins;
8866                         break;
8867                 case CEE_LDC_I4_M1:
8868                         CHECK_STACK_OVF (1);
8869                         EMIT_NEW_ICONST (cfg, ins, -1);
8870                         ++ip;
8871                         *sp++ = ins;
8872                         break;
8873                 case CEE_LDC_I4_0:
8874                 case CEE_LDC_I4_1:
8875                 case CEE_LDC_I4_2:
8876                 case CEE_LDC_I4_3:
8877                 case CEE_LDC_I4_4:
8878                 case CEE_LDC_I4_5:
8879                 case CEE_LDC_I4_6:
8880                 case CEE_LDC_I4_7:
8881                 case CEE_LDC_I4_8:
8882                         CHECK_STACK_OVF (1);
8883                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
8884                         ++ip;
8885                         *sp++ = ins;
8886                         break;
8887                 case CEE_LDC_I4_S:
8888                         CHECK_OPSIZE (2);
8889                         CHECK_STACK_OVF (1);
8890                         ++ip;
8891                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
8892                         ++ip;
8893                         *sp++ = ins;
8894                         break;
8895                 case CEE_LDC_I4:
8896                         CHECK_OPSIZE (5);
8897                         CHECK_STACK_OVF (1);
8898                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
8899                         ip += 5;
8900                         *sp++ = ins;
8901                         break;
8902                 case CEE_LDC_I8:
8903                         CHECK_OPSIZE (9);
8904                         CHECK_STACK_OVF (1);
8905                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
8906                         ins->type = STACK_I8;
8907                         ins->dreg = alloc_dreg (cfg, STACK_I8);
8908                         ++ip;
8909                         ins->inst_l = (gint64)read64 (ip);
8910                         MONO_ADD_INS (cfg->cbb, ins);
8911                         ip += 8;
8912                         *sp++ = ins;
8913                         break;
8914                 case CEE_LDC_R4: {
8915                         float *f;
8916                         gboolean use_aotconst = FALSE;
8917
8918 #ifdef TARGET_POWERPC
8919                         /* FIXME: Clean this up */
8920                         if (cfg->compile_aot)
8921                                 use_aotconst = TRUE;
8922 #endif
8923
8924                         /* FIXME: we should really allocate this only late in the compilation process */
8925                         f = (float *)mono_domain_alloc (cfg->domain, sizeof (float));
8926                         CHECK_OPSIZE (5);
8927                         CHECK_STACK_OVF (1);
8928
8929                         if (use_aotconst) {
8930                                 MonoInst *cons;
8931                                 int dreg;
8932
8933                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
8934
8935                                 dreg = alloc_freg (cfg);
8936                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
8937                                 ins->type = cfg->r4_stack_type;
8938                         } else {
8939                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
8940                                 ins->type = cfg->r4_stack_type;
8941                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8942                                 ins->inst_p0 = f;
8943                                 MONO_ADD_INS (cfg->cbb, ins);
8944                         }
8945                         ++ip;
8946                         readr4 (ip, f);
8947                         ip += 4;
8948                         *sp++ = ins;                    
8949                         break;
8950                 }
8951                 case CEE_LDC_R8: {
8952                         double *d;
8953                         gboolean use_aotconst = FALSE;
8954
8955 #ifdef TARGET_POWERPC
8956                         /* FIXME: Clean this up */
8957                         if (cfg->compile_aot)
8958                                 use_aotconst = TRUE;
8959 #endif
8960
8961                         /* FIXME: we should really allocate this only late in the compilation process */
8962                         d = (double *)mono_domain_alloc (cfg->domain, sizeof (double));
8963                         CHECK_OPSIZE (9);
8964                         CHECK_STACK_OVF (1);
8965
8966                         if (use_aotconst) {
8967                                 MonoInst *cons;
8968                                 int dreg;
8969
8970                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
8971
8972                                 dreg = alloc_freg (cfg);
8973                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
8974                                 ins->type = STACK_R8;
8975                         } else {
8976                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
8977                                 ins->type = STACK_R8;
8978                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8979                                 ins->inst_p0 = d;
8980                                 MONO_ADD_INS (cfg->cbb, ins);
8981                         }
8982                         ++ip;
8983                         readr8 (ip, d);
8984                         ip += 8;
8985                         *sp++ = ins;
8986                         break;
8987                 }
8988                 case CEE_DUP: {
8989                         MonoInst *temp, *store;
8990                         CHECK_STACK (1);
8991                         CHECK_STACK_OVF (1);
8992                         sp--;
8993                         ins = *sp;
8994
8995                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
8996                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
8997
8998                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8999                         *sp++ = ins;
9000
9001                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
9002                         *sp++ = ins;
9003
9004                         ++ip;
9005                         inline_costs += 2;
9006                         break;
9007                 }
9008                 case CEE_POP:
9009                         CHECK_STACK (1);
9010                         ip++;
9011                         --sp;
9012
9013 #ifdef TARGET_X86
9014                         if (sp [0]->type == STACK_R8)
9015                                 /* we need to pop the value from the x86 FP stack */
9016                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
9017 #endif
9018                         break;
9019                 case CEE_JMP: {
9020                         MonoCallInst *call;
9021                         MonoMethodSignature *fsig;
9022                         int i, n;
9023
9024                         INLINE_FAILURE ("jmp");
9025                         GSHAREDVT_FAILURE (*ip);
9026
9027                         CHECK_OPSIZE (5);
9028                         if (stack_start != sp)
9029                                 UNVERIFIED;
9030                         token = read32 (ip + 1);
9031                         /* FIXME: check the signature matches */
9032                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
9033                         CHECK_CFG_ERROR;
9034  
9035                         if (cfg->gshared && mono_method_check_context_used (cmethod))
9036                                 GENERIC_SHARING_FAILURE (CEE_JMP);
9037
9038                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
9039
9040                         fsig = mono_method_signature (cmethod);
9041                         n = fsig->param_count + fsig->hasthis;
9042                         if (cfg->llvm_only) {
9043                                 MonoInst **args;
9044
9045                                 args = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
9046                                 for (i = 0; i < n; ++i)
9047                                         EMIT_NEW_ARGLOAD (cfg, args [i], i);
9048                                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, TRUE, args, NULL, NULL, NULL);
9049                                 /*
9050                                  * The code in mono-basic-block.c treats the rest of the code as dead, but we
9051                                  * have to emit a normal return since llvm expects it.
9052                                  */
9053                                 if (cfg->ret)
9054                                         emit_setret (cfg, ins);
9055                                 MONO_INST_NEW (cfg, ins, OP_BR);
9056                                 ins->inst_target_bb = end_bblock;
9057                                 MONO_ADD_INS (cfg->cbb, ins);
9058                                 link_bblock (cfg, cfg->cbb, end_bblock);
9059                                 ip += 5;
9060                                 break;
9061                         } else if (cfg->backend->have_op_tail_call) {
9062                                 /* Handle tail calls similarly to calls */
9063                                 DISABLE_AOT (cfg);
9064
9065                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
9066                                 call->method = cmethod;
9067                                 call->tail_call = TRUE;
9068                                 call->signature = mono_method_signature (cmethod);
9069                                 call->args = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
9070                                 call->inst.inst_p0 = cmethod;
9071                                 for (i = 0; i < n; ++i)
9072                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
9073
9074                                 if (mini_type_is_vtype (mini_get_underlying_type (call->signature->ret)))
9075                                         call->vret_var = cfg->vret_addr;
9076
9077                                 mono_arch_emit_call (cfg, call);
9078                                 cfg->param_area = MAX(cfg->param_area, call->stack_usage);
9079                                 MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
9080                         } else {
9081                                 for (i = 0; i < num_args; ++i)
9082                                         /* Prevent arguments from being optimized away */
9083                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
9084
9085                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9086                                 ins = (MonoInst*)call;
9087                                 ins->inst_p0 = cmethod;
9088                                 MONO_ADD_INS (cfg->cbb, ins);
9089                         }
9090
9091                         ip += 5;
9092                         start_new_bblock = 1;
9093                         break;
9094                 }
9095                 case CEE_CALLI: {
9096                         MonoInst *addr;
9097                         MonoMethodSignature *fsig;
9098
9099                         CHECK_OPSIZE (5);
9100                         token = read32 (ip + 1);
9101
9102                         ins = NULL;
9103
9104                         //GSHAREDVT_FAILURE (*ip);
9105                         cmethod = NULL;
9106                         CHECK_STACK (1);
9107                         --sp;
9108                         addr = *sp;
9109                         fsig = mini_get_signature (method, token, generic_context, &cfg->error);
9110                         CHECK_CFG_ERROR;
9111
9112                         if (method->dynamic && fsig->pinvoke) {
9113                                 MonoInst *args [3];
9114
9115                                 /*
9116                                  * This is a call through a function pointer using a pinvoke
9117                                  * signature. Have to create a wrapper and call that instead.
9118                                  * FIXME: This is very slow, need to create a wrapper at JIT time
9119                                  * instead based on the signature.
9120                                  */
9121                                 EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
9122                                 EMIT_NEW_PCONST (cfg, args [1], fsig);
9123                                 args [2] = addr;
9124                                 addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
9125                         }
9126
9127                         n = fsig->param_count + fsig->hasthis;
9128
9129                         CHECK_STACK (n);
9130
9131                         //g_assert (!virtual_ || fsig->hasthis);
9132
9133                         sp -= n;
9134
9135                         inline_costs += 10 * num_calls++;
9136
9137                         /*
9138                          * Making generic calls out of gsharedvt methods.
9139                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9140                          * patching gshared method addresses into a gsharedvt method.
9141                          */
9142                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
9143                                 /*
9144                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
9145                                  */
9146                                 MonoInst *callee = addr;
9147
9148                                 if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
9149                                         /* Not tested */
9150                                         GSHAREDVT_FAILURE (*ip);
9151
9152                                 if (cfg->llvm_only)
9153                                         // FIXME:
9154                                         GSHAREDVT_FAILURE (*ip);
9155
9156                                 addr = emit_get_rgctx_sig (cfg, context_used,
9157                                                                                           fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
9158                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
9159                                 goto calli_end;
9160                         }
9161
9162                         /* Prevent inlining of methods with indirect calls */
9163                         INLINE_FAILURE ("indirect call");
9164
9165                         if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
9166                                 MonoJumpInfoType info_type;
9167                                 gpointer info_data;
9168
9169                                 /*
9170                                  * Instead of emitting an indirect call, emit a direct call
9171                                  * with the contents of the aotconst as the patch info.
9172                                  */
9173                                 if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
9174                                         info_type = (MonoJumpInfoType)addr->inst_c1;
9175                                         info_data = addr->inst_p0;
9176                                 } else {
9177                                         info_type = (MonoJumpInfoType)addr->inst_right->inst_c1;
9178                                         info_data = addr->inst_right->inst_left;
9179                                 }
9180
9181                                 if (info_type == MONO_PATCH_INFO_ICALL_ADDR) {
9182                                         ins = (MonoInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_ICALL_ADDR_CALL, info_data, fsig, sp);
9183                                         NULLIFY_INS (addr);
9184                                         goto calli_end;
9185                                 } else if (info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
9186                                         ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
9187                                         NULLIFY_INS (addr);
9188                                         goto calli_end;
9189                                 }
9190                         }
9191                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9192
9193                         calli_end:
9194
9195                         /* End of call, INS should contain the result of the call, if any */
9196
9197                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9198                                 g_assert (ins);
9199                                 *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
9200                         }
9201
9202                         CHECK_CFG_EXCEPTION;
9203
9204                         ip += 5;
9205                         ins_flag = 0;
9206                         constrained_class = NULL;
9207                         break;
9208                 }
9209                 case CEE_CALL:
9210                 case CEE_CALLVIRT: {
9211                         MonoInst *addr = NULL;
9212                         MonoMethodSignature *fsig = NULL;
9213                         int array_rank = 0;
9214                         int virtual_ = *ip == CEE_CALLVIRT;
9215                         gboolean pass_imt_from_rgctx = FALSE;
9216                         MonoInst *imt_arg = NULL;
9217                         MonoInst *keep_this_alive = NULL;
9218                         gboolean pass_vtable = FALSE;
9219                         gboolean pass_mrgctx = FALSE;
9220                         MonoInst *vtable_arg = NULL;
9221                         gboolean check_this = FALSE;
9222                         gboolean supported_tail_call = FALSE;
9223                         gboolean tail_call = FALSE;
9224                         gboolean need_seq_point = FALSE;
9225                         guint32 call_opcode = *ip;
9226                         gboolean emit_widen = TRUE;
9227                         gboolean push_res = TRUE;
9228                         gboolean skip_ret = FALSE;
9229                         gboolean delegate_invoke = FALSE;
9230                         gboolean direct_icall = FALSE;
9231                         gboolean constrained_partial_call = FALSE;
9232                         MonoMethod *cil_method;
9233
9234                         CHECK_OPSIZE (5);
9235                         token = read32 (ip + 1);
9236
9237                         ins = NULL;
9238
9239                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
9240                         CHECK_CFG_ERROR;
9241
9242                         cil_method = cmethod;
9243                                 
9244                         if (constrained_class) {
9245                                 if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
9246                                         if (!mini_is_gsharedvt_klass (constrained_class)) {
9247                                                 g_assert (!cmethod->klass->valuetype);
9248                                                 if (!mini_type_is_reference (&constrained_class->byval_arg))
9249                                                         constrained_partial_call = TRUE;
9250                                         }
9251                                 }
9252
9253                                 if (method->wrapper_type != MONO_WRAPPER_NONE) {
9254                                         if (cfg->verbose_level > 2)
9255                                                 printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_class));
9256                                         if (!((constrained_class->byval_arg.type == MONO_TYPE_VAR ||
9257                                                    constrained_class->byval_arg.type == MONO_TYPE_MVAR) &&
9258                                                   cfg->gshared)) {
9259                                                 cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_class, generic_context, &cfg->error);
9260                                                 CHECK_CFG_ERROR;
9261                                         }
9262                                 } else {
9263                                         if (cfg->verbose_level > 2)
9264                                                 printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_class));
9265
9266                                         if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
9267                                                 /* 
9268                                                  * This is needed since get_method_constrained can't find 
9269                                                  * the method in klass representing a type var.
9270                                                  * The type var is guaranteed to be a reference type in this
9271                                                  * case.
9272                                                  */
9273                                                 if (!mini_is_gsharedvt_klass (constrained_class))
9274                                                         g_assert (!cmethod->klass->valuetype);
9275                                         } else {
9276                                                 cmethod = mono_get_method_constrained_checked (image, token, constrained_class, generic_context, &cil_method, &cfg->error);
9277                                                 CHECK_CFG_ERROR;
9278                                         }
9279                                 }
9280                         }
9281                                         
9282                         if (!dont_verify && !cfg->skip_visibility) {
9283                                 MonoMethod *target_method = cil_method;
9284                                 if (method->is_inflated) {
9285                                         target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context), &cfg->error);
9286                                         CHECK_CFG_ERROR;
9287                                 }
9288                                 if (!mono_method_can_access_method (method_definition, target_method) &&
9289                                         !mono_method_can_access_method (method, cil_method))
9290                                         emit_method_access_failure (cfg, method, cil_method);
9291                         }
9292
9293                         if (mono_security_core_clr_enabled ())
9294                                 ensure_method_is_allowed_to_call_method (cfg, method, cil_method);
9295
9296                         if (!virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
9297                                 /* MS.NET seems to silently convert this to a callvirt */
9298                                 virtual_ = 1;
9299
9300                         {
9301                                 /*
9302                                  * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
9303                                  * converts to a callvirt.
9304                                  *
9305                                  * tests/bug-515884.il is an example of this behavior
9306                                  */
9307                                 const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
9308                                 const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
9309                                 if (!virtual_ && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
9310                                         virtual_ = 1;
9311                         }
9312
9313                         if (!cmethod->klass->inited)
9314                                 if (!mono_class_init (cmethod->klass))
9315                                         TYPE_LOAD_ERROR (cmethod->klass);
9316
9317                         fsig = mono_method_signature (cmethod);
9318                         if (!fsig)
9319                                 LOAD_ERROR;
9320                         if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
9321                                 mini_class_is_system_array (cmethod->klass)) {
9322                                 array_rank = cmethod->klass->rank;
9323                         } else if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && icall_is_direct_callable (cfg, cmethod)) {
9324                                 direct_icall = TRUE;
9325                         } else if (fsig->pinvoke) {
9326                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
9327                                 fsig = mono_method_signature (wrapper);
9328                         } else if (constrained_class) {
9329                         } else {
9330                                 fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
9331                                 CHECK_CFG_ERROR;
9332                         }
9333
9334                         if (cfg->llvm_only && !cfg->method->wrapper_type && (!cmethod || cmethod->is_inflated))
9335                                 cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, fsig);
9336
9337                         /* See code below */
9338                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
9339                                 MonoBasicBlock *tbb;
9340
9341                                 GET_BBLOCK (cfg, tbb, ip + 5);
9342                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
9343                                         /*
9344                                          * We want to extend the try block to cover the call, but we can't do it if the
9345                                          * call is made directly since its followed by an exception check.
9346                                          */
9347                                         direct_icall = FALSE;
9348                                 }
9349                         }
9350
9351                         mono_save_token_info (cfg, image, token, cil_method);
9352
9353                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip + 5 - header->code)))
9354                                 need_seq_point = TRUE;
9355
9356                         /* Don't support calls made using type arguments for now */
9357                         /*
9358                           if (cfg->gsharedvt) {
9359                           if (mini_is_gsharedvt_signature (fsig))
9360                           GSHAREDVT_FAILURE (*ip);
9361                           }
9362                         */
9363
9364                         if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
9365                                 g_assert_not_reached ();
9366
9367                         n = fsig->param_count + fsig->hasthis;
9368
9369                         if (!cfg->gshared && cmethod->klass->generic_container)
9370                                 UNVERIFIED;
9371
9372                         if (!cfg->gshared)
9373                                 g_assert (!mono_method_check_context_used (cmethod));
9374
9375                         CHECK_STACK (n);
9376
9377                         //g_assert (!virtual_ || fsig->hasthis);
9378
9379                         sp -= n;
9380
9381                         /*
9382                          * We have the `constrained.' prefix opcode.
9383                          */
9384                         if (constrained_class) {
9385                                 if (mini_is_gsharedvt_klass (constrained_class)) {
9386                                         if ((cmethod->klass != mono_defaults.object_class) && constrained_class->valuetype && cmethod->klass->valuetype) {
9387                                                 /* The 'Own method' case below */
9388                                         } else if (cmethod->klass->image != mono_defaults.corlib && !(cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !cmethod->klass->valuetype) {
9389                                                 /* 'The type parameter is instantiated as a reference type' case below. */
9390                                         } else {
9391                                                 ins = handle_constrained_gsharedvt_call (cfg, cmethod, fsig, sp, constrained_class, &emit_widen);
9392                                                 CHECK_CFG_EXCEPTION;
9393                                                 g_assert (ins);
9394                                                 goto call_end;
9395                                         }
9396                                 }
9397
9398                                 if (constrained_partial_call) {
9399                                         gboolean need_box = TRUE;
9400
9401                                         /*
9402                                          * The receiver is a valuetype, but the exact type is not known at compile time. This means the
9403                                          * called method is not known at compile time either. The called method could end up being
9404                                          * one of the methods on the parent classes (object/valuetype/enum), in which case we need
9405                                          * to box the receiver.
9406                                          * A simple solution would be to box always and make a normal virtual call, but that would
9407                                          * be bad performance wise.
9408                                          */
9409                                         if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE && cmethod->klass->generic_class) {
9410                                                 /*
9411                                                  * The parent classes implement no generic interfaces, so the called method will be a vtype method, so no boxing neccessary.
9412                                                  */
9413                                                 need_box = FALSE;
9414                                         }
9415
9416                                         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)) {
9417                                                 /* The called method is not virtual, i.e. Object:GetType (), the receiver is a vtype, has to box */
9418                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9419                                                 ins->klass = constrained_class;
9420                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9421                                                 CHECK_CFG_EXCEPTION;
9422                                         } else if (need_box) {
9423                                                 MonoInst *box_type;
9424                                                 MonoBasicBlock *is_ref_bb, *end_bb;
9425                                                 MonoInst *nonbox_call;
9426
9427                                                 /*
9428                                                  * Determine at runtime whenever the called method is defined on object/valuetype/enum, and emit a boxing call
9429                                                  * if needed.
9430                                                  * FIXME: It is possible to inline the called method in a lot of cases, i.e. for T_INT,
9431                                                  * the no-box case goes to a method in Int32, while the box case goes to a method in Enum.
9432                                                  */
9433                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
9434
9435                                                 NEW_BBLOCK (cfg, is_ref_bb);
9436                                                 NEW_BBLOCK (cfg, end_bb);
9437
9438                                                 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);
9439                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, box_type->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
9440                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
9441
9442                                                 /* Non-ref case */
9443                                                 nonbox_call = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9444
9445                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9446
9447                                                 /* Ref case */
9448                                                 MONO_START_BB (cfg, is_ref_bb);
9449                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9450                                                 ins->klass = constrained_class;
9451                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9452                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9453
9454                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9455
9456                                                 MONO_START_BB (cfg, end_bb);
9457                                                 cfg->cbb = end_bb;
9458
9459                                                 nonbox_call->dreg = ins->dreg;
9460                                                 goto call_end;
9461                                         } else {
9462                                                 g_assert (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
9463                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
9464                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9465                                                 goto call_end;
9466                                         }
9467                                 } else if (constrained_class->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
9468                                         /*
9469                                          * The type parameter is instantiated as a valuetype,
9470                                          * but that type doesn't override the method we're
9471                                          * calling, so we need to box `this'.
9472                                          */
9473                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9474                                         ins->klass = constrained_class;
9475                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9476                                         CHECK_CFG_EXCEPTION;
9477                                 } else if (!constrained_class->valuetype) {
9478                                         int dreg = alloc_ireg_ref (cfg);
9479
9480                                         /*
9481                                          * The type parameter is instantiated as a reference
9482                                          * type.  We have a managed pointer on the stack, so
9483                                          * we need to dereference it here.
9484                                          */
9485                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
9486                                         ins->type = STACK_OBJ;
9487                                         sp [0] = ins;
9488                                 } else {
9489                                         if (cmethod->klass->valuetype) {
9490                                                 /* Own method */
9491                                         } else {
9492                                                 /* Interface method */
9493                                                 int ioffset, slot;
9494
9495                                                 mono_class_setup_vtable (constrained_class);
9496                                                 CHECK_TYPELOAD (constrained_class);
9497                                                 ioffset = mono_class_interface_offset (constrained_class, cmethod->klass);
9498                                                 if (ioffset == -1)
9499                                                         TYPE_LOAD_ERROR (constrained_class);
9500                                                 slot = mono_method_get_vtable_slot (cmethod);
9501                                                 if (slot == -1)
9502                                                         TYPE_LOAD_ERROR (cmethod->klass);
9503                                                 cmethod = constrained_class->vtable [ioffset + slot];
9504
9505                                                 if (cmethod->klass == mono_defaults.enum_class) {
9506                                                         /* Enum implements some interfaces, so treat this as the first case */
9507                                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9508                                                         ins->klass = constrained_class;
9509                                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9510                                                         CHECK_CFG_EXCEPTION;
9511                                                 }
9512                                         }
9513                                         virtual_ = 0;
9514                                 }
9515                                 constrained_class = NULL;
9516                         }
9517
9518                         if (check_call_signature (cfg, fsig, sp))
9519                                 UNVERIFIED;
9520
9521                         if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
9522                                 delegate_invoke = TRUE;
9523
9524                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
9525                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9526                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9527                                         emit_widen = FALSE;
9528                                 }
9529
9530                                 goto call_end;
9531                         }
9532
9533                         /* 
9534                          * If the callee is a shared method, then its static cctor
9535                          * might not get called after the call was patched.
9536                          */
9537                         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)) {
9538                                 emit_class_init (cfg, cmethod->klass);
9539                                 CHECK_TYPELOAD (cmethod->klass);
9540                         }
9541
9542                         check_method_sharing (cfg, cmethod, &pass_vtable, &pass_mrgctx);
9543
9544                         if (cfg->gshared) {
9545                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
9546
9547                                 context_used = mini_method_check_context_used (cfg, cmethod);
9548
9549                                 if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9550                                         /* Generic method interface
9551                                            calls are resolved via a
9552                                            helper function and don't
9553                                            need an imt. */
9554                                         if (!cmethod_context || !cmethod_context->method_inst)
9555                                                 pass_imt_from_rgctx = TRUE;
9556                                 }
9557
9558                                 /*
9559                                  * If a shared method calls another
9560                                  * shared method then the caller must
9561                                  * have a generic sharing context
9562                                  * because the magic trampoline
9563                                  * requires it.  FIXME: We shouldn't
9564                                  * have to force the vtable/mrgctx
9565                                  * variable here.  Instead there
9566                                  * should be a flag in the cfg to
9567                                  * request a generic sharing context.
9568                                  */
9569                                 if (context_used &&
9570                                                 ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
9571                                         mono_get_vtable_var (cfg);
9572                         }
9573
9574                         if (pass_vtable) {
9575                                 if (context_used) {
9576                                         vtable_arg = emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
9577                                 } else {
9578                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
9579
9580                                         CHECK_TYPELOAD (cmethod->klass);
9581                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
9582                                 }
9583                         }
9584
9585                         if (pass_mrgctx) {
9586                                 g_assert (!vtable_arg);
9587
9588                                 if (!cfg->compile_aot) {
9589                                         /* 
9590                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
9591                                          * for type load errors before.
9592                                          */
9593                                         mono_class_setup_vtable (cmethod->klass);
9594                                         CHECK_TYPELOAD (cmethod->klass);
9595                                 }
9596
9597                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
9598
9599                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
9600                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
9601                                          MONO_METHOD_IS_FINAL (cmethod)) &&
9602                                         !mono_class_is_marshalbyref (cmethod->klass)) {
9603                                         if (virtual_)
9604                                                 check_this = TRUE;
9605                                         virtual_ = 0;
9606                                 }
9607                         }
9608
9609                         if (pass_imt_from_rgctx) {
9610                                 g_assert (!pass_vtable);
9611
9612                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9613                                         cmethod, MONO_RGCTX_INFO_METHOD);
9614                         }
9615
9616                         if (check_this)
9617                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9618
9619                         /* Calling virtual generic methods */
9620                         if (virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) &&
9621                             !(MONO_METHOD_IS_FINAL (cmethod) && 
9622                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
9623                             fsig->generic_param_count && 
9624                                 !(cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) &&
9625                                 !cfg->llvm_only) {
9626                                 MonoInst *this_temp, *this_arg_temp, *store;
9627                                 MonoInst *iargs [4];
9628
9629                                 g_assert (fsig->is_inflated);
9630
9631                                 /* Prevent inlining of methods that contain indirect calls */
9632                                 INLINE_FAILURE ("virtual generic call");
9633
9634                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
9635                                         GSHAREDVT_FAILURE (*ip);
9636
9637                                 if (cfg->backend->have_generalized_imt_trampoline && cfg->backend->gshared_supported && cmethod->wrapper_type == MONO_WRAPPER_NONE) {
9638                                         g_assert (!imt_arg);
9639                                         if (!context_used)
9640                                                 g_assert (cmethod->is_inflated);
9641                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
9642                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
9643                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, sp [0], imt_arg, NULL);
9644                                 } else {
9645                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
9646                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
9647                                         MONO_ADD_INS (cfg->cbb, store);
9648
9649                                         /* FIXME: This should be a managed pointer */
9650                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
9651
9652                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
9653                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
9654                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
9655                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
9656                                         addr = mono_emit_jit_icall (cfg,
9657                                                                                                 mono_helper_compile_generic_method, iargs);
9658
9659                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
9660
9661                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9662                                 }
9663
9664                                 goto call_end;
9665                         }
9666
9667                         /*
9668                          * Implement a workaround for the inherent races involved in locking:
9669                          * Monitor.Enter ()
9670                          * try {
9671                          * } finally {
9672                          *    Monitor.Exit ()
9673                          * }
9674                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
9675                          * try block, the Exit () won't be executed, see:
9676                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
9677                          * To work around this, we extend such try blocks to include the last x bytes
9678                          * of the Monitor.Enter () call.
9679                          */
9680                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
9681                                 MonoBasicBlock *tbb;
9682
9683                                 GET_BBLOCK (cfg, tbb, ip + 5);
9684                                 /* 
9685                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
9686                                  * from Monitor.Enter like ArgumentNullException.
9687                                  */
9688                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
9689                                         /* Mark this bblock as needing to be extended */
9690                                         tbb->extend_try_block = TRUE;
9691                                 }
9692                         }
9693
9694                         /* Conversion to a JIT intrinsic */
9695                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
9696                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9697                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9698                                         emit_widen = FALSE;
9699                                 }
9700                                 goto call_end;
9701                         }
9702                         CHECK_CFG_ERROR;
9703                         
9704                         /* Inlining */
9705                         if ((cfg->opt & MONO_OPT_INLINE) &&
9706                                 (!virtual_ || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
9707                             mono_method_check_inlining (cfg, cmethod)) {
9708                                 int costs;
9709                                 gboolean always = FALSE;
9710
9711                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
9712                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
9713                                         /* Prevent inlining of methods that call wrappers */
9714                                         INLINE_FAILURE ("wrapper call");
9715                                         cmethod = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
9716                                         always = TRUE;
9717                                 }
9718
9719                                 costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, always);
9720                                 if (costs) {
9721                                         cfg->real_offset += 5;
9722
9723                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9724                                                 /* *sp is already set by inline_method */
9725                                                 sp++;
9726                                                 push_res = FALSE;
9727                                         }
9728
9729                                         inline_costs += costs;
9730
9731                                         goto call_end;
9732                                 }
9733                         }
9734
9735                         /* Tail recursion elimination */
9736                         if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
9737                                 gboolean has_vtargs = FALSE;
9738                                 int i;
9739
9740                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9741                                 INLINE_FAILURE ("tail call");
9742
9743                                 /* keep it simple */
9744                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
9745                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
9746                                                 has_vtargs = TRUE;
9747                                 }
9748
9749                                 if (!has_vtargs) {
9750                                         if (need_seq_point) {
9751                                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
9752                                                 need_seq_point = FALSE;
9753                                         }
9754                                         for (i = 0; i < n; ++i)
9755                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9756                                         MONO_INST_NEW (cfg, ins, OP_BR);
9757                                         MONO_ADD_INS (cfg->cbb, ins);
9758                                         tblock = start_bblock->out_bb [0];
9759                                         link_bblock (cfg, cfg->cbb, tblock);
9760                                         ins->inst_target_bb = tblock;
9761                                         start_new_bblock = 1;
9762
9763                                         /* skip the CEE_RET, too */
9764                                         if (ip_in_bb (cfg, cfg->cbb, ip + 5))
9765                                                 skip_ret = TRUE;
9766                                         push_res = FALSE;
9767                                         goto call_end;
9768                                 }
9769                         }
9770
9771                         inline_costs += 10 * num_calls++;
9772
9773                         /*
9774                          * Synchronized wrappers.
9775                          * Its hard to determine where to replace a method with its synchronized
9776                          * wrapper without causing an infinite recursion. The current solution is
9777                          * to add the synchronized wrapper in the trampolines, and to
9778                          * change the called method to a dummy wrapper, and resolve that wrapper
9779                          * to the real method in mono_jit_compile_method ().
9780                          */
9781                         if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
9782                                 MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
9783                                 if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
9784                                         cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
9785                         }
9786
9787                         /*
9788                          * Making generic calls out of gsharedvt methods.
9789                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9790                          * patching gshared method addresses into a gsharedvt method.
9791                          */
9792                         if (cfg->gsharedvt && (mini_is_gsharedvt_signature (fsig) || cmethod->is_inflated || cmethod->klass->generic_class) &&
9793                                 !(cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY) &&
9794                                 (!(cfg->llvm_only && virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)))) {
9795                                 MonoRgctxInfoType info_type;
9796
9797                                 if (virtual_) {
9798                                         //if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
9799                                                 //GSHAREDVT_FAILURE (*ip);
9800                                         // disable for possible remoting calls
9801                                         if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
9802                                                 GSHAREDVT_FAILURE (*ip);
9803                                         if (fsig->generic_param_count) {
9804                                                 /* virtual generic call */
9805                                                 g_assert (!imt_arg);
9806                                                 /* Same as the virtual generic case above */
9807                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9808                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9809                                                 /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
9810                                                 vtable_arg = NULL;
9811                                         } else if ((cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !imt_arg) {
9812                                                 /* This can happen when we call a fully instantiated iface method */
9813                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9814                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9815                                                 vtable_arg = NULL;
9816                                         }
9817                                 }
9818
9819                                 if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
9820                                         keep_this_alive = sp [0];
9821
9822                                 if (virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
9823                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
9824                                 else
9825                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
9826                                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
9827
9828                                 if (cfg->llvm_only) {
9829                                         // FIXME: Avoid initializing vtable_arg
9830                                         ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
9831                                 } else {
9832                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9833                                 }
9834                                 goto call_end;
9835                         }
9836
9837                         /* Generic sharing */
9838
9839                         /*
9840                          * Use this if the callee is gsharedvt sharable too, since
9841                          * at runtime we might find an instantiation so the call cannot
9842                          * be patched (the 'no_patch' code path in mini-trampolines.c).
9843                          */
9844                         if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
9845                                 (!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
9846                                  !mono_class_generic_sharing_enabled (cmethod->klass)) &&
9847                                 (!virtual_ || MONO_METHOD_IS_FINAL (cmethod) ||
9848                                  !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
9849                                 INLINE_FAILURE ("gshared");
9850
9851                                 g_assert (cfg->gshared && cmethod);
9852                                 g_assert (!addr);
9853
9854                                 /*
9855                                  * We are compiling a call to a
9856                                  * generic method from shared code,
9857                                  * which means that we have to look up
9858                                  * the method in the rgctx and do an
9859                                  * indirect call.
9860                                  */
9861                                 if (fsig->hasthis)
9862                                         MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9863
9864                                 if (cfg->llvm_only) {
9865                                         if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig))
9866                                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER);
9867                                         else
9868                                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9869                                         // FIXME: Avoid initializing imt_arg/vtable_arg
9870                                         ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
9871                                 } else {
9872                                         addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9873                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9874                                 }
9875                                 goto call_end;
9876                         }
9877
9878                         /* Direct calls to icalls */
9879                         if (direct_icall) {
9880                                 MonoMethod *wrapper;
9881                                 int costs;
9882
9883                                 /* Inline the wrapper */
9884                                 wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
9885
9886                                 costs = inline_method (cfg, wrapper, fsig, sp, ip, cfg->real_offset, TRUE);
9887                                 g_assert (costs > 0);
9888                                 cfg->real_offset += 5;
9889
9890                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9891                                         /* *sp is already set by inline_method */
9892                                         sp++;
9893                                         push_res = FALSE;
9894                                 }
9895
9896                                 inline_costs += costs;
9897
9898                                 goto call_end;
9899                         }
9900                                         
9901                         /* Array methods */
9902                         if (array_rank) {
9903                                 MonoInst *addr;
9904
9905                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
9906                                         MonoInst *val = sp [fsig->param_count];
9907
9908                                         if (val->type == STACK_OBJ) {
9909                                                 MonoInst *iargs [2];
9910
9911                                                 iargs [0] = sp [0];
9912                                                 iargs [1] = val;
9913                                                 
9914                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
9915                                         }
9916                                         
9917                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
9918                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
9919                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !MONO_INS_IS_PCONST_NULL (val))
9920                                                 emit_write_barrier (cfg, addr, val);
9921                                         if (cfg->gen_write_barriers && mini_is_gsharedvt_klass (cmethod->klass))
9922                                                 GSHAREDVT_FAILURE (*ip);
9923                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
9924                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9925
9926                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
9927                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
9928                                         if (!cmethod->klass->element_class->valuetype && !readonly)
9929                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
9930                                         CHECK_TYPELOAD (cmethod->klass);
9931                                         
9932                                         readonly = FALSE;
9933                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9934                                         ins = addr;
9935                                 } else {
9936                                         g_assert_not_reached ();
9937                                 }
9938
9939                                 emit_widen = FALSE;
9940                                 goto call_end;
9941                         }
9942
9943                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual_ ? sp [0] : NULL);
9944                         if (ins)
9945                                 goto call_end;
9946
9947                         /* Tail prefix / tail call optimization */
9948
9949                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
9950                         /* FIXME: runtime generic context pointer for jumps? */
9951                         /* FIXME: handle this for generic sharing eventually */
9952                         if ((ins_flag & MONO_INST_TAILCALL) &&
9953                                 !vtable_arg && !cfg->gshared && is_supported_tail_call (cfg, method, cmethod, fsig, call_opcode))
9954                                 supported_tail_call = TRUE;
9955
9956                         if (supported_tail_call) {
9957                                 MonoCallInst *call;
9958
9959                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9960                                 INLINE_FAILURE ("tail call");
9961
9962                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
9963
9964                                 if (cfg->backend->have_op_tail_call) {
9965                                         /* Handle tail calls similarly to normal calls */
9966                                         tail_call = TRUE;
9967                                 } else {
9968                                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
9969
9970                                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9971                                         call->tail_call = TRUE;
9972                                         call->method = cmethod;
9973                                         call->signature = mono_method_signature (cmethod);
9974
9975                                         /*
9976                                          * We implement tail calls by storing the actual arguments into the 
9977                                          * argument variables, then emitting a CEE_JMP.
9978                                          */
9979                                         for (i = 0; i < n; ++i) {
9980                                                 /* Prevent argument from being register allocated */
9981                                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
9982                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9983                                         }
9984                                         ins = (MonoInst*)call;
9985                                         ins->inst_p0 = cmethod;
9986                                         ins->inst_p1 = arg_array [0];
9987                                         MONO_ADD_INS (cfg->cbb, ins);
9988                                         link_bblock (cfg, cfg->cbb, end_bblock);
9989                                         start_new_bblock = 1;
9990
9991                                         // FIXME: Eliminate unreachable epilogs
9992
9993                                         /*
9994                                          * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9995                                          * only reachable from this call.
9996                                          */
9997                                         GET_BBLOCK (cfg, tblock, ip + 5);
9998                                         if (tblock == cfg->cbb || tblock->in_count == 0)
9999                                                 skip_ret = TRUE;
10000                                         push_res = FALSE;
10001
10002                                         goto call_end;
10003                                 }
10004                         }
10005
10006                         /*
10007                          * Virtual calls in llvm-only mode.
10008                          */
10009                         if (cfg->llvm_only && virtual_ && cmethod && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
10010                                 ins = emit_llvmonly_virtual_call (cfg, cmethod, fsig, context_used, sp);
10011                                 goto call_end;
10012                         }
10013
10014                         /* Common call */
10015                         INLINE_FAILURE ("call");
10016                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual_ ? sp [0] : NULL,
10017                                                                                           imt_arg, vtable_arg);
10018
10019                         if (tail_call && !cfg->llvm_only) {
10020                                 link_bblock (cfg, cfg->cbb, end_bblock);
10021                                 start_new_bblock = 1;
10022
10023                                 // FIXME: Eliminate unreachable epilogs
10024
10025                                 /*
10026                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
10027                                  * only reachable from this call.
10028                                  */
10029                                 GET_BBLOCK (cfg, tblock, ip + 5);
10030                                 if (tblock == cfg->cbb || tblock->in_count == 0)
10031                                         skip_ret = TRUE;
10032                                 push_res = FALSE;
10033                         }
10034
10035                         call_end:
10036
10037                         /* End of call, INS should contain the result of the call, if any */
10038
10039                         if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
10040                                 g_assert (ins);
10041                                 if (emit_widen)
10042                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
10043                                 else
10044                                         *sp++ = ins;
10045                         }
10046
10047                         if (keep_this_alive) {
10048                                 MonoInst *dummy_use;
10049
10050                                 /* See mono_emit_method_call_full () */
10051                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
10052                         }
10053
10054                         if (cfg->llvm_only && cmethod && method_needs_stack_walk (cfg, cmethod)) {
10055                                 /*
10056                                  * Clang can convert these calls to tail calls which screw up the stack
10057                                  * walk. This happens even when the -fno-optimize-sibling-calls
10058                                  * option is passed to clang.
10059                                  * Work around this by emitting a dummy call.
10060                                  */
10061                                 mono_emit_jit_icall (cfg, mono_dummy_jit_icall, NULL);
10062                         }
10063
10064                         CHECK_CFG_EXCEPTION;
10065
10066                         ip += 5;
10067                         if (skip_ret) {
10068                                 g_assert (*ip == CEE_RET);
10069                                 ip += 1;
10070                         }
10071                         ins_flag = 0;
10072                         constrained_class = NULL;
10073                         if (need_seq_point)
10074                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10075                         break;
10076                 }
10077                 case CEE_RET:
10078                         if (cfg->method != method) {
10079                                 /* return from inlined method */
10080                                 /* 
10081                                  * If in_count == 0, that means the ret is unreachable due to
10082                                  * being preceeded by a throw. In that case, inline_method () will
10083                                  * handle setting the return value 
10084                                  * (test case: test_0_inline_throw ()).
10085                                  */
10086                                 if (return_var && cfg->cbb->in_count) {
10087                                         MonoType *ret_type = mono_method_signature (method)->ret;
10088
10089                                         MonoInst *store;
10090                                         CHECK_STACK (1);
10091                                         --sp;
10092
10093                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
10094                                                 UNVERIFIED;
10095
10096                                         //g_assert (returnvar != -1);
10097                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
10098                                         cfg->ret_var_set = TRUE;
10099                                 } 
10100                         } else {
10101                                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
10102
10103                                 if (cfg->lmf_var && cfg->cbb->in_count && !cfg->llvm_only)
10104                                         emit_pop_lmf (cfg);
10105
10106                                 if (cfg->ret) {
10107                                         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (method)->ret);
10108
10109                                         if (seq_points && !sym_seq_points) {
10110                                                 /* 
10111                                                  * Place a seq point here too even through the IL stack is not
10112                                                  * empty, so a step over on
10113                                                  * call <FOO>
10114                                                  * ret
10115                                                  * will work correctly.
10116                                                  */
10117                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
10118                                                 MONO_ADD_INS (cfg->cbb, ins);
10119                                         }
10120
10121                                         g_assert (!return_var);
10122                                         CHECK_STACK (1);
10123                                         --sp;
10124
10125                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
10126                                                 UNVERIFIED;
10127
10128                                         emit_setret (cfg, *sp);
10129                                 }
10130                         }
10131                         if (sp != stack_start)
10132                                 UNVERIFIED;
10133                         MONO_INST_NEW (cfg, ins, OP_BR);
10134                         ip++;
10135                         ins->inst_target_bb = end_bblock;
10136                         MONO_ADD_INS (cfg->cbb, ins);
10137                         link_bblock (cfg, cfg->cbb, end_bblock);
10138                         start_new_bblock = 1;
10139                         break;
10140                 case CEE_BR_S:
10141                         CHECK_OPSIZE (2);
10142                         MONO_INST_NEW (cfg, ins, OP_BR);
10143                         ip++;
10144                         target = ip + 1 + (signed char)(*ip);
10145                         ++ip;
10146                         GET_BBLOCK (cfg, tblock, target);
10147                         link_bblock (cfg, cfg->cbb, tblock);
10148                         ins->inst_target_bb = tblock;
10149                         if (sp != stack_start) {
10150                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10151                                 sp = stack_start;
10152                                 CHECK_UNVERIFIABLE (cfg);
10153                         }
10154                         MONO_ADD_INS (cfg->cbb, ins);
10155                         start_new_bblock = 1;
10156                         inline_costs += BRANCH_COST;
10157                         break;
10158                 case CEE_BEQ_S:
10159                 case CEE_BGE_S:
10160                 case CEE_BGT_S:
10161                 case CEE_BLE_S:
10162                 case CEE_BLT_S:
10163                 case CEE_BNE_UN_S:
10164                 case CEE_BGE_UN_S:
10165                 case CEE_BGT_UN_S:
10166                 case CEE_BLE_UN_S:
10167                 case CEE_BLT_UN_S:
10168                         CHECK_OPSIZE (2);
10169                         CHECK_STACK (2);
10170                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
10171                         ip++;
10172                         target = ip + 1 + *(signed char*)ip;
10173                         ip++;
10174
10175                         ADD_BINCOND (NULL);
10176
10177                         sp = stack_start;
10178                         inline_costs += BRANCH_COST;
10179                         break;
10180                 case CEE_BR:
10181                         CHECK_OPSIZE (5);
10182                         MONO_INST_NEW (cfg, ins, OP_BR);
10183                         ip++;
10184
10185                         target = ip + 4 + (gint32)read32(ip);
10186                         ip += 4;
10187                         GET_BBLOCK (cfg, tblock, target);
10188                         link_bblock (cfg, cfg->cbb, tblock);
10189                         ins->inst_target_bb = tblock;
10190                         if (sp != stack_start) {
10191                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10192                                 sp = stack_start;
10193                                 CHECK_UNVERIFIABLE (cfg);
10194                         }
10195
10196                         MONO_ADD_INS (cfg->cbb, ins);
10197
10198                         start_new_bblock = 1;
10199                         inline_costs += BRANCH_COST;
10200                         break;
10201                 case CEE_BRFALSE_S:
10202                 case CEE_BRTRUE_S:
10203                 case CEE_BRFALSE:
10204                 case CEE_BRTRUE: {
10205                         MonoInst *cmp;
10206                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
10207                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
10208                         guint32 opsize = is_short ? 1 : 4;
10209
10210                         CHECK_OPSIZE (opsize);
10211                         CHECK_STACK (1);
10212                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
10213                                 UNVERIFIED;
10214                         ip ++;
10215                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
10216                         ip += opsize;
10217
10218                         sp--;
10219
10220                         GET_BBLOCK (cfg, tblock, target);
10221                         link_bblock (cfg, cfg->cbb, tblock);
10222                         GET_BBLOCK (cfg, tblock, ip);
10223                         link_bblock (cfg, cfg->cbb, tblock);
10224
10225                         if (sp != stack_start) {
10226                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10227                                 CHECK_UNVERIFIABLE (cfg);
10228                         }
10229
10230                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
10231                         cmp->sreg1 = sp [0]->dreg;
10232                         type_from_op (cfg, cmp, sp [0], NULL);
10233                         CHECK_TYPE (cmp);
10234
10235 #if SIZEOF_REGISTER == 4
10236                         if (cmp->opcode == OP_LCOMPARE_IMM) {
10237                                 /* Convert it to OP_LCOMPARE */
10238                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
10239                                 ins->type = STACK_I8;
10240                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
10241                                 ins->inst_l = 0;
10242                                 MONO_ADD_INS (cfg->cbb, ins);
10243                                 cmp->opcode = OP_LCOMPARE;
10244                                 cmp->sreg2 = ins->dreg;
10245                         }
10246 #endif
10247                         MONO_ADD_INS (cfg->cbb, cmp);
10248
10249                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
10250                         type_from_op (cfg, ins, sp [0], NULL);
10251                         MONO_ADD_INS (cfg->cbb, ins);
10252                         ins->inst_many_bb = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
10253                         GET_BBLOCK (cfg, tblock, target);
10254                         ins->inst_true_bb = tblock;
10255                         GET_BBLOCK (cfg, tblock, ip);
10256                         ins->inst_false_bb = tblock;
10257                         start_new_bblock = 2;
10258
10259                         sp = stack_start;
10260                         inline_costs += BRANCH_COST;
10261                         break;
10262                 }
10263                 case CEE_BEQ:
10264                 case CEE_BGE:
10265                 case CEE_BGT:
10266                 case CEE_BLE:
10267                 case CEE_BLT:
10268                 case CEE_BNE_UN:
10269                 case CEE_BGE_UN:
10270                 case CEE_BGT_UN:
10271                 case CEE_BLE_UN:
10272                 case CEE_BLT_UN:
10273                         CHECK_OPSIZE (5);
10274                         CHECK_STACK (2);
10275                         MONO_INST_NEW (cfg, ins, *ip);
10276                         ip++;
10277                         target = ip + 4 + (gint32)read32(ip);
10278                         ip += 4;
10279
10280                         ADD_BINCOND (NULL);
10281
10282                         sp = stack_start;
10283                         inline_costs += BRANCH_COST;
10284                         break;
10285                 case CEE_SWITCH: {
10286                         MonoInst *src1;
10287                         MonoBasicBlock **targets;
10288                         MonoBasicBlock *default_bblock;
10289                         MonoJumpInfoBBTable *table;
10290                         int offset_reg = alloc_preg (cfg);
10291                         int target_reg = alloc_preg (cfg);
10292                         int table_reg = alloc_preg (cfg);
10293                         int sum_reg = alloc_preg (cfg);
10294                         gboolean use_op_switch;
10295
10296                         CHECK_OPSIZE (5);
10297                         CHECK_STACK (1);
10298                         n = read32 (ip + 1);
10299                         --sp;
10300                         src1 = sp [0];
10301                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
10302                                 UNVERIFIED;
10303
10304                         ip += 5;
10305                         CHECK_OPSIZE (n * sizeof (guint32));
10306                         target = ip + n * sizeof (guint32);
10307
10308                         GET_BBLOCK (cfg, default_bblock, target);
10309                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
10310
10311                         targets = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
10312                         for (i = 0; i < n; ++i) {
10313                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
10314                                 targets [i] = tblock;
10315                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
10316                                 ip += 4;
10317                         }
10318
10319                         if (sp != stack_start) {
10320                                 /* 
10321                                  * Link the current bb with the targets as well, so handle_stack_args
10322                                  * will set their in_stack correctly.
10323                                  */
10324                                 link_bblock (cfg, cfg->cbb, default_bblock);
10325                                 for (i = 0; i < n; ++i)
10326                                         link_bblock (cfg, cfg->cbb, targets [i]);
10327
10328                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10329                                 sp = stack_start;
10330                                 CHECK_UNVERIFIABLE (cfg);
10331
10332                                 /* Undo the links */
10333                                 mono_unlink_bblock (cfg, cfg->cbb, default_bblock);
10334                                 for (i = 0; i < n; ++i)
10335                                         mono_unlink_bblock (cfg, cfg->cbb, targets [i]);
10336                         }
10337
10338                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
10339                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
10340
10341                         for (i = 0; i < n; ++i)
10342                                 link_bblock (cfg, cfg->cbb, targets [i]);
10343
10344                         table = (MonoJumpInfoBBTable *)mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
10345                         table->table = targets;
10346                         table->table_size = n;
10347
10348                         use_op_switch = FALSE;
10349 #ifdef TARGET_ARM
10350                         /* ARM implements SWITCH statements differently */
10351                         /* FIXME: Make it use the generic implementation */
10352                         if (!cfg->compile_aot)
10353                                 use_op_switch = TRUE;
10354 #endif
10355
10356                         if (COMPILE_LLVM (cfg))
10357                                 use_op_switch = TRUE;
10358
10359                         cfg->cbb->has_jump_table = 1;
10360
10361                         if (use_op_switch) {
10362                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
10363                                 ins->sreg1 = src1->dreg;
10364                                 ins->inst_p0 = table;
10365                                 ins->inst_many_bb = targets;
10366                                 ins->klass = (MonoClass *)GUINT_TO_POINTER (n);
10367                                 MONO_ADD_INS (cfg->cbb, ins);
10368                         } else {
10369                                 if (sizeof (gpointer) == 8)
10370                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
10371                                 else
10372                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
10373
10374 #if SIZEOF_REGISTER == 8
10375                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
10376                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
10377 #endif
10378
10379                                 if (cfg->compile_aot) {
10380                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
10381                                 } else {
10382                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
10383                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
10384                                         ins->inst_p0 = table;
10385                                         ins->dreg = table_reg;
10386                                         MONO_ADD_INS (cfg->cbb, ins);
10387                                 }
10388
10389                                 /* FIXME: Use load_memindex */
10390                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
10391                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
10392                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
10393                         }
10394                         start_new_bblock = 1;
10395                         inline_costs += (BRANCH_COST * 2);
10396                         break;
10397                 }
10398                 case CEE_LDIND_I1:
10399                 case CEE_LDIND_U1:
10400                 case CEE_LDIND_I2:
10401                 case CEE_LDIND_U2:
10402                 case CEE_LDIND_I4:
10403                 case CEE_LDIND_U4:
10404                 case CEE_LDIND_I8:
10405                 case CEE_LDIND_I:
10406                 case CEE_LDIND_R4:
10407                 case CEE_LDIND_R8:
10408                 case CEE_LDIND_REF:
10409                         CHECK_STACK (1);
10410                         --sp;
10411
10412                         switch (*ip) {
10413                         case CEE_LDIND_R4:
10414                         case CEE_LDIND_R8:
10415                                 dreg = alloc_freg (cfg);
10416                                 break;
10417                         case CEE_LDIND_I8:
10418                                 dreg = alloc_lreg (cfg);
10419                                 break;
10420                         case CEE_LDIND_REF:
10421                                 dreg = alloc_ireg_ref (cfg);
10422                                 break;
10423                         default:
10424                                 dreg = alloc_preg (cfg);
10425                         }
10426
10427                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
10428                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
10429                         if (*ip == CEE_LDIND_R4)
10430                                 ins->type = cfg->r4_stack_type;
10431                         ins->flags |= ins_flag;
10432                         MONO_ADD_INS (cfg->cbb, ins);
10433                         *sp++ = ins;
10434                         if (ins_flag & MONO_INST_VOLATILE) {
10435                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10436                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10437                         }
10438                         ins_flag = 0;
10439                         ++ip;
10440                         break;
10441                 case CEE_STIND_REF:
10442                 case CEE_STIND_I1:
10443                 case CEE_STIND_I2:
10444                 case CEE_STIND_I4:
10445                 case CEE_STIND_I8:
10446                 case CEE_STIND_R4:
10447                 case CEE_STIND_R8:
10448                 case CEE_STIND_I:
10449                         CHECK_STACK (2);
10450                         sp -= 2;
10451
10452                         if (ins_flag & MONO_INST_VOLATILE) {
10453                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
10454                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
10455                         }
10456
10457                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
10458                         ins->flags |= ins_flag;
10459                         ins_flag = 0;
10460
10461                         MONO_ADD_INS (cfg->cbb, ins);
10462
10463                         if (cfg->gen_write_barriers && *ip == CEE_STIND_REF && method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER && !MONO_INS_IS_PCONST_NULL (sp [1]))
10464                                 emit_write_barrier (cfg, sp [0], sp [1]);
10465
10466                         inline_costs += 1;
10467                         ++ip;
10468                         break;
10469
10470                 case CEE_MUL:
10471                         CHECK_STACK (2);
10472
10473                         MONO_INST_NEW (cfg, ins, (*ip));
10474                         sp -= 2;
10475                         ins->sreg1 = sp [0]->dreg;
10476                         ins->sreg2 = sp [1]->dreg;
10477                         type_from_op (cfg, ins, sp [0], sp [1]);
10478                         CHECK_TYPE (ins);
10479                         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type);
10480
10481                         /* Use the immediate opcodes if possible */
10482                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
10483                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
10484                                 if (imm_opcode != -1) {
10485                                         ins->opcode = imm_opcode;
10486                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
10487                                         ins->sreg2 = -1;
10488
10489                                         NULLIFY_INS (sp [1]);
10490                                 }
10491                         }
10492
10493                         MONO_ADD_INS ((cfg)->cbb, (ins));
10494
10495                         *sp++ = mono_decompose_opcode (cfg, ins);
10496                         ip++;
10497                         break;
10498                 case CEE_ADD:
10499                 case CEE_SUB:
10500                 case CEE_DIV:
10501                 case CEE_DIV_UN:
10502                 case CEE_REM:
10503                 case CEE_REM_UN:
10504                 case CEE_AND:
10505                 case CEE_OR:
10506                 case CEE_XOR:
10507                 case CEE_SHL:
10508                 case CEE_SHR:
10509                 case CEE_SHR_UN:
10510                         CHECK_STACK (2);
10511
10512                         MONO_INST_NEW (cfg, ins, (*ip));
10513                         sp -= 2;
10514                         ins->sreg1 = sp [0]->dreg;
10515                         ins->sreg2 = sp [1]->dreg;
10516                         type_from_op (cfg, ins, sp [0], sp [1]);
10517                         CHECK_TYPE (ins);
10518                         add_widen_op (cfg, ins, &sp [0], &sp [1]);
10519                         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type);
10520
10521                         /* FIXME: Pass opcode to is_inst_imm */
10522
10523                         /* Use the immediate opcodes if possible */
10524                         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)) {
10525                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
10526                                 if (imm_opcode != -1) {
10527                                         ins->opcode = imm_opcode;
10528                                         if (sp [1]->opcode == OP_I8CONST) {
10529 #if SIZEOF_REGISTER == 8
10530                                                 ins->inst_imm = sp [1]->inst_l;
10531 #else
10532                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
10533                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
10534 #endif
10535                                         }
10536                                         else
10537                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
10538                                         ins->sreg2 = -1;
10539
10540                                         /* Might be followed by an instruction added by add_widen_op */
10541                                         if (sp [1]->next == NULL)
10542                                                 NULLIFY_INS (sp [1]);
10543                                 }
10544                         }
10545                         MONO_ADD_INS ((cfg)->cbb, (ins));
10546
10547                         *sp++ = mono_decompose_opcode (cfg, ins);
10548                         ip++;
10549                         break;
10550                 case CEE_NEG:
10551                 case CEE_NOT:
10552                 case CEE_CONV_I1:
10553                 case CEE_CONV_I2:
10554                 case CEE_CONV_I4:
10555                 case CEE_CONV_R4:
10556                 case CEE_CONV_R8:
10557                 case CEE_CONV_U4:
10558                 case CEE_CONV_I8:
10559                 case CEE_CONV_U8:
10560                 case CEE_CONV_OVF_I8:
10561                 case CEE_CONV_OVF_U8:
10562                 case CEE_CONV_R_UN:
10563                         CHECK_STACK (1);
10564
10565                         /* Special case this earlier so we have long constants in the IR */
10566                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
10567                                 int data = sp [-1]->inst_c0;
10568                                 sp [-1]->opcode = OP_I8CONST;
10569                                 sp [-1]->type = STACK_I8;
10570 #if SIZEOF_REGISTER == 8
10571                                 if ((*ip) == CEE_CONV_U8)
10572                                         sp [-1]->inst_c0 = (guint32)data;
10573                                 else
10574                                         sp [-1]->inst_c0 = data;
10575 #else
10576                                 sp [-1]->inst_ls_word = data;
10577                                 if ((*ip) == CEE_CONV_U8)
10578                                         sp [-1]->inst_ms_word = 0;
10579                                 else
10580                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
10581 #endif
10582                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
10583                         }
10584                         else {
10585                                 ADD_UNOP (*ip);
10586                         }
10587                         ip++;
10588                         break;
10589                 case CEE_CONV_OVF_I4:
10590                 case CEE_CONV_OVF_I1:
10591                 case CEE_CONV_OVF_I2:
10592                 case CEE_CONV_OVF_I:
10593                 case CEE_CONV_OVF_U:
10594                         CHECK_STACK (1);
10595
10596                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10597                                 ADD_UNOP (CEE_CONV_OVF_I8);
10598                                 ADD_UNOP (*ip);
10599                         } else {
10600                                 ADD_UNOP (*ip);
10601                         }
10602                         ip++;
10603                         break;
10604                 case CEE_CONV_OVF_U1:
10605                 case CEE_CONV_OVF_U2:
10606                 case CEE_CONV_OVF_U4:
10607                         CHECK_STACK (1);
10608
10609                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10610                                 ADD_UNOP (CEE_CONV_OVF_U8);
10611                                 ADD_UNOP (*ip);
10612                         } else {
10613                                 ADD_UNOP (*ip);
10614                         }
10615                         ip++;
10616                         break;
10617                 case CEE_CONV_OVF_I1_UN:
10618                 case CEE_CONV_OVF_I2_UN:
10619                 case CEE_CONV_OVF_I4_UN:
10620                 case CEE_CONV_OVF_I8_UN:
10621                 case CEE_CONV_OVF_U1_UN:
10622                 case CEE_CONV_OVF_U2_UN:
10623                 case CEE_CONV_OVF_U4_UN:
10624                 case CEE_CONV_OVF_U8_UN:
10625                 case CEE_CONV_OVF_I_UN:
10626                 case CEE_CONV_OVF_U_UN:
10627                 case CEE_CONV_U2:
10628                 case CEE_CONV_U1:
10629                 case CEE_CONV_I:
10630                 case CEE_CONV_U:
10631                         CHECK_STACK (1);
10632                         ADD_UNOP (*ip);
10633                         CHECK_CFG_EXCEPTION;
10634                         ip++;
10635                         break;
10636                 case CEE_ADD_OVF:
10637                 case CEE_ADD_OVF_UN:
10638                 case CEE_MUL_OVF:
10639                 case CEE_MUL_OVF_UN:
10640                 case CEE_SUB_OVF:
10641                 case CEE_SUB_OVF_UN:
10642                         CHECK_STACK (2);
10643                         ADD_BINOP (*ip);
10644                         ip++;
10645                         break;
10646                 case CEE_CPOBJ:
10647                         GSHAREDVT_FAILURE (*ip);
10648                         CHECK_OPSIZE (5);
10649                         CHECK_STACK (2);
10650                         token = read32 (ip + 1);
10651                         klass = mini_get_class (method, token, generic_context);
10652                         CHECK_TYPELOAD (klass);
10653                         sp -= 2;
10654                         if (generic_class_is_reference_type (cfg, klass)) {
10655                                 MonoInst *store, *load;
10656                                 int dreg = alloc_ireg_ref (cfg);
10657
10658                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
10659                                 load->flags |= ins_flag;
10660                                 MONO_ADD_INS (cfg->cbb, load);
10661
10662                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
10663                                 store->flags |= ins_flag;
10664                                 MONO_ADD_INS (cfg->cbb, store);
10665
10666                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
10667                                         emit_write_barrier (cfg, sp [0], sp [1]);
10668                         } else {
10669                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10670                         }
10671                         ins_flag = 0;
10672                         ip += 5;
10673                         break;
10674                 case CEE_LDOBJ: {
10675                         int loc_index = -1;
10676                         int stloc_len = 0;
10677
10678                         CHECK_OPSIZE (5);
10679                         CHECK_STACK (1);
10680                         --sp;
10681                         token = read32 (ip + 1);
10682                         klass = mini_get_class (method, token, generic_context);
10683                         CHECK_TYPELOAD (klass);
10684
10685                         /* Optimize the common ldobj+stloc combination */
10686                         switch (ip [5]) {
10687                         case CEE_STLOC_S:
10688                                 loc_index = ip [6];
10689                                 stloc_len = 2;
10690                                 break;
10691                         case CEE_STLOC_0:
10692                         case CEE_STLOC_1:
10693                         case CEE_STLOC_2:
10694                         case CEE_STLOC_3:
10695                                 loc_index = ip [5] - CEE_STLOC_0;
10696                                 stloc_len = 1;
10697                                 break;
10698                         default:
10699                                 break;
10700                         }
10701
10702                         if ((loc_index != -1) && ip_in_bb (cfg, cfg->cbb, ip + 5)) {
10703                                 CHECK_LOCAL (loc_index);
10704
10705                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10706                                 ins->dreg = cfg->locals [loc_index]->dreg;
10707                                 ins->flags |= ins_flag;
10708                                 ip += 5;
10709                                 ip += stloc_len;
10710                                 if (ins_flag & MONO_INST_VOLATILE) {
10711                                         /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10712                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10713                                 }
10714                                 ins_flag = 0;
10715                                 break;
10716                         }
10717
10718                         /* Optimize the ldobj+stobj combination */
10719                         /* The reference case ends up being a load+store anyway */
10720                         /* Skip this if the operation is volatile. */
10721                         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)) {
10722                                 CHECK_STACK (1);
10723
10724                                 sp --;
10725
10726                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10727
10728                                 ip += 5 + 5;
10729                                 ins_flag = 0;
10730                                 break;
10731                         }
10732
10733                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10734                         ins->flags |= ins_flag;
10735                         *sp++ = ins;
10736
10737                         if (ins_flag & MONO_INST_VOLATILE) {
10738                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10739                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10740                         }
10741
10742                         ip += 5;
10743                         ins_flag = 0;
10744                         inline_costs += 1;
10745                         break;
10746                 }
10747                 case CEE_LDSTR:
10748                         CHECK_STACK_OVF (1);
10749                         CHECK_OPSIZE (5);
10750                         n = read32 (ip + 1);
10751
10752                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
10753                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
10754                                 ins->type = STACK_OBJ;
10755                                 *sp = ins;
10756                         }
10757                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
10758                                 MonoInst *iargs [1];
10759                                 char *str = (char *)mono_method_get_wrapper_data (method, n);
10760
10761                                 if (cfg->compile_aot)
10762                                         EMIT_NEW_LDSTRLITCONST (cfg, iargs [0], str);
10763                                 else
10764                                         EMIT_NEW_PCONST (cfg, iargs [0], str);
10765                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
10766                         } else {
10767                                 if (cfg->opt & MONO_OPT_SHARED) {
10768                                         MonoInst *iargs [3];
10769
10770                                         if (cfg->compile_aot) {
10771                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
10772                                         }
10773                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10774                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
10775                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
10776                                         *sp = mono_emit_jit_icall (cfg, ves_icall_mono_ldstr, iargs);
10777                                         mono_ldstr_checked (cfg->domain, image, mono_metadata_token_index (n), &cfg->error);
10778                                         CHECK_CFG_ERROR;
10779                                 } else {
10780                                         if (cfg->cbb->out_of_line) {
10781                                                 MonoInst *iargs [2];
10782
10783                                                 if (image == mono_defaults.corlib) {
10784                                                         /* 
10785                                                          * Avoid relocations in AOT and save some space by using a 
10786                                                          * version of helper_ldstr specialized to mscorlib.
10787                                                          */
10788                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
10789                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
10790                                                 } else {
10791                                                         /* Avoid creating the string object */
10792                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
10793                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
10794                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
10795                                                 }
10796                                         } 
10797                                         else
10798                                         if (cfg->compile_aot) {
10799                                                 NEW_LDSTRCONST (cfg, ins, image, n);
10800                                                 *sp = ins;
10801                                                 MONO_ADD_INS (cfg->cbb, ins);
10802                                         } 
10803                                         else {
10804                                                 NEW_PCONST (cfg, ins, NULL);
10805                                                 ins->type = STACK_OBJ;
10806                                                 ins->inst_p0 = mono_ldstr_checked (cfg->domain, image, mono_metadata_token_index (n), &cfg->error);
10807                                                 CHECK_CFG_ERROR;
10808                                                 
10809                                                 if (!ins->inst_p0)
10810                                                         OUT_OF_MEMORY_FAILURE;
10811
10812                                                 *sp = ins;
10813                                                 MONO_ADD_INS (cfg->cbb, ins);
10814                                         }
10815                                 }
10816                         }
10817
10818                         sp++;
10819                         ip += 5;
10820                         break;
10821                 case CEE_NEWOBJ: {
10822                         MonoInst *iargs [2];
10823                         MonoMethodSignature *fsig;
10824                         MonoInst this_ins;
10825                         MonoInst *alloc;
10826                         MonoInst *vtable_arg = NULL;
10827
10828                         CHECK_OPSIZE (5);
10829                         token = read32 (ip + 1);
10830                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
10831                         CHECK_CFG_ERROR;
10832
10833                         fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
10834                         CHECK_CFG_ERROR;
10835
10836                         mono_save_token_info (cfg, image, token, cmethod);
10837
10838                         if (!mono_class_init (cmethod->klass))
10839                                 TYPE_LOAD_ERROR (cmethod->klass);
10840
10841                         context_used = mini_method_check_context_used (cfg, cmethod);
10842
10843                         if (mono_security_core_clr_enabled ())
10844                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
10845
10846                         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)) {
10847                                 emit_class_init (cfg, cmethod->klass);
10848                                 CHECK_TYPELOAD (cmethod->klass);
10849                         }
10850
10851                         /*
10852                         if (cfg->gsharedvt) {
10853                                 if (mini_is_gsharedvt_variable_signature (sig))
10854                                         GSHAREDVT_FAILURE (*ip);
10855                         }
10856                         */
10857
10858                         n = fsig->param_count;
10859                         CHECK_STACK (n);
10860
10861                         /* 
10862                          * Generate smaller code for the common newobj <exception> instruction in
10863                          * argument checking code.
10864                          */
10865                         if (cfg->cbb->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
10866                                 is_exception_class (cmethod->klass) && n <= 2 &&
10867                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
10868                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
10869                                 MonoInst *iargs [3];
10870
10871                                 sp -= n;
10872
10873                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
10874                                 switch (n) {
10875                                 case 0:
10876                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
10877                                         break;
10878                                 case 1:
10879                                         iargs [1] = sp [0];
10880                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
10881                                         break;
10882                                 case 2:
10883                                         iargs [1] = sp [0];
10884                                         iargs [2] = sp [1];
10885                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
10886                                         break;
10887                                 default:
10888                                         g_assert_not_reached ();
10889                                 }
10890
10891                                 ip += 5;
10892                                 inline_costs += 5;
10893                                 break;
10894                         }
10895
10896                         /* move the args to allow room for 'this' in the first position */
10897                         while (n--) {
10898                                 --sp;
10899                                 sp [1] = sp [0];
10900                         }
10901
10902                         /* check_call_signature () requires sp[0] to be set */
10903                         this_ins.type = STACK_OBJ;
10904                         sp [0] = &this_ins;
10905                         if (check_call_signature (cfg, fsig, sp))
10906                                 UNVERIFIED;
10907
10908                         iargs [0] = NULL;
10909
10910                         if (mini_class_is_system_array (cmethod->klass)) {
10911                                 *sp = emit_get_rgctx_method (cfg, context_used,
10912                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
10913
10914                                 /* Avoid varargs in the common case */
10915                                 if (fsig->param_count == 1)
10916                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
10917                                 else if (fsig->param_count == 2)
10918                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
10919                                 else if (fsig->param_count == 3)
10920                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
10921                                 else if (fsig->param_count == 4)
10922                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
10923                                 else
10924                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
10925                         } else if (cmethod->string_ctor) {
10926                                 g_assert (!context_used);
10927                                 g_assert (!vtable_arg);
10928                                 /* we simply pass a null pointer */
10929                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
10930                                 /* now call the string ctor */
10931                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
10932                         } else {
10933                                 if (cmethod->klass->valuetype) {
10934                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
10935                                         emit_init_rvar (cfg, iargs [0]->dreg, &cmethod->klass->byval_arg);
10936                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
10937
10938                                         alloc = NULL;
10939
10940                                         /* 
10941                                          * The code generated by mini_emit_virtual_call () expects
10942                                          * iargs [0] to be a boxed instance, but luckily the vcall
10943                                          * will be transformed into a normal call there.
10944                                          */
10945                                 } else if (context_used) {
10946                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
10947                                         *sp = alloc;
10948                                 } else {
10949                                         MonoVTable *vtable = NULL;
10950
10951                                         if (!cfg->compile_aot)
10952                                                 vtable = mono_class_vtable (cfg->domain, cmethod->klass);
10953                                         CHECK_TYPELOAD (cmethod->klass);
10954
10955                                         /*
10956                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
10957                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
10958                                          * As a workaround, we call class cctors before allocating objects.
10959                                          */
10960                                         if (mini_field_access_needs_cctor_run (cfg, method, cmethod->klass, vtable) && !(g_slist_find (class_inits, cmethod->klass))) {
10961                                                 emit_class_init (cfg, cmethod->klass);
10962                                                 if (cfg->verbose_level > 2)
10963                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
10964                                                 class_inits = g_slist_prepend (class_inits, cmethod->klass);
10965                                         }
10966
10967                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
10968                                         *sp = alloc;
10969                                 }
10970                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
10971
10972                                 if (alloc)
10973                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
10974
10975                                 /* Now call the actual ctor */
10976                                 handle_ctor_call (cfg, cmethod, fsig, context_used, sp, ip, &inline_costs);
10977                                 CHECK_CFG_EXCEPTION;
10978                         }
10979
10980                         if (alloc == NULL) {
10981                                 /* Valuetype */
10982                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
10983                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
10984                                 *sp++= ins;
10985                         } else {
10986                                 *sp++ = alloc;
10987                         }
10988                         
10989                         ip += 5;
10990                         inline_costs += 5;
10991                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip - header->code)))
10992                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10993                         break;
10994                 }
10995                 case CEE_CASTCLASS:
10996                 case CEE_ISINST: {
10997                         CHECK_STACK (1);
10998                         --sp;
10999                         CHECK_OPSIZE (5);
11000                         token = read32 (ip + 1);
11001                         klass = mini_get_class (method, token, generic_context);
11002                         CHECK_TYPELOAD (klass);
11003                         if (sp [0]->type != STACK_OBJ)
11004                                 UNVERIFIED;
11005
11006                         MONO_INST_NEW (cfg, ins, *ip == CEE_ISINST ? OP_ISINST : OP_CASTCLASS);
11007                         ins->dreg = alloc_preg (cfg);
11008                         ins->sreg1 = (*sp)->dreg;
11009                         ins->klass = klass;
11010                         ins->type = STACK_OBJ;
11011                         MONO_ADD_INS (cfg->cbb, ins);
11012
11013                         CHECK_CFG_EXCEPTION;
11014                         *sp++ = ins;
11015                         ip += 5;
11016
11017                         cfg->flags |= MONO_CFG_HAS_TYPE_CHECK;
11018                         break;
11019                 }
11020                 case CEE_UNBOX_ANY: {
11021                         MonoInst *res, *addr;
11022
11023                         CHECK_STACK (1);
11024                         --sp;
11025                         CHECK_OPSIZE (5);
11026                         token = read32 (ip + 1);
11027                         klass = mini_get_class (method, token, generic_context);
11028                         CHECK_TYPELOAD (klass);
11029
11030                         mono_save_token_info (cfg, image, token, klass);
11031
11032                         context_used = mini_class_check_context_used (cfg, klass);
11033
11034                         if (mini_is_gsharedvt_klass (klass)) {
11035                                 res = handle_unbox_gsharedvt (cfg, klass, *sp);
11036                                 inline_costs += 2;
11037                         } else if (generic_class_is_reference_type (cfg, klass)) {
11038                                 if (MONO_INS_IS_PCONST_NULL (*sp)) {
11039                                         EMIT_NEW_PCONST (cfg, res, NULL);
11040                                         res->type = STACK_OBJ;
11041                                 } else {
11042                                         MONO_INST_NEW (cfg, res, OP_CASTCLASS);
11043                                         res->dreg = alloc_preg (cfg);
11044                                         res->sreg1 = (*sp)->dreg;
11045                                         res->klass = klass;
11046                                         res->type = STACK_OBJ;
11047                                         MONO_ADD_INS (cfg->cbb, res);
11048                                         cfg->flags |= MONO_CFG_HAS_TYPE_CHECK;
11049                                 }
11050                         } else if (mono_class_is_nullable (klass)) {
11051                                 res = handle_unbox_nullable (cfg, *sp, klass, context_used);
11052                         } else {
11053                                 addr = handle_unbox (cfg, klass, sp, context_used);
11054                                 /* LDOBJ */
11055                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11056                                 res = ins;
11057                                 inline_costs += 2;
11058                         }
11059
11060                         *sp ++ = res;
11061                         ip += 5;
11062                         break;
11063                 }
11064                 case CEE_BOX: {
11065                         MonoInst *val;
11066                         MonoClass *enum_class;
11067                         MonoMethod *has_flag;
11068
11069                         CHECK_STACK (1);
11070                         --sp;
11071                         val = *sp;
11072                         CHECK_OPSIZE (5);
11073                         token = read32 (ip + 1);
11074                         klass = mini_get_class (method, token, generic_context);
11075                         CHECK_TYPELOAD (klass);
11076
11077                         mono_save_token_info (cfg, image, token, klass);
11078
11079                         context_used = mini_class_check_context_used (cfg, klass);
11080
11081                         if (generic_class_is_reference_type (cfg, klass)) {
11082                                 *sp++ = val;
11083                                 ip += 5;
11084                                 break;
11085                         }
11086
11087                         if (klass == mono_defaults.void_class)
11088                                 UNVERIFIED;
11089                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
11090                                 UNVERIFIED;
11091                         /* frequent check in generic code: box (struct), brtrue */
11092
11093                         /*
11094                          * Look for:
11095                          *
11096                          *   <push int/long ptr>
11097                          *   <push int/long>
11098                          *   box MyFlags
11099                          *   constrained. MyFlags
11100                          *   callvirt instace bool class [mscorlib] System.Enum::HasFlag (class [mscorlib] System.Enum)
11101                          *
11102                          * If we find this sequence and the operand types on box and constrained
11103                          * are equal, we can emit a specialized instruction sequence instead of
11104                          * the very slow HasFlag () call.
11105                          */
11106                         if ((cfg->opt & MONO_OPT_INTRINS) &&
11107                             /* Cheap checks first. */
11108                             ip + 5 + 6 + 5 < end &&
11109                             ip [5] == CEE_PREFIX1 &&
11110                             ip [6] == CEE_CONSTRAINED_ &&
11111                             ip [11] == CEE_CALLVIRT &&
11112                             ip_in_bb (cfg, cfg->cbb, ip + 5 + 6 + 5) &&
11113                             mono_class_is_enum (klass) &&
11114                             (enum_class = mini_get_class (method, read32 (ip + 7), generic_context)) &&
11115                             (has_flag = mini_get_method (cfg, method, read32 (ip + 12), NULL, generic_context)) &&
11116                             has_flag->klass == mono_defaults.enum_class &&
11117                             !strcmp (has_flag->name, "HasFlag") &&
11118                             has_flag->signature->hasthis &&
11119                             has_flag->signature->param_count == 1) {
11120                                 CHECK_TYPELOAD (enum_class);
11121
11122                                 if (enum_class == klass) {
11123                                         MonoInst *enum_this, *enum_flag;
11124
11125                                         ip += 5 + 6 + 5;
11126                                         --sp;
11127
11128                                         enum_this = sp [0];
11129                                         enum_flag = sp [1];
11130
11131                                         *sp++ = handle_enum_has_flag (cfg, klass, enum_this, enum_flag);
11132                                         break;
11133                                 }
11134                         }
11135
11136                         // FIXME: LLVM can't handle the inconsistent bb linking
11137                         if (!mono_class_is_nullable (klass) &&
11138                                 !mini_is_gsharedvt_klass (klass) &&
11139                                 ip + 5 < end && ip_in_bb (cfg, cfg->cbb, ip + 5) &&
11140                                 (ip [5] == CEE_BRTRUE || 
11141                                  ip [5] == CEE_BRTRUE_S ||
11142                                  ip [5] == CEE_BRFALSE ||
11143                                  ip [5] == CEE_BRFALSE_S)) {
11144                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
11145                                 int dreg;
11146                                 MonoBasicBlock *true_bb, *false_bb;
11147
11148                                 ip += 5;
11149
11150                                 if (cfg->verbose_level > 3) {
11151                                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
11152                                         printf ("<box+brtrue opt>\n");
11153                                 }
11154
11155                                 switch (*ip) {
11156                                 case CEE_BRTRUE_S:
11157                                 case CEE_BRFALSE_S:
11158                                         CHECK_OPSIZE (2);
11159                                         ip++;
11160                                         target = ip + 1 + (signed char)(*ip);
11161                                         ip++;
11162                                         break;
11163                                 case CEE_BRTRUE:
11164                                 case CEE_BRFALSE:
11165                                         CHECK_OPSIZE (5);
11166                                         ip++;
11167                                         target = ip + 4 + (gint)(read32 (ip));
11168                                         ip += 4;
11169                                         break;
11170                                 default:
11171                                         g_assert_not_reached ();
11172                                 }
11173
11174                                 /* 
11175                                  * We need to link both bblocks, since it is needed for handling stack
11176                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
11177                                  * Branching to only one of them would lead to inconsistencies, so
11178                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
11179                                  */
11180                                 GET_BBLOCK (cfg, true_bb, target);
11181                                 GET_BBLOCK (cfg, false_bb, ip);
11182
11183                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
11184                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
11185
11186                                 if (sp != stack_start) {
11187                                         handle_stack_args (cfg, stack_start, sp - stack_start);
11188                                         sp = stack_start;
11189                                         CHECK_UNVERIFIABLE (cfg);
11190                                 }
11191
11192                                 if (COMPILE_LLVM (cfg)) {
11193                                         dreg = alloc_ireg (cfg);
11194                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
11195                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
11196
11197                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
11198                                 } else {
11199                                         /* The JIT can't eliminate the iconst+compare */
11200                                         MONO_INST_NEW (cfg, ins, OP_BR);
11201                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
11202                                         MONO_ADD_INS (cfg->cbb, ins);
11203                                 }
11204
11205                                 start_new_bblock = 1;
11206                                 break;
11207                         }
11208
11209                         *sp++ = handle_box (cfg, val, klass, context_used);
11210
11211                         CHECK_CFG_EXCEPTION;
11212                         ip += 5;
11213                         inline_costs += 1;
11214                         break;
11215                 }
11216                 case CEE_UNBOX: {
11217                         CHECK_STACK (1);
11218                         --sp;
11219                         CHECK_OPSIZE (5);
11220                         token = read32 (ip + 1);
11221                         klass = mini_get_class (method, token, generic_context);
11222                         CHECK_TYPELOAD (klass);
11223
11224                         mono_save_token_info (cfg, image, token, klass);
11225
11226                         context_used = mini_class_check_context_used (cfg, klass);
11227
11228                         if (mono_class_is_nullable (klass)) {
11229                                 MonoInst *val;
11230
11231                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
11232                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
11233
11234                                 *sp++= ins;
11235                         } else {
11236                                 ins = handle_unbox (cfg, klass, sp, context_used);
11237                                 *sp++ = ins;
11238                         }
11239                         ip += 5;
11240                         inline_costs += 2;
11241                         break;
11242                 }
11243                 case CEE_LDFLD:
11244                 case CEE_LDFLDA:
11245                 case CEE_STFLD:
11246                 case CEE_LDSFLD:
11247                 case CEE_LDSFLDA:
11248                 case CEE_STSFLD: {
11249                         MonoClassField *field;
11250 #ifndef DISABLE_REMOTING
11251                         int costs;
11252 #endif
11253                         guint foffset;
11254                         gboolean is_instance;
11255                         int op;
11256                         gpointer addr = NULL;
11257                         gboolean is_special_static;
11258                         MonoType *ftype;
11259                         MonoInst *store_val = NULL;
11260                         MonoInst *thread_ins;
11261
11262                         op = *ip;
11263                         is_instance = (op == CEE_LDFLD || op == CEE_LDFLDA || op == CEE_STFLD);
11264                         if (is_instance) {
11265                                 if (op == CEE_STFLD) {
11266                                         CHECK_STACK (2);
11267                                         sp -= 2;
11268                                         store_val = sp [1];
11269                                 } else {
11270                                         CHECK_STACK (1);
11271                                         --sp;
11272                                 }
11273                                 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
11274                                         UNVERIFIED;
11275                                 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
11276                                         UNVERIFIED;
11277                         } else {
11278                                 if (op == CEE_STSFLD) {
11279                                         CHECK_STACK (1);
11280                                         sp--;
11281                                         store_val = sp [0];
11282                                 }
11283                         }
11284
11285                         CHECK_OPSIZE (5);
11286                         token = read32 (ip + 1);
11287                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
11288                                 field = (MonoClassField *)mono_method_get_wrapper_data (method, token);
11289                                 klass = field->parent;
11290                         }
11291                         else {
11292                                 field = mono_field_from_token_checked (image, token, &klass, generic_context, &cfg->error);
11293                                 CHECK_CFG_ERROR;
11294                         }
11295                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
11296                                 FIELD_ACCESS_FAILURE (method, field);
11297                         mono_class_init (klass);
11298
11299                         /* if the class is Critical then transparent code cannot access it's fields */
11300                         if (!is_instance && mono_security_core_clr_enabled ())
11301                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
11302
11303                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
11304                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
11305                         if (mono_security_core_clr_enabled ())
11306                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
11307                         */
11308
11309                         ftype = mono_field_get_type (field);
11310
11311                         /*
11312                          * LDFLD etc. is usable on static fields as well, so convert those cases to
11313                          * the static case.
11314                          */
11315                         if (is_instance && ftype->attrs & FIELD_ATTRIBUTE_STATIC) {
11316                                 switch (op) {
11317                                 case CEE_LDFLD:
11318                                         op = CEE_LDSFLD;
11319                                         break;
11320                                 case CEE_STFLD:
11321                                         op = CEE_STSFLD;
11322                                         break;
11323                                 case CEE_LDFLDA:
11324                                         op = CEE_LDSFLDA;
11325                                         break;
11326                                 default:
11327                                         g_assert_not_reached ();
11328                                 }
11329                                 is_instance = FALSE;
11330                         }
11331
11332                         context_used = mini_class_check_context_used (cfg, klass);
11333
11334                         /* INSTANCE CASE */
11335
11336                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
11337                         if (op == CEE_STFLD) {
11338                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
11339                                         UNVERIFIED;
11340 #ifndef DISABLE_REMOTING
11341                                 if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
11342                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
11343                                         MonoInst *iargs [5];
11344
11345                                         GSHAREDVT_FAILURE (op);
11346
11347                                         iargs [0] = sp [0];
11348                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11349                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
11350                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
11351                                                     field->offset);
11352                                         iargs [4] = sp [1];
11353
11354                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
11355                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
11356                                                                                            iargs, ip, cfg->real_offset, TRUE);
11357                                                 CHECK_CFG_EXCEPTION;
11358                                                 g_assert (costs > 0);
11359                                                       
11360                                                 cfg->real_offset += 5;
11361
11362                                                 inline_costs += costs;
11363                                         } else {
11364                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
11365                                         }
11366                                 } else
11367 #endif
11368                                 {
11369                                         MonoInst *store, *wbarrier_ptr_ins = NULL;
11370
11371                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
11372
11373                                         if (ins_flag & MONO_INST_VOLATILE) {
11374                                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11375                                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11376                                         }
11377
11378                                         if (mini_is_gsharedvt_klass (klass)) {
11379                                                 MonoInst *offset_ins;
11380
11381                                                 context_used = mini_class_check_context_used (cfg, klass);
11382
11383                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11384                                                 /* The value is offset by 1 */
11385                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11386                                                 dreg = alloc_ireg_mp (cfg);
11387                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11388                                                 wbarrier_ptr_ins = ins;
11389                                                 /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
11390                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
11391                                         } else {
11392                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
11393                                         }
11394                                         if (sp [0]->opcode != OP_LDADDR)
11395                                                 store->flags |= MONO_INST_FAULT;
11396
11397                                         if (cfg->gen_write_barriers && mini_type_to_stind (cfg, field->type) == CEE_STIND_REF && !MONO_INS_IS_PCONST_NULL (sp [1])) {
11398                                                 if (mini_is_gsharedvt_klass (klass)) {
11399                                                         g_assert (wbarrier_ptr_ins);
11400                                                         emit_write_barrier (cfg, wbarrier_ptr_ins, sp [1]);
11401                                                 } else {
11402                                                         /* insert call to write barrier */
11403                                                         MonoInst *ptr;
11404                                                         int dreg;
11405
11406                                                         dreg = alloc_ireg_mp (cfg);
11407                                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
11408                                                         emit_write_barrier (cfg, ptr, sp [1]);
11409                                                 }
11410                                         }
11411
11412                                         store->flags |= ins_flag;
11413                                 }
11414                                 ins_flag = 0;
11415                                 ip += 5;
11416                                 break;
11417                         }
11418
11419 #ifndef DISABLE_REMOTING
11420                         if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
11421                                 MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
11422                                 MonoInst *iargs [4];
11423
11424                                 GSHAREDVT_FAILURE (op);
11425
11426                                 iargs [0] = sp [0];
11427                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11428                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
11429                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
11430                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
11431                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
11432                                                                                    iargs, ip, cfg->real_offset, TRUE);
11433                                         CHECK_CFG_EXCEPTION;
11434                                         g_assert (costs > 0);
11435                                                       
11436                                         cfg->real_offset += 5;
11437
11438                                         *sp++ = iargs [0];
11439
11440                                         inline_costs += costs;
11441                                 } else {
11442                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
11443                                         *sp++ = ins;
11444                                 }
11445                         } else 
11446 #endif
11447                         if (is_instance) {
11448                                 if (sp [0]->type == STACK_VTYPE) {
11449                                         MonoInst *var;
11450
11451                                         /* Have to compute the address of the variable */
11452
11453                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
11454                                         if (!var)
11455                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
11456                                         else
11457                                                 g_assert (var->klass == klass);
11458                                         
11459                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
11460                                         sp [0] = ins;
11461                                 }
11462
11463                                 if (op == CEE_LDFLDA) {
11464                                         if (sp [0]->type == STACK_OBJ) {
11465                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
11466                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
11467                                         }
11468
11469                                         dreg = alloc_ireg_mp (cfg);
11470
11471                                         if (mini_is_gsharedvt_klass (klass)) {
11472                                                 MonoInst *offset_ins;
11473
11474                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11475                                                 /* The value is offset by 1 */
11476                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11477                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11478                                         } else {
11479                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
11480                                         }
11481                                         ins->klass = mono_class_from_mono_type (field->type);
11482                                         ins->type = STACK_MP;
11483                                         *sp++ = ins;
11484                                 } else {
11485                                         MonoInst *load;
11486
11487                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
11488
11489                                         if (mini_is_gsharedvt_klass (klass)) {
11490                                                 MonoInst *offset_ins;
11491
11492                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11493                                                 /* The value is offset by 1 */
11494                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11495                                                 dreg = alloc_ireg_mp (cfg);
11496                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11497                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
11498                                         } else {
11499                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
11500                                         }
11501                                         load->flags |= ins_flag;
11502                                         if (sp [0]->opcode != OP_LDADDR)
11503                                                 load->flags |= MONO_INST_FAULT;
11504                                         *sp++ = load;
11505                                 }
11506                         }
11507
11508                         if (is_instance) {
11509                                 ins_flag = 0;
11510                                 ip += 5;
11511                                 break;
11512                         }
11513
11514                         /* STATIC CASE */
11515                         context_used = mini_class_check_context_used (cfg, klass);
11516
11517                         if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL) {
11518                                 mono_error_set_field_load (&cfg->error, field->parent, field->name, "Using static instructions with literal field");
11519                                 CHECK_CFG_ERROR;
11520                         }
11521
11522                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
11523                          * to be called here.
11524                          */
11525                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
11526                                 mono_class_vtable (cfg->domain, klass);
11527                                 CHECK_TYPELOAD (klass);
11528                         }
11529                         mono_domain_lock (cfg->domain);
11530                         if (cfg->domain->special_static_fields)
11531                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
11532                         mono_domain_unlock (cfg->domain);
11533
11534                         is_special_static = mono_class_field_is_special_static (field);
11535
11536                         if (is_special_static && ((gsize)addr & 0x80000000) == 0)
11537                                 thread_ins = mono_get_thread_intrinsic (cfg);
11538                         else
11539                                 thread_ins = NULL;
11540
11541                         /* Generate IR to compute the field address */
11542                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && thread_ins && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
11543                                 /*
11544                                  * Fast access to TLS data
11545                                  * Inline version of get_thread_static_data () in
11546                                  * threads.c.
11547                                  */
11548                                 guint32 offset;
11549                                 int idx, static_data_reg, array_reg, dreg;
11550
11551                                 GSHAREDVT_FAILURE (op);
11552
11553                                 MONO_ADD_INS (cfg->cbb, thread_ins);
11554                                 static_data_reg = alloc_ireg (cfg);
11555                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
11556
11557                                 if (cfg->compile_aot) {
11558                                         int offset_reg, offset2_reg, idx_reg;
11559
11560                                         /* For TLS variables, this will return the TLS offset */
11561                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
11562                                         offset_reg = ins->dreg;
11563                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
11564                                         idx_reg = alloc_ireg (cfg);
11565                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, idx_reg, offset_reg, 0x3f);
11566                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
11567                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
11568                                         array_reg = alloc_ireg (cfg);
11569                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
11570                                         offset2_reg = alloc_ireg (cfg);
11571                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, offset2_reg, offset_reg, 6);
11572                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset2_reg, 0x1ffffff);
11573                                         dreg = alloc_ireg (cfg);
11574                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
11575                                 } else {
11576                                         offset = (gsize)addr & 0x7fffffff;
11577                                         idx = offset & 0x3f;
11578
11579                                         array_reg = alloc_ireg (cfg);
11580                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
11581                                         dreg = alloc_ireg (cfg);
11582                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, ((offset >> 6) & 0x1ffffff));
11583                                 }
11584                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
11585                                         (cfg->compile_aot && is_special_static) ||
11586                                         (context_used && is_special_static)) {
11587                                 MonoInst *iargs [2];
11588
11589                                 g_assert (field->parent);
11590                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11591                                 if (context_used) {
11592                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
11593                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
11594                                 } else {
11595                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11596                                 }
11597                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11598                         } else if (context_used) {
11599                                 MonoInst *static_data;
11600
11601                                 /*
11602                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
11603                                         method->klass->name_space, method->klass->name, method->name,
11604                                         depth, field->offset);
11605                                 */
11606
11607                                 if (mono_class_needs_cctor_run (klass, method))
11608                                         emit_class_init (cfg, klass);
11609
11610                                 /*
11611                                  * The pointer we're computing here is
11612                                  *
11613                                  *   super_info.static_data + field->offset
11614                                  */
11615                                 static_data = emit_get_rgctx_klass (cfg, context_used,
11616                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
11617
11618                                 if (mini_is_gsharedvt_klass (klass)) {
11619                                         MonoInst *offset_ins;
11620
11621                                         offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11622                                         /* The value is offset by 1 */
11623                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11624                                         dreg = alloc_ireg_mp (cfg);
11625                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
11626                                 } else if (field->offset == 0) {
11627                                         ins = static_data;
11628                                 } else {
11629                                         int addr_reg = mono_alloc_preg (cfg);
11630                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
11631                                 }
11632                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
11633                                 MonoInst *iargs [2];
11634
11635                                 g_assert (field->parent);
11636                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11637                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11638                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11639                         } else {
11640                                 MonoVTable *vtable = NULL;
11641
11642                                 if (!cfg->compile_aot)
11643                                         vtable = mono_class_vtable (cfg->domain, klass);
11644                                 CHECK_TYPELOAD (klass);
11645
11646                                 if (!addr) {
11647                                         if (mini_field_access_needs_cctor_run (cfg, method, klass, vtable)) {
11648                                                 if (!(g_slist_find (class_inits, klass))) {
11649                                                         emit_class_init (cfg, klass);
11650                                                         if (cfg->verbose_level > 2)
11651                                                                 printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
11652                                                         class_inits = g_slist_prepend (class_inits, klass);
11653                                                 }
11654                                         } else {
11655                                                 if (cfg->run_cctors) {
11656                                                         /* This makes so that inline cannot trigger */
11657                                                         /* .cctors: too many apps depend on them */
11658                                                         /* running with a specific order... */
11659                                                         g_assert (vtable);
11660                                                         if (! vtable->initialized)
11661                                                                 INLINE_FAILURE ("class init");
11662                                                         if (!mono_runtime_class_init_full (vtable, &cfg->error)) {
11663                                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
11664                                                                 goto exception_exit;
11665                                                         }
11666                                                 }
11667                                         }
11668                                         if (cfg->compile_aot)
11669                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
11670                                         else {
11671                                                 g_assert (vtable);
11672                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11673                                                 g_assert (addr);
11674                                                 EMIT_NEW_PCONST (cfg, ins, addr);
11675                                         }
11676                                 } else {
11677                                         MonoInst *iargs [1];
11678                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
11679                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
11680                                 }
11681                         }
11682
11683                         /* Generate IR to do the actual load/store operation */
11684
11685                         if ((op == CEE_STFLD || op == CEE_STSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11686                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11687                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11688                         }
11689
11690                         if (op == CEE_LDSFLDA) {
11691                                 ins->klass = mono_class_from_mono_type (ftype);
11692                                 ins->type = STACK_PTR;
11693                                 *sp++ = ins;
11694                         } else if (op == CEE_STSFLD) {
11695                                 MonoInst *store;
11696
11697                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
11698                                 store->flags |= ins_flag;
11699                         } else {
11700                                 gboolean is_const = FALSE;
11701                                 MonoVTable *vtable = NULL;
11702                                 gpointer addr = NULL;
11703
11704                                 if (!context_used) {
11705                                         vtable = mono_class_vtable (cfg->domain, klass);
11706                                         CHECK_TYPELOAD (klass);
11707                                 }
11708                                 if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) ||
11709                                                 (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) {
11710                                         int ro_type = ftype->type;
11711                                         if (!addr)
11712                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11713                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
11714                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
11715                                         }
11716
11717                                         GSHAREDVT_FAILURE (op);
11718
11719                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
11720                                         is_const = TRUE;
11721                                         switch (ro_type) {
11722                                         case MONO_TYPE_BOOLEAN:
11723                                         case MONO_TYPE_U1:
11724                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
11725                                                 sp++;
11726                                                 break;
11727                                         case MONO_TYPE_I1:
11728                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
11729                                                 sp++;
11730                                                 break;                                          
11731                                         case MONO_TYPE_CHAR:
11732                                         case MONO_TYPE_U2:
11733                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
11734                                                 sp++;
11735                                                 break;
11736                                         case MONO_TYPE_I2:
11737                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
11738                                                 sp++;
11739                                                 break;
11740                                                 break;
11741                                         case MONO_TYPE_I4:
11742                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
11743                                                 sp++;
11744                                                 break;                                          
11745                                         case MONO_TYPE_U4:
11746                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
11747                                                 sp++;
11748                                                 break;
11749                                         case MONO_TYPE_I:
11750                                         case MONO_TYPE_U:
11751                                         case MONO_TYPE_PTR:
11752                                         case MONO_TYPE_FNPTR:
11753                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11754                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
11755                                                 sp++;
11756                                                 break;
11757                                         case MONO_TYPE_STRING:
11758                                         case MONO_TYPE_OBJECT:
11759                                         case MONO_TYPE_CLASS:
11760                                         case MONO_TYPE_SZARRAY:
11761                                         case MONO_TYPE_ARRAY:
11762                                                 if (!mono_gc_is_moving ()) {
11763                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11764                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
11765                                                         sp++;
11766                                                 } else {
11767                                                         is_const = FALSE;
11768                                                 }
11769                                                 break;
11770                                         case MONO_TYPE_I8:
11771                                         case MONO_TYPE_U8:
11772                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
11773                                                 sp++;
11774                                                 break;
11775                                         case MONO_TYPE_R4:
11776                                         case MONO_TYPE_R8:
11777                                         case MONO_TYPE_VALUETYPE:
11778                                         default:
11779                                                 is_const = FALSE;
11780                                                 break;
11781                                         }
11782                                 }
11783
11784                                 if (!is_const) {
11785                                         MonoInst *load;
11786
11787                                         CHECK_STACK_OVF (1);
11788
11789                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
11790                                         load->flags |= ins_flag;
11791                                         ins_flag = 0;
11792                                         *sp++ = load;
11793                                 }
11794                         }
11795
11796                         if ((op == CEE_LDFLD || op == CEE_LDSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11797                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
11798                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
11799                         }
11800
11801                         ins_flag = 0;
11802                         ip += 5;
11803                         break;
11804                 }
11805                 case CEE_STOBJ:
11806                         CHECK_STACK (2);
11807                         sp -= 2;
11808                         CHECK_OPSIZE (5);
11809                         token = read32 (ip + 1);
11810                         klass = mini_get_class (method, token, generic_context);
11811                         CHECK_TYPELOAD (klass);
11812                         if (ins_flag & MONO_INST_VOLATILE) {
11813                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11814                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11815                         }
11816                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
11817                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
11818                         ins->flags |= ins_flag;
11819                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
11820                                 generic_class_is_reference_type (cfg, klass) && !MONO_INS_IS_PCONST_NULL (sp [1])) {
11821                                 /* insert call to write barrier */
11822                                 emit_write_barrier (cfg, sp [0], sp [1]);
11823                         }
11824                         ins_flag = 0;
11825                         ip += 5;
11826                         inline_costs += 1;
11827                         break;
11828
11829                         /*
11830                          * Array opcodes
11831                          */
11832                 case CEE_NEWARR: {
11833                         MonoInst *len_ins;
11834                         const char *data_ptr;
11835                         int data_size = 0;
11836                         guint32 field_token;
11837
11838                         CHECK_STACK (1);
11839                         --sp;
11840
11841                         CHECK_OPSIZE (5);
11842                         token = read32 (ip + 1);
11843
11844                         klass = mini_get_class (method, token, generic_context);
11845                         CHECK_TYPELOAD (klass);
11846
11847                         context_used = mini_class_check_context_used (cfg, klass);
11848
11849                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
11850                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_OVF_U4);
11851                                 ins->sreg1 = sp [0]->dreg;
11852                                 ins->type = STACK_I4;
11853                                 ins->dreg = alloc_ireg (cfg);
11854                                 MONO_ADD_INS (cfg->cbb, ins);
11855                                 *sp = mono_decompose_opcode (cfg, ins);
11856                         }
11857
11858                         if (context_used) {
11859                                 MonoInst *args [3];
11860                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11861                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
11862
11863                                 /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
11864
11865                                 /* vtable */
11866                                 args [0] = emit_get_rgctx_klass (cfg, context_used,
11867                                         array_class, MONO_RGCTX_INFO_VTABLE);
11868                                 /* array len */
11869                                 args [1] = sp [0];
11870
11871                                 if (managed_alloc)
11872                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
11873                                 else
11874                                         ins = mono_emit_jit_icall (cfg, ves_icall_array_new_specific, args);
11875                         } else {
11876                                 if (cfg->opt & MONO_OPT_SHARED) {
11877                                         /* Decompose now to avoid problems with references to the domainvar */
11878                                         MonoInst *iargs [3];
11879
11880                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11881                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11882                                         iargs [2] = sp [0];
11883
11884                                         ins = mono_emit_jit_icall (cfg, ves_icall_array_new, iargs);
11885                                 } else {
11886                                         /* Decompose later since it is needed by abcrem */
11887                                         MonoClass *array_type = mono_array_class_get (klass, 1);
11888                                         mono_class_vtable (cfg->domain, array_type);
11889                                         CHECK_TYPELOAD (array_type);
11890
11891                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
11892                                         ins->dreg = alloc_ireg_ref (cfg);
11893                                         ins->sreg1 = sp [0]->dreg;
11894                                         ins->inst_newa_class = klass;
11895                                         ins->type = STACK_OBJ;
11896                                         ins->klass = array_type;
11897                                         MONO_ADD_INS (cfg->cbb, ins);
11898                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11899                                         cfg->cbb->has_array_access = TRUE;
11900
11901                                         /* Needed so mono_emit_load_get_addr () gets called */
11902                                         mono_get_got_var (cfg);
11903                                 }
11904                         }
11905
11906                         len_ins = sp [0];
11907                         ip += 5;
11908                         *sp++ = ins;
11909                         inline_costs += 1;
11910
11911                         /* 
11912                          * we inline/optimize the initialization sequence if possible.
11913                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
11914                          * for small sizes open code the memcpy
11915                          * ensure the rva field is big enough
11916                          */
11917                         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))) {
11918                                 MonoMethod *memcpy_method = get_memcpy_method ();
11919                                 MonoInst *iargs [3];
11920                                 int add_reg = alloc_ireg_mp (cfg);
11921
11922                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, MONO_STRUCT_OFFSET (MonoArray, vector));
11923                                 if (cfg->compile_aot) {
11924                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
11925                                 } else {
11926                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
11927                                 }
11928                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
11929                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
11930                                 ip += 11;
11931                         }
11932
11933                         break;
11934                 }
11935                 case CEE_LDLEN:
11936                         CHECK_STACK (1);
11937                         --sp;
11938                         if (sp [0]->type != STACK_OBJ)
11939                                 UNVERIFIED;
11940
11941                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
11942                         ins->dreg = alloc_preg (cfg);
11943                         ins->sreg1 = sp [0]->dreg;
11944                         ins->type = STACK_I4;
11945                         /* This flag will be inherited by the decomposition */
11946                         ins->flags |= MONO_INST_FAULT;
11947                         MONO_ADD_INS (cfg->cbb, ins);
11948                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11949                         cfg->cbb->has_array_access = TRUE;
11950                         ip ++;
11951                         *sp++ = ins;
11952                         break;
11953                 case CEE_LDELEMA:
11954                         CHECK_STACK (2);
11955                         sp -= 2;
11956                         CHECK_OPSIZE (5);
11957                         if (sp [0]->type != STACK_OBJ)
11958                                 UNVERIFIED;
11959
11960                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11961
11962                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11963                         CHECK_TYPELOAD (klass);
11964                         /* we need to make sure that this array is exactly the type it needs
11965                          * to be for correctness. the wrappers are lax with their usage
11966                          * so we need to ignore them here
11967                          */
11968                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
11969                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11970                                 mini_emit_check_array_type (cfg, sp [0], array_class);
11971                                 CHECK_TYPELOAD (array_class);
11972                         }
11973
11974                         readonly = FALSE;
11975                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11976                         *sp++ = ins;
11977                         ip += 5;
11978                         break;
11979                 case CEE_LDELEM:
11980                 case CEE_LDELEM_I1:
11981                 case CEE_LDELEM_U1:
11982                 case CEE_LDELEM_I2:
11983                 case CEE_LDELEM_U2:
11984                 case CEE_LDELEM_I4:
11985                 case CEE_LDELEM_U4:
11986                 case CEE_LDELEM_I8:
11987                 case CEE_LDELEM_I:
11988                 case CEE_LDELEM_R4:
11989                 case CEE_LDELEM_R8:
11990                 case CEE_LDELEM_REF: {
11991                         MonoInst *addr;
11992
11993                         CHECK_STACK (2);
11994                         sp -= 2;
11995
11996                         if (*ip == CEE_LDELEM) {
11997                                 CHECK_OPSIZE (5);
11998                                 token = read32 (ip + 1);
11999                                 klass = mini_get_class (method, token, generic_context);
12000                                 CHECK_TYPELOAD (klass);
12001                                 mono_class_init (klass);
12002                         }
12003                         else
12004                                 klass = array_access_to_klass (*ip);
12005
12006                         if (sp [0]->type != STACK_OBJ)
12007                                 UNVERIFIED;
12008
12009                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
12010
12011                         if (mini_is_gsharedvt_variable_klass (klass)) {
12012                                 // FIXME-VT: OP_ICONST optimization
12013                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
12014                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
12015                                 ins->opcode = OP_LOADV_MEMBASE;
12016                         } else if (sp [1]->opcode == OP_ICONST) {
12017                                 int array_reg = sp [0]->dreg;
12018                                 int index_reg = sp [1]->dreg;
12019                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
12020
12021                                 if (SIZEOF_REGISTER == 8 && COMPILE_LLVM (cfg))
12022                                         MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, index_reg);
12023
12024                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
12025                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
12026                         } else {
12027                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
12028                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
12029                         }
12030                         *sp++ = ins;
12031                         if (*ip == CEE_LDELEM)
12032                                 ip += 5;
12033                         else
12034                                 ++ip;
12035                         break;
12036                 }
12037                 case CEE_STELEM_I:
12038                 case CEE_STELEM_I1:
12039                 case CEE_STELEM_I2:
12040                 case CEE_STELEM_I4:
12041                 case CEE_STELEM_I8:
12042                 case CEE_STELEM_R4:
12043                 case CEE_STELEM_R8:
12044                 case CEE_STELEM_REF:
12045                 case CEE_STELEM: {
12046                         CHECK_STACK (3);
12047                         sp -= 3;
12048
12049                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
12050
12051                         if (*ip == CEE_STELEM) {
12052                                 CHECK_OPSIZE (5);
12053                                 token = read32 (ip + 1);
12054                                 klass = mini_get_class (method, token, generic_context);
12055                                 CHECK_TYPELOAD (klass);
12056                                 mono_class_init (klass);
12057                         }
12058                         else
12059                                 klass = array_access_to_klass (*ip);
12060
12061                         if (sp [0]->type != STACK_OBJ)
12062                                 UNVERIFIED;
12063
12064                         emit_array_store (cfg, klass, sp, TRUE);
12065
12066                         if (*ip == CEE_STELEM)
12067                                 ip += 5;
12068                         else
12069                                 ++ip;
12070                         inline_costs += 1;
12071                         break;
12072                 }
12073                 case CEE_CKFINITE: {
12074                         CHECK_STACK (1);
12075                         --sp;
12076
12077                         if (cfg->llvm_only) {
12078                                 MonoInst *iargs [1];
12079
12080                                 iargs [0] = sp [0];
12081                                 *sp++ = mono_emit_jit_icall (cfg, mono_ckfinite, iargs);
12082                         } else  {
12083                                 MONO_INST_NEW (cfg, ins, OP_CKFINITE);
12084                                 ins->sreg1 = sp [0]->dreg;
12085                                 ins->dreg = alloc_freg (cfg);
12086                                 ins->type = STACK_R8;
12087                                 MONO_ADD_INS (cfg->cbb, ins);
12088
12089                                 *sp++ = mono_decompose_opcode (cfg, ins);
12090                         }
12091
12092                         ++ip;
12093                         break;
12094                 }
12095                 case CEE_REFANYVAL: {
12096                         MonoInst *src_var, *src;
12097
12098                         int klass_reg = alloc_preg (cfg);
12099                         int dreg = alloc_preg (cfg);
12100
12101                         GSHAREDVT_FAILURE (*ip);
12102
12103                         CHECK_STACK (1);
12104                         MONO_INST_NEW (cfg, ins, *ip);
12105                         --sp;
12106                         CHECK_OPSIZE (5);
12107                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
12108                         CHECK_TYPELOAD (klass);
12109
12110                         context_used = mini_class_check_context_used (cfg, klass);
12111
12112                         // FIXME:
12113                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12114                         if (!src_var)
12115                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
12116                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
12117                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass));
12118
12119                         if (context_used) {
12120                                 MonoInst *klass_ins;
12121
12122                                 klass_ins = emit_get_rgctx_klass (cfg, context_used,
12123                                                 klass, MONO_RGCTX_INFO_KLASS);
12124
12125                                 // FIXME:
12126                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
12127                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
12128                         } else {
12129                                 mini_emit_class_check (cfg, klass_reg, klass);
12130                         }
12131                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value));
12132                         ins->type = STACK_MP;
12133                         ins->klass = klass;
12134                         *sp++ = ins;
12135                         ip += 5;
12136                         break;
12137                 }
12138                 case CEE_MKREFANY: {
12139                         MonoInst *loc, *addr;
12140
12141                         GSHAREDVT_FAILURE (*ip);
12142
12143                         CHECK_STACK (1);
12144                         MONO_INST_NEW (cfg, ins, *ip);
12145                         --sp;
12146                         CHECK_OPSIZE (5);
12147                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
12148                         CHECK_TYPELOAD (klass);
12149
12150                         context_used = mini_class_check_context_used (cfg, klass);
12151
12152                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
12153                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
12154
12155                         if (context_used) {
12156                                 MonoInst *const_ins;
12157                                 int type_reg = alloc_preg (cfg);
12158
12159                                 const_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
12160                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
12161                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
12162                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
12163                         } else if (cfg->compile_aot) {
12164                                 int const_reg = alloc_preg (cfg);
12165                                 int type_reg = alloc_preg (cfg);
12166
12167                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
12168                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
12169                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
12170                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
12171                         } else {
12172                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), &klass->byval_arg);
12173                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), klass);
12174                         }
12175                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
12176
12177                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
12178                         ins->type = STACK_VTYPE;
12179                         ins->klass = mono_defaults.typed_reference_class;
12180                         *sp++ = ins;
12181                         ip += 5;
12182                         break;
12183                 }
12184                 case CEE_LDTOKEN: {
12185                         gpointer handle;
12186                         MonoClass *handle_class;
12187
12188                         CHECK_STACK_OVF (1);
12189
12190                         CHECK_OPSIZE (5);
12191                         n = read32 (ip + 1);
12192
12193                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
12194                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
12195                                 handle = mono_method_get_wrapper_data (method, n);
12196                                 handle_class = (MonoClass *)mono_method_get_wrapper_data (method, n + 1);
12197                                 if (handle_class == mono_defaults.typehandle_class)
12198                                         handle = &((MonoClass*)handle)->byval_arg;
12199                         }
12200                         else {
12201                                 handle = mono_ldtoken_checked (image, n, &handle_class, generic_context, &cfg->error);
12202                                 CHECK_CFG_ERROR;
12203                         }
12204                         if (!handle)
12205                                 LOAD_ERROR;
12206                         mono_class_init (handle_class);
12207                         if (cfg->gshared) {
12208                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
12209                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
12210                                         /* This case handles ldtoken
12211                                            of an open type, like for
12212                                            typeof(Gen<>). */
12213                                         context_used = 0;
12214                                 } else if (handle_class == mono_defaults.typehandle_class) {
12215                                         context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type ((MonoType *)handle));
12216                                 } else if (handle_class == mono_defaults.fieldhandle_class)
12217                                         context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
12218                                 else if (handle_class == mono_defaults.methodhandle_class)
12219                                         context_used = mini_method_check_context_used (cfg, (MonoMethod *)handle);
12220                                 else
12221                                         g_assert_not_reached ();
12222                         }
12223
12224                         if ((cfg->opt & MONO_OPT_SHARED) &&
12225                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
12226                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
12227                                 MonoInst *addr, *vtvar, *iargs [3];
12228                                 int method_context_used;
12229
12230                                 method_context_used = mini_method_check_context_used (cfg, method);
12231
12232                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
12233
12234                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
12235                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
12236                                 if (method_context_used) {
12237                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
12238                                                 method, MONO_RGCTX_INFO_METHOD);
12239                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
12240                                 } else {
12241                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
12242                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
12243                                 }
12244                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12245
12246                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
12247
12248                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12249                         } else {
12250                                 if ((ip + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 5) && 
12251                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
12252                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
12253                                         (cmethod->klass == mono_defaults.systemtype_class) &&
12254                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
12255                                         MonoClass *tclass = mono_class_from_mono_type ((MonoType *)handle);
12256
12257                                         mono_class_init (tclass);
12258                                         if (context_used) {
12259                                                 ins = emit_get_rgctx_klass (cfg, context_used,
12260                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
12261                                         } else if (cfg->compile_aot) {
12262                                                 if (method->wrapper_type) {
12263                                                         mono_error_init (&error); //got to do it since there are multiple conditionals below
12264                                                         if (mono_class_get_checked (tclass->image, tclass->type_token, &error) == tclass && !generic_context) {
12265                                                                 /* Special case for static synchronized wrappers */
12266                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
12267                                                         } else {
12268                                                                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
12269                                                                 /* FIXME: n is not a normal token */
12270                                                                 DISABLE_AOT (cfg);
12271                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12272                                                         }
12273                                                 } else {
12274                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
12275                                                 }
12276                                         } else {
12277                                                 MonoReflectionType *rt = mono_type_get_object_checked (cfg->domain, (MonoType *)handle, &cfg->error);
12278                                                 CHECK_CFG_ERROR;
12279                                                 EMIT_NEW_PCONST (cfg, ins, rt);
12280                                         }
12281                                         ins->type = STACK_OBJ;
12282                                         ins->klass = cmethod->klass;
12283                                         ip += 5;
12284                                 } else {
12285                                         MonoInst *addr, *vtvar;
12286
12287                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
12288
12289                                         if (context_used) {
12290                                                 if (handle_class == mono_defaults.typehandle_class) {
12291                                                         ins = emit_get_rgctx_klass (cfg, context_used,
12292                                                                         mono_class_from_mono_type ((MonoType *)handle),
12293                                                                         MONO_RGCTX_INFO_TYPE);
12294                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
12295                                                         ins = emit_get_rgctx_method (cfg, context_used,
12296                                                                         (MonoMethod *)handle, MONO_RGCTX_INFO_METHOD);
12297                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
12298                                                         ins = emit_get_rgctx_field (cfg, context_used,
12299                                                                         (MonoClassField *)handle, MONO_RGCTX_INFO_CLASS_FIELD);
12300                                                 } else {
12301                                                         g_assert_not_reached ();
12302                                                 }
12303                                         } else if (cfg->compile_aot) {
12304                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n, generic_context);
12305                                         } else {
12306                                                 EMIT_NEW_PCONST (cfg, ins, handle);
12307                                         }
12308                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12309                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
12310                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12311                                 }
12312                         }
12313
12314                         *sp++ = ins;
12315                         ip += 5;
12316                         break;
12317                 }
12318                 case CEE_THROW:
12319                         CHECK_STACK (1);
12320                         if (sp [-1]->type != STACK_OBJ)
12321                                 UNVERIFIED;
12322
12323                         MONO_INST_NEW (cfg, ins, OP_THROW);
12324                         --sp;
12325                         ins->sreg1 = sp [0]->dreg;
12326                         ip++;
12327                         cfg->cbb->out_of_line = TRUE;
12328                         MONO_ADD_INS (cfg->cbb, ins);
12329                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
12330                         MONO_ADD_INS (cfg->cbb, ins);
12331                         sp = stack_start;
12332                         
12333                         link_bblock (cfg, cfg->cbb, end_bblock);
12334                         start_new_bblock = 1;
12335                         /* This can complicate code generation for llvm since the return value might not be defined */
12336                         if (COMPILE_LLVM (cfg))
12337                                 INLINE_FAILURE ("throw");
12338                         break;
12339                 case CEE_ENDFINALLY:
12340                         if (!ip_in_finally_clause (cfg, ip - header->code))
12341                                 UNVERIFIED;
12342                         /* mono_save_seq_point_info () depends on this */
12343                         if (sp != stack_start)
12344                                 emit_seq_point (cfg, method, ip, FALSE, FALSE);
12345                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
12346                         MONO_ADD_INS (cfg->cbb, ins);
12347                         ip++;
12348                         start_new_bblock = 1;
12349
12350                         /*
12351                          * Control will leave the method so empty the stack, otherwise
12352                          * the next basic block will start with a nonempty stack.
12353                          */
12354                         while (sp != stack_start) {
12355                                 sp--;
12356                         }
12357                         break;
12358                 case CEE_LEAVE:
12359                 case CEE_LEAVE_S: {
12360                         GList *handlers;
12361
12362                         if (*ip == CEE_LEAVE) {
12363                                 CHECK_OPSIZE (5);
12364                                 target = ip + 5 + (gint32)read32(ip + 1);
12365                         } else {
12366                                 CHECK_OPSIZE (2);
12367                                 target = ip + 2 + (signed char)(ip [1]);
12368                         }
12369
12370                         /* empty the stack */
12371                         while (sp != stack_start) {
12372                                 sp--;
12373                         }
12374
12375                         /* 
12376                          * If this leave statement is in a catch block, check for a
12377                          * pending exception, and rethrow it if necessary.
12378                          * We avoid doing this in runtime invoke wrappers, since those are called
12379                          * by native code which excepts the wrapper to catch all exceptions.
12380                          */
12381                         for (i = 0; i < header->num_clauses; ++i) {
12382                                 MonoExceptionClause *clause = &header->clauses [i];
12383
12384                                 /* 
12385                                  * Use <= in the final comparison to handle clauses with multiple
12386                                  * leave statements, like in bug #78024.
12387                                  * The ordering of the exception clauses guarantees that we find the
12388                                  * innermost clause.
12389                                  */
12390                                 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) {
12391                                         MonoInst *exc_ins;
12392                                         MonoBasicBlock *dont_throw;
12393
12394                                         /*
12395                                           MonoInst *load;
12396
12397                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
12398                                         */
12399
12400                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
12401
12402                                         NEW_BBLOCK (cfg, dont_throw);
12403
12404                                         /*
12405                                          * Currently, we always rethrow the abort exception, despite the 
12406                                          * fact that this is not correct. See thread6.cs for an example. 
12407                                          * But propagating the abort exception is more important than 
12408                                          * getting the sematics right.
12409                                          */
12410                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
12411                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
12412                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
12413
12414                                         MONO_START_BB (cfg, dont_throw);
12415                                 }
12416                         }
12417
12418 #ifdef ENABLE_LLVM
12419                         cfg->cbb->try_end = (intptr_t)(ip - header->code);
12420 #endif
12421
12422                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
12423                                 GList *tmp;
12424                                 MonoExceptionClause *clause;
12425
12426                                 for (tmp = handlers; tmp; tmp = tmp->next) {
12427                                         clause = (MonoExceptionClause *)tmp->data;
12428                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
12429                                         g_assert (tblock);
12430                                         link_bblock (cfg, cfg->cbb, tblock);
12431                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
12432                                         ins->inst_target_bb = tblock;
12433                                         ins->inst_eh_block = clause;
12434                                         MONO_ADD_INS (cfg->cbb, ins);
12435                                         cfg->cbb->has_call_handler = 1;
12436                                         if (COMPILE_LLVM (cfg)) {
12437                                                 MonoBasicBlock *target_bb;
12438
12439                                                 /* 
12440                                                  * Link the finally bblock with the target, since it will
12441                                                  * conceptually branch there.
12442                                                  */
12443                                                 GET_BBLOCK (cfg, tblock, cfg->cil_start + clause->handler_offset + clause->handler_len - 1);
12444                                                 GET_BBLOCK (cfg, target_bb, target);
12445                                                 link_bblock (cfg, tblock, target_bb);
12446                                         }
12447                                 }
12448                                 g_list_free (handlers);
12449                         } 
12450
12451                         MONO_INST_NEW (cfg, ins, OP_BR);
12452                         MONO_ADD_INS (cfg->cbb, ins);
12453                         GET_BBLOCK (cfg, tblock, target);
12454                         link_bblock (cfg, cfg->cbb, tblock);
12455                         ins->inst_target_bb = tblock;
12456
12457                         start_new_bblock = 1;
12458
12459                         if (*ip == CEE_LEAVE)
12460                                 ip += 5;
12461                         else
12462                                 ip += 2;
12463
12464                         break;
12465                 }
12466
12467                         /*
12468                          * Mono specific opcodes
12469                          */
12470                 case MONO_CUSTOM_PREFIX: {
12471
12472                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
12473
12474                         CHECK_OPSIZE (2);
12475                         switch (ip [1]) {
12476                         case CEE_MONO_ICALL: {
12477                                 gpointer func;
12478                                 MonoJitICallInfo *info;
12479
12480                                 token = read32 (ip + 2);
12481                                 func = mono_method_get_wrapper_data (method, token);
12482                                 info = mono_find_jit_icall_by_addr (func);
12483                                 if (!info)
12484                                         g_error ("Could not find icall address in wrapper %s", mono_method_full_name (method, 1));
12485                                 g_assert (info);
12486
12487                                 CHECK_STACK (info->sig->param_count);
12488                                 sp -= info->sig->param_count;
12489
12490                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
12491                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
12492                                         *sp++ = ins;
12493
12494                                 ip += 6;
12495                                 inline_costs += 10 * num_calls++;
12496
12497                                 break;
12498                         }
12499                         case CEE_MONO_LDPTR_CARD_TABLE:
12500                         case CEE_MONO_LDPTR_NURSERY_START:
12501                         case CEE_MONO_LDPTR_NURSERY_BITS:
12502                         case CEE_MONO_LDPTR_INT_REQ_FLAG: {
12503                                 CHECK_STACK_OVF (1);
12504
12505                                 switch (ip [1]) {
12506                                         case CEE_MONO_LDPTR_CARD_TABLE:
12507                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
12508                                                 break;
12509                                         case CEE_MONO_LDPTR_NURSERY_START:
12510                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_START, NULL);
12511                                                 break;
12512                                         case CEE_MONO_LDPTR_NURSERY_BITS:
12513                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_BITS, NULL);
12514                                                 break;
12515                                         case CEE_MONO_LDPTR_INT_REQ_FLAG:
12516                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
12517                                                 break;
12518                                 }
12519
12520                                 *sp++ = ins;
12521                                 ip += 2;
12522                                 inline_costs += 10 * num_calls++;
12523                                 break;
12524                         }
12525                         case CEE_MONO_LDPTR: {
12526                                 gpointer ptr;
12527
12528                                 CHECK_STACK_OVF (1);
12529                                 CHECK_OPSIZE (6);
12530                                 token = read32 (ip + 2);
12531
12532                                 ptr = mono_method_get_wrapper_data (method, token);
12533                                 EMIT_NEW_PCONST (cfg, ins, ptr);
12534                                 *sp++ = ins;
12535                                 ip += 6;
12536                                 inline_costs += 10 * num_calls++;
12537                                 /* Can't embed random pointers into AOT code */
12538                                 DISABLE_AOT (cfg);
12539                                 break;
12540                         }
12541                         case CEE_MONO_JIT_ICALL_ADDR: {
12542                                 MonoJitICallInfo *callinfo;
12543                                 gpointer ptr;
12544
12545                                 CHECK_STACK_OVF (1);
12546                                 CHECK_OPSIZE (6);
12547                                 token = read32 (ip + 2);
12548
12549                                 ptr = mono_method_get_wrapper_data (method, token);
12550                                 callinfo = mono_find_jit_icall_by_addr (ptr);
12551                                 g_assert (callinfo);
12552                                 EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
12553                                 *sp++ = ins;
12554                                 ip += 6;
12555                                 inline_costs += 10 * num_calls++;
12556                                 break;
12557                         }
12558                         case CEE_MONO_ICALL_ADDR: {
12559                                 MonoMethod *cmethod;
12560                                 gpointer ptr;
12561
12562                                 CHECK_STACK_OVF (1);
12563                                 CHECK_OPSIZE (6);
12564                                 token = read32 (ip + 2);
12565
12566                                 cmethod = (MonoMethod *)mono_method_get_wrapper_data (method, token);
12567
12568                                 if (cfg->compile_aot) {
12569                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
12570                                 } else {
12571                                         ptr = mono_lookup_internal_call (cmethod);
12572                                         g_assert (ptr);
12573                                         EMIT_NEW_PCONST (cfg, ins, ptr);
12574                                 }
12575                                 *sp++ = ins;
12576                                 ip += 6;
12577                                 break;
12578                         }
12579                         case CEE_MONO_VTADDR: {
12580                                 MonoInst *src_var, *src;
12581
12582                                 CHECK_STACK (1);
12583                                 --sp;
12584
12585                                 // FIXME:
12586                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12587                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
12588                                 *sp++ = src;
12589                                 ip += 2;
12590                                 break;
12591                         }
12592                         case CEE_MONO_NEWOBJ: {
12593                                 MonoInst *iargs [2];
12594
12595                                 CHECK_STACK_OVF (1);
12596                                 CHECK_OPSIZE (6);
12597                                 token = read32 (ip + 2);
12598                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12599                                 mono_class_init (klass);
12600                                 NEW_DOMAINCONST (cfg, iargs [0]);
12601                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
12602                                 NEW_CLASSCONST (cfg, iargs [1], klass);
12603                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
12604                                 *sp++ = mono_emit_jit_icall (cfg, ves_icall_object_new, iargs);
12605                                 ip += 6;
12606                                 inline_costs += 10 * num_calls++;
12607                                 break;
12608                         }
12609                         case CEE_MONO_OBJADDR:
12610                                 CHECK_STACK (1);
12611                                 --sp;
12612                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
12613                                 ins->dreg = alloc_ireg_mp (cfg);
12614                                 ins->sreg1 = sp [0]->dreg;
12615                                 ins->type = STACK_MP;
12616                                 MONO_ADD_INS (cfg->cbb, ins);
12617                                 *sp++ = ins;
12618                                 ip += 2;
12619                                 break;
12620                         case CEE_MONO_LDNATIVEOBJ:
12621                                 /*
12622                                  * Similar to LDOBJ, but instead load the unmanaged 
12623                                  * representation of the vtype to the stack.
12624                                  */
12625                                 CHECK_STACK (1);
12626                                 CHECK_OPSIZE (6);
12627                                 --sp;
12628                                 token = read32 (ip + 2);
12629                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12630                                 g_assert (klass->valuetype);
12631                                 mono_class_init (klass);
12632
12633                                 {
12634                                         MonoInst *src, *dest, *temp;
12635
12636                                         src = sp [0];
12637                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
12638                                         temp->backend.is_pinvoke = 1;
12639                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
12640                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
12641
12642                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
12643                                         dest->type = STACK_VTYPE;
12644                                         dest->klass = klass;
12645
12646                                         *sp ++ = dest;
12647                                         ip += 6;
12648                                 }
12649                                 break;
12650                         case CEE_MONO_RETOBJ: {
12651                                 /*
12652                                  * Same as RET, but return the native representation of a vtype
12653                                  * to the caller.
12654                                  */
12655                                 g_assert (cfg->ret);
12656                                 g_assert (mono_method_signature (method)->pinvoke); 
12657                                 CHECK_STACK (1);
12658                                 --sp;
12659                                 
12660                                 CHECK_OPSIZE (6);
12661                                 token = read32 (ip + 2);    
12662                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12663
12664                                 if (!cfg->vret_addr) {
12665                                         g_assert (cfg->ret_var_is_local);
12666
12667                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
12668                                 } else {
12669                                         EMIT_NEW_RETLOADA (cfg, ins);
12670                                 }
12671                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
12672                                 
12673                                 if (sp != stack_start)
12674                                         UNVERIFIED;
12675                                 
12676                                 MONO_INST_NEW (cfg, ins, OP_BR);
12677                                 ins->inst_target_bb = end_bblock;
12678                                 MONO_ADD_INS (cfg->cbb, ins);
12679                                 link_bblock (cfg, cfg->cbb, end_bblock);
12680                                 start_new_bblock = 1;
12681                                 ip += 6;
12682                                 break;
12683                         }
12684                         case CEE_MONO_CISINST:
12685                         case CEE_MONO_CCASTCLASS: {
12686                                 int token;
12687                                 CHECK_STACK (1);
12688                                 --sp;
12689                                 CHECK_OPSIZE (6);
12690                                 token = read32 (ip + 2);
12691                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12692                                 if (ip [1] == CEE_MONO_CISINST)
12693                                         ins = handle_cisinst (cfg, klass, sp [0]);
12694                                 else
12695                                         ins = handle_ccastclass (cfg, klass, sp [0]);
12696                                 *sp++ = ins;
12697                                 ip += 6;
12698                                 break;
12699                         }
12700                         case CEE_MONO_SAVE_LMF:
12701                         case CEE_MONO_RESTORE_LMF:
12702                                 ip += 2;
12703                                 break;
12704                         case CEE_MONO_CLASSCONST:
12705                                 CHECK_STACK_OVF (1);
12706                                 CHECK_OPSIZE (6);
12707                                 token = read32 (ip + 2);
12708                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
12709                                 *sp++ = ins;
12710                                 ip += 6;
12711                                 inline_costs += 10 * num_calls++;
12712                                 break;
12713                         case CEE_MONO_NOT_TAKEN:
12714                                 cfg->cbb->out_of_line = TRUE;
12715                                 ip += 2;
12716                                 break;
12717                         case CEE_MONO_TLS: {
12718                                 MonoTlsKey key;
12719
12720                                 CHECK_STACK_OVF (1);
12721                                 CHECK_OPSIZE (6);
12722                                 key = (MonoTlsKey)read32 (ip + 2);
12723                                 g_assert (key < TLS_KEY_NUM);
12724
12725                                 ins = mono_create_tls_get (cfg, key);
12726                                 if (!ins) {
12727                                         if (cfg->compile_aot) {
12728                                                 DISABLE_AOT (cfg);
12729                                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
12730                                                 ins->dreg = alloc_preg (cfg);
12731                                                 ins->type = STACK_PTR;
12732                                         } else {
12733                                                 g_assert_not_reached ();
12734                                         }
12735                                 }
12736                                 ins->type = STACK_PTR;
12737                                 MONO_ADD_INS (cfg->cbb, ins);
12738                                 *sp++ = ins;
12739                                 ip += 6;
12740                                 break;
12741                         }
12742                         case CEE_MONO_DYN_CALL: {
12743                                 MonoCallInst *call;
12744
12745                                 /* It would be easier to call a trampoline, but that would put an
12746                                  * extra frame on the stack, confusing exception handling. So
12747                                  * implement it inline using an opcode for now.
12748                                  */
12749
12750                                 if (!cfg->dyn_call_var) {
12751                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12752                                         /* prevent it from being register allocated */
12753                                         cfg->dyn_call_var->flags |= MONO_INST_VOLATILE;
12754                                 }
12755
12756                                 /* Has to use a call inst since it local regalloc expects it */
12757                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
12758                                 ins = (MonoInst*)call;
12759                                 sp -= 2;
12760                                 ins->sreg1 = sp [0]->dreg;
12761                                 ins->sreg2 = sp [1]->dreg;
12762                                 MONO_ADD_INS (cfg->cbb, ins);
12763
12764                                 cfg->param_area = MAX (cfg->param_area, cfg->backend->dyn_call_param_area);
12765
12766                                 ip += 2;
12767                                 inline_costs += 10 * num_calls++;
12768
12769                                 break;
12770                         }
12771                         case CEE_MONO_MEMORY_BARRIER: {
12772                                 CHECK_OPSIZE (6);
12773                                 emit_memory_barrier (cfg, (int)read32 (ip + 2));
12774                                 ip += 6;
12775                                 break;
12776                         }
12777                         case CEE_MONO_ATOMIC_STORE_I4: {
12778                                 g_assert (mono_arch_opcode_supported (OP_ATOMIC_STORE_I4));
12779
12780                                 CHECK_OPSIZE (6);
12781                                 CHECK_STACK (2);
12782                                 sp -= 2;
12783
12784                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_STORE_I4);
12785                                 ins->dreg = sp [0]->dreg;
12786                                 ins->sreg1 = sp [1]->dreg;
12787                                 ins->backend.memory_barrier_kind = (int) read32 (ip + 2);
12788                                 MONO_ADD_INS (cfg->cbb, ins);
12789
12790                                 ip += 6;
12791                                 break;
12792                         }
12793                         case CEE_MONO_JIT_ATTACH: {
12794                                 MonoInst *args [16], *domain_ins;
12795                                 MonoInst *ad_ins, *jit_tls_ins;
12796                                 MonoBasicBlock *next_bb = NULL, *call_bb = NULL;
12797
12798                                 g_assert (!mono_threads_is_coop_enabled ());
12799
12800                                 cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12801
12802                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12803                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12804
12805                                 ad_ins = mono_get_domain_intrinsic (cfg);
12806                                 jit_tls_ins = mono_get_jit_tls_intrinsic (cfg);
12807
12808                                 if (cfg->backend->have_tls_get && ad_ins && jit_tls_ins) {
12809                                         NEW_BBLOCK (cfg, next_bb);
12810                                         NEW_BBLOCK (cfg, call_bb);
12811
12812                                         if (cfg->compile_aot) {
12813                                                 /* AOT code is only used in the root domain */
12814                                                 EMIT_NEW_PCONST (cfg, domain_ins, NULL);
12815                                         } else {
12816                                                 EMIT_NEW_PCONST (cfg, domain_ins, cfg->domain);
12817                                         }
12818                                         MONO_ADD_INS (cfg->cbb, ad_ins);
12819                                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, ad_ins->dreg, domain_ins->dreg);
12820                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, call_bb);
12821
12822                                         MONO_ADD_INS (cfg->cbb, jit_tls_ins);
12823                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, jit_tls_ins->dreg, 0);
12824                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, call_bb);
12825
12826                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, next_bb);
12827                                         MONO_START_BB (cfg, call_bb);
12828                                 }
12829
12830                                 /* AOT code is only used in the root domain */
12831                                 EMIT_NEW_PCONST (cfg, args [0], cfg->compile_aot ? NULL : cfg->domain);
12832                                 ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
12833                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12834
12835                                 if (next_bb)
12836                                         MONO_START_BB (cfg, next_bb);
12837
12838
12839                                 ip += 2;
12840                                 break;
12841                         }
12842                         case CEE_MONO_JIT_DETACH: {
12843                                 MonoInst *args [16];
12844
12845                                 /* Restore the original domain */
12846                                 dreg = alloc_ireg (cfg);
12847                                 EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->orig_domain_var->dreg);
12848                                 mono_emit_jit_icall (cfg, mono_jit_set_domain, args);
12849                                 ip += 2;
12850                                 break;
12851                         }
12852                         case CEE_MONO_CALLI_EXTRA_ARG: {
12853                                 MonoInst *addr;
12854                                 MonoMethodSignature *fsig;
12855                                 MonoInst *arg;
12856
12857                                 /*
12858                                  * This is the same as CEE_CALLI, but passes an additional argument
12859                                  * to the called method in llvmonly mode.
12860                                  * This is only used by delegate invoke wrappers to call the
12861                                  * actual delegate method.
12862                                  */
12863                                 g_assert (method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE);
12864
12865                                 CHECK_OPSIZE (6);
12866                                 token = read32 (ip + 2);
12867
12868                                 ins = NULL;
12869
12870                                 cmethod = NULL;
12871                                 CHECK_STACK (1);
12872                                 --sp;
12873                                 addr = *sp;
12874                                 fsig = mini_get_signature (method, token, generic_context, &cfg->error);
12875                                 CHECK_CFG_ERROR;
12876
12877                                 if (cfg->llvm_only)
12878                                         cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, fsig);
12879
12880                                 n = fsig->param_count + fsig->hasthis + 1;
12881
12882                                 CHECK_STACK (n);
12883
12884                                 sp -= n;
12885                                 arg = sp [n - 1];
12886
12887                                 if (cfg->llvm_only) {
12888                                         /*
12889                                          * The lowest bit of 'arg' determines whenever the callee uses the gsharedvt
12890                                          * cconv. This is set by mono_init_delegate ().
12891                                          */
12892                                         if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig)) {
12893                                                 MonoInst *callee = addr;
12894                                                 MonoInst *call, *localloc_ins;
12895                                                 MonoBasicBlock *is_gsharedvt_bb, *end_bb;
12896                                                 int low_bit_reg = alloc_preg (cfg);
12897
12898                                                 NEW_BBLOCK (cfg, is_gsharedvt_bb);
12899                                                 NEW_BBLOCK (cfg, end_bb);
12900
12901                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, low_bit_reg, arg->dreg, 1);
12902                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_bit_reg, 0);
12903                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_gsharedvt_bb);
12904
12905                                                 /* Normal case: callee uses a normal cconv, have to add an out wrapper */
12906                                                 addr = emit_get_rgctx_sig (cfg, context_used,
12907                                                                                                    fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
12908                                                 /*
12909                                                  * ADDR points to a gsharedvt-out wrapper, have to pass <callee, arg> as an extra arg.
12910                                                  */
12911                                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
12912                                                 ins->dreg = alloc_preg (cfg);
12913                                                 ins->inst_imm = 2 * SIZEOF_VOID_P;
12914                                                 MONO_ADD_INS (cfg->cbb, ins);
12915                                                 localloc_ins = ins;
12916                                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12917                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, 0, callee->dreg);
12918                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, SIZEOF_VOID_P, arg->dreg);
12919
12920                                                 call = emit_extra_arg_calli (cfg, fsig, sp, localloc_ins->dreg, addr);
12921                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12922
12923                                                 /* Gsharedvt case: callee uses a gsharedvt cconv, no conversion is needed */
12924                                                 MONO_START_BB (cfg, is_gsharedvt_bb);
12925                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PXOR_IMM, arg->dreg, arg->dreg, 1);
12926                                                 ins = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
12927                                                 ins->dreg = call->dreg;
12928
12929                                                 MONO_START_BB (cfg, end_bb);
12930                                         } else {
12931                                                 /* Caller uses a normal calling conv */
12932
12933                                                 MonoInst *callee = addr;
12934                                                 MonoInst *call, *localloc_ins;
12935                                                 MonoBasicBlock *is_gsharedvt_bb, *end_bb;
12936                                                 int low_bit_reg = alloc_preg (cfg);
12937
12938                                                 NEW_BBLOCK (cfg, is_gsharedvt_bb);
12939                                                 NEW_BBLOCK (cfg, end_bb);
12940
12941                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, low_bit_reg, arg->dreg, 1);
12942                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_bit_reg, 0);
12943                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_gsharedvt_bb);
12944
12945                                                 /* Normal case: callee uses a normal cconv, no conversion is needed */
12946                                                 call = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
12947                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12948                                                 /* Gsharedvt case: callee uses a gsharedvt cconv, have to add an in wrapper */
12949                                                 MONO_START_BB (cfg, is_gsharedvt_bb);
12950                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PXOR_IMM, arg->dreg, arg->dreg, 1);
12951                                                 NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER, fsig);
12952                                                 MONO_ADD_INS (cfg->cbb, addr);
12953                                                 /*
12954                                                  * ADDR points to a gsharedvt-in wrapper, have to pass <callee, arg> as an extra arg.
12955                                                  */
12956                                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
12957                                                 ins->dreg = alloc_preg (cfg);
12958                                                 ins->inst_imm = 2 * SIZEOF_VOID_P;
12959                                                 MONO_ADD_INS (cfg->cbb, ins);
12960                                                 localloc_ins = ins;
12961                                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12962                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, 0, callee->dreg);
12963                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, SIZEOF_VOID_P, arg->dreg);
12964
12965                                                 ins = emit_extra_arg_calli (cfg, fsig, sp, localloc_ins->dreg, addr);
12966                                                 ins->dreg = call->dreg;
12967                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12968
12969                                                 MONO_START_BB (cfg, end_bb);
12970                                         }
12971                                 } else {
12972                                         /* Same as CEE_CALLI */
12973                                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
12974                                                 /*
12975                                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
12976                                                  */
12977                                                 MonoInst *callee = addr;
12978
12979                                                 addr = emit_get_rgctx_sig (cfg, context_used,
12980                                                                                                    fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
12981                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
12982                                         } else {
12983                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
12984                                         }
12985                                 }
12986
12987                                 if (!MONO_TYPE_IS_VOID (fsig->ret))
12988                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
12989
12990                                 CHECK_CFG_EXCEPTION;
12991
12992                                 ip += 6;
12993                                 ins_flag = 0;
12994                                 constrained_class = NULL;
12995                                 break;
12996                         }
12997                         case CEE_MONO_LDDOMAIN:
12998                                 CHECK_STACK_OVF (1);
12999                                 EMIT_NEW_PCONST (cfg, ins, cfg->compile_aot ? NULL : cfg->domain);
13000                                 ip += 2;
13001                                 *sp++ = ins;
13002                                 break;
13003                         case CEE_MONO_GET_LAST_ERROR:
13004                                 CHECK_OPSIZE (2);
13005                                 CHECK_STACK_OVF (1);
13006
13007                                 MONO_INST_NEW (cfg, ins, OP_GET_LAST_ERROR);
13008                                 ins->dreg = alloc_dreg (cfg, STACK_I4);
13009                                 ins->type = STACK_I4;
13010                                 MONO_ADD_INS (cfg->cbb, ins);
13011
13012                                 ip += 2;
13013                                 *sp++ = ins;
13014                                 break;
13015                         default:
13016                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
13017                                 break;
13018                         }
13019                         break;
13020                 }
13021
13022                 case CEE_PREFIX1: {
13023                         CHECK_OPSIZE (2);
13024                         switch (ip [1]) {
13025                         case CEE_ARGLIST: {
13026                                 /* somewhat similar to LDTOKEN */
13027                                 MonoInst *addr, *vtvar;
13028                                 CHECK_STACK_OVF (1);
13029                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
13030
13031                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
13032                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
13033
13034                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
13035                                 ins->type = STACK_VTYPE;
13036                                 ins->klass = mono_defaults.argumenthandle_class;
13037                                 *sp++ = ins;
13038                                 ip += 2;
13039                                 break;
13040                         }
13041                         case CEE_CEQ:
13042                         case CEE_CGT:
13043                         case CEE_CGT_UN:
13044                         case CEE_CLT:
13045                         case CEE_CLT_UN: {
13046                                 MonoInst *cmp, *arg1, *arg2;
13047
13048                                 CHECK_STACK (2);
13049                                 sp -= 2;
13050                                 arg1 = sp [0];
13051                                 arg2 = sp [1];
13052
13053                                 /*
13054                                  * The following transforms:
13055                                  *    CEE_CEQ    into OP_CEQ
13056                                  *    CEE_CGT    into OP_CGT
13057                                  *    CEE_CGT_UN into OP_CGT_UN
13058                                  *    CEE_CLT    into OP_CLT
13059                                  *    CEE_CLT_UN into OP_CLT_UN
13060                                  */
13061                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
13062
13063                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
13064                                 cmp->sreg1 = arg1->dreg;
13065                                 cmp->sreg2 = arg2->dreg;
13066                                 type_from_op (cfg, cmp, arg1, arg2);
13067                                 CHECK_TYPE (cmp);
13068                                 add_widen_op (cfg, cmp, &arg1, &arg2);
13069                                 if ((arg1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((arg1->type == STACK_PTR) || (arg1->type == STACK_OBJ) || (arg1->type == STACK_MP))))
13070                                         cmp->opcode = OP_LCOMPARE;
13071                                 else if (arg1->type == STACK_R4)
13072                                         cmp->opcode = OP_RCOMPARE;
13073                                 else if (arg1->type == STACK_R8)
13074                                         cmp->opcode = OP_FCOMPARE;
13075                                 else
13076                                         cmp->opcode = OP_ICOMPARE;
13077                                 MONO_ADD_INS (cfg->cbb, cmp);
13078                                 ins->type = STACK_I4;
13079                                 ins->dreg = alloc_dreg (cfg, (MonoStackType)ins->type);
13080                                 type_from_op (cfg, ins, arg1, arg2);
13081
13082                                 if (cmp->opcode == OP_FCOMPARE || cmp->opcode == OP_RCOMPARE) {
13083                                         /*
13084                                          * The backends expect the fceq opcodes to do the
13085                                          * comparison too.
13086                                          */
13087                                         ins->sreg1 = cmp->sreg1;
13088                                         ins->sreg2 = cmp->sreg2;
13089                                         NULLIFY_INS (cmp);
13090                                 }
13091                                 MONO_ADD_INS (cfg->cbb, ins);
13092                                 *sp++ = ins;
13093                                 ip += 2;
13094                                 break;
13095                         }
13096                         case CEE_LDFTN: {
13097                                 MonoInst *argconst;
13098                                 MonoMethod *cil_method;
13099
13100                                 CHECK_STACK_OVF (1);
13101                                 CHECK_OPSIZE (6);
13102                                 n = read32 (ip + 2);
13103                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
13104                                 CHECK_CFG_ERROR;
13105
13106                                 mono_class_init (cmethod->klass);
13107
13108                                 mono_save_token_info (cfg, image, n, cmethod);
13109
13110                                 context_used = mini_method_check_context_used (cfg, cmethod);
13111
13112                                 cil_method = cmethod;
13113                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
13114                                         emit_method_access_failure (cfg, method, cil_method);
13115
13116                                 if (mono_security_core_clr_enabled ())
13117                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
13118
13119                                 /* 
13120                                  * Optimize the common case of ldftn+delegate creation
13121                                  */
13122                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
13123                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
13124                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
13125                                                 MonoInst *target_ins, *handle_ins;
13126                                                 MonoMethod *invoke;
13127                                                 int invoke_context_used;
13128
13129                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
13130                                                 if (!invoke || !mono_method_signature (invoke))
13131                                                         LOAD_ERROR;
13132
13133                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
13134
13135                                                 target_ins = sp [-1];
13136
13137                                                 if (mono_security_core_clr_enabled ())
13138                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
13139
13140                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
13141                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
13142                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
13143                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
13144                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
13145                                                         }
13146                                                 }
13147
13148                                                 /* FIXME: SGEN support */
13149                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
13150                                                         ip += 6;
13151                                                         if (cfg->verbose_level > 3)
13152                                                                 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));
13153                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, FALSE))) {
13154                                                                 sp --;
13155                                                                 *sp = handle_ins;
13156                                                                 CHECK_CFG_EXCEPTION;
13157                                                                 ip += 5;
13158                                                                 sp ++;
13159                                                                 break;
13160                                                         }
13161                                                         ip -= 6;
13162                                                 }
13163                                         }
13164                                 }
13165
13166                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
13167                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
13168                                 *sp++ = ins;
13169                                 
13170                                 ip += 6;
13171                                 inline_costs += 10 * num_calls++;
13172                                 break;
13173                         }
13174                         case CEE_LDVIRTFTN: {
13175                                 MonoInst *args [2];
13176
13177                                 CHECK_STACK (1);
13178                                 CHECK_OPSIZE (6);
13179                                 n = read32 (ip + 2);
13180                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
13181                                 CHECK_CFG_ERROR;
13182
13183                                 mono_class_init (cmethod->klass);
13184  
13185                                 context_used = mini_method_check_context_used (cfg, cmethod);
13186
13187                                 if (mono_security_core_clr_enabled ())
13188                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
13189
13190                                 /*
13191                                  * Optimize the common case of ldvirtftn+delegate creation
13192                                  */
13193                                 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)) {
13194                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
13195                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
13196                                                 MonoInst *target_ins, *handle_ins;
13197                                                 MonoMethod *invoke;
13198                                                 int invoke_context_used;
13199                                                 gboolean is_virtual = cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL;
13200
13201                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
13202                                                 if (!invoke || !mono_method_signature (invoke))
13203                                                         LOAD_ERROR;
13204
13205                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
13206
13207                                                 target_ins = sp [-1];
13208
13209                                                 if (mono_security_core_clr_enabled ())
13210                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
13211
13212                                                 /* FIXME: SGEN support */
13213                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
13214                                                         ip += 6;
13215                                                         if (cfg->verbose_level > 3)
13216                                                                 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));
13217                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, is_virtual))) {
13218                                                                 sp -= 2;
13219                                                                 *sp = handle_ins;
13220                                                                 CHECK_CFG_EXCEPTION;
13221                                                                 ip += 5;
13222                                                                 sp ++;
13223                                                                 break;
13224                                                         }
13225                                                         ip -= 6;
13226                                                 }
13227                                         }
13228                                 }
13229
13230                                 --sp;
13231                                 args [0] = *sp;
13232
13233                                 args [1] = emit_get_rgctx_method (cfg, context_used,
13234                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
13235
13236                                 if (context_used)
13237                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
13238                                 else
13239                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
13240
13241                                 ip += 6;
13242                                 inline_costs += 10 * num_calls++;
13243                                 break;
13244                         }
13245                         case CEE_LDARG:
13246                                 CHECK_STACK_OVF (1);
13247                                 CHECK_OPSIZE (4);
13248                                 n = read16 (ip + 2);
13249                                 CHECK_ARG (n);
13250                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
13251                                 *sp++ = ins;
13252                                 ip += 4;
13253                                 break;
13254                         case CEE_LDARGA:
13255                                 CHECK_STACK_OVF (1);
13256                                 CHECK_OPSIZE (4);
13257                                 n = read16 (ip + 2);
13258                                 CHECK_ARG (n);
13259                                 NEW_ARGLOADA (cfg, ins, n);
13260                                 MONO_ADD_INS (cfg->cbb, ins);
13261                                 *sp++ = ins;
13262                                 ip += 4;
13263                                 break;
13264                         case CEE_STARG:
13265                                 CHECK_STACK (1);
13266                                 --sp;
13267                                 CHECK_OPSIZE (4);
13268                                 n = read16 (ip + 2);
13269                                 CHECK_ARG (n);
13270                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
13271                                         UNVERIFIED;
13272                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
13273                                 ip += 4;
13274                                 break;
13275                         case CEE_LDLOC:
13276                                 CHECK_STACK_OVF (1);
13277                                 CHECK_OPSIZE (4);
13278                                 n = read16 (ip + 2);
13279                                 CHECK_LOCAL (n);
13280                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
13281                                 *sp++ = ins;
13282                                 ip += 4;
13283                                 break;
13284                         case CEE_LDLOCA: {
13285                                 unsigned char *tmp_ip;
13286                                 CHECK_STACK_OVF (1);
13287                                 CHECK_OPSIZE (4);
13288                                 n = read16 (ip + 2);
13289                                 CHECK_LOCAL (n);
13290
13291                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
13292                                         ip = tmp_ip;
13293                                         inline_costs += 1;
13294                                         break;
13295                                 }                       
13296                                 
13297                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
13298                                 *sp++ = ins;
13299                                 ip += 4;
13300                                 break;
13301                         }
13302                         case CEE_STLOC:
13303                                 CHECK_STACK (1);
13304                                 --sp;
13305                                 CHECK_OPSIZE (4);
13306                                 n = read16 (ip + 2);
13307                                 CHECK_LOCAL (n);
13308                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
13309                                         UNVERIFIED;
13310                                 emit_stloc_ir (cfg, sp, header, n);
13311                                 ip += 4;
13312                                 inline_costs += 1;
13313                                 break;
13314                         case CEE_LOCALLOC: {
13315                                 CHECK_STACK (1);
13316                                 MonoBasicBlock *non_zero_bb, *end_bb;
13317                                 int alloc_ptr = alloc_preg (cfg);
13318                                 --sp;
13319                                 if (sp != stack_start) 
13320                                         UNVERIFIED;
13321                                 if (cfg->method != method) 
13322                                         /* 
13323                                          * Inlining this into a loop in a parent could lead to 
13324                                          * stack overflows which is different behavior than the
13325                                          * non-inlined case, thus disable inlining in this case.
13326                                          */
13327                                         INLINE_FAILURE("localloc");
13328
13329                                 NEW_BBLOCK (cfg, non_zero_bb);
13330                                 NEW_BBLOCK (cfg, end_bb);
13331
13332                                 /* if size != zero */
13333                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
13334                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, non_zero_bb);
13335
13336                                 //size is zero, so result is NULL
13337                                 MONO_EMIT_NEW_PCONST (cfg, alloc_ptr, NULL);
13338                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
13339
13340                                 MONO_START_BB (cfg, non_zero_bb);
13341                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
13342                                 ins->dreg = alloc_ptr;
13343                                 ins->sreg1 = sp [0]->dreg;
13344                                 ins->type = STACK_PTR;
13345                                 MONO_ADD_INS (cfg->cbb, ins);
13346
13347                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
13348                                 if (init_locals)
13349                                         ins->flags |= MONO_INST_INIT;
13350
13351                                 MONO_START_BB (cfg, end_bb);
13352                                 EMIT_NEW_UNALU (cfg, ins, OP_MOVE, alloc_preg (cfg), alloc_ptr);
13353                                 ins->type = STACK_PTR;
13354
13355                                 *sp++ = ins;
13356                                 ip += 2;
13357                                 break;
13358                         }
13359                         case CEE_ENDFILTER: {
13360                                 MonoExceptionClause *clause, *nearest;
13361                                 int cc;
13362
13363                                 CHECK_STACK (1);
13364                                 --sp;
13365                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
13366                                         UNVERIFIED;
13367                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
13368                                 ins->sreg1 = (*sp)->dreg;
13369                                 MONO_ADD_INS (cfg->cbb, ins);
13370                                 start_new_bblock = 1;
13371                                 ip += 2;
13372
13373                                 nearest = NULL;
13374                                 for (cc = 0; cc < header->num_clauses; ++cc) {
13375                                         clause = &header->clauses [cc];
13376                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
13377                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
13378                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset)))
13379                                                 nearest = clause;
13380                                 }
13381                                 g_assert (nearest);
13382                                 if ((ip - header->code) != nearest->handler_offset)
13383                                         UNVERIFIED;
13384
13385                                 break;
13386                         }
13387                         case CEE_UNALIGNED_:
13388                                 ins_flag |= MONO_INST_UNALIGNED;
13389                                 /* FIXME: record alignment? we can assume 1 for now */
13390                                 CHECK_OPSIZE (3);
13391                                 ip += 3;
13392                                 break;
13393                         case CEE_VOLATILE_:
13394                                 ins_flag |= MONO_INST_VOLATILE;
13395                                 ip += 2;
13396                                 break;
13397                         case CEE_TAIL_:
13398                                 ins_flag   |= MONO_INST_TAILCALL;
13399                                 cfg->flags |= MONO_CFG_HAS_TAIL;
13400                                 /* Can't inline tail calls at this time */
13401                                 inline_costs += 100000;
13402                                 ip += 2;
13403                                 break;
13404                         case CEE_INITOBJ:
13405                                 CHECK_STACK (1);
13406                                 --sp;
13407                                 CHECK_OPSIZE (6);
13408                                 token = read32 (ip + 2);
13409                                 klass = mini_get_class (method, token, generic_context);
13410                                 CHECK_TYPELOAD (klass);
13411                                 if (generic_class_is_reference_type (cfg, klass))
13412                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
13413                                 else
13414                                         mini_emit_initobj (cfg, *sp, NULL, klass);
13415                                 ip += 6;
13416                                 inline_costs += 1;
13417                                 break;
13418                         case CEE_CONSTRAINED_:
13419                                 CHECK_OPSIZE (6);
13420                                 token = read32 (ip + 2);
13421                                 constrained_class = mini_get_class (method, token, generic_context);
13422                                 CHECK_TYPELOAD (constrained_class);
13423                                 ip += 6;
13424                                 break;
13425                         case CEE_CPBLK:
13426                         case CEE_INITBLK: {
13427                                 MonoInst *iargs [3];
13428                                 CHECK_STACK (3);
13429                                 sp -= 3;
13430
13431                                 /* Skip optimized paths for volatile operations. */
13432                                 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)) {
13433                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
13434                                 } 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)) {
13435                                         /* emit_memset only works when val == 0 */
13436                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
13437                                 } else {
13438                                         MonoInst *call;
13439                                         iargs [0] = sp [0];
13440                                         iargs [1] = sp [1];
13441                                         iargs [2] = sp [2];
13442                                         if (ip [1] == CEE_CPBLK) {
13443                                                 /*
13444                                                  * FIXME: It's unclear whether we should be emitting both the acquire
13445                                                  * and release barriers for cpblk. It is technically both a load and
13446                                                  * store operation, so it seems like that's the sensible thing to do.
13447                                                  *
13448                                                  * FIXME: We emit full barriers on both sides of the operation for
13449                                                  * simplicity. We should have a separate atomic memcpy method instead.
13450                                                  */
13451                                                 MonoMethod *memcpy_method = get_memcpy_method ();
13452
13453                                                 if (ins_flag & MONO_INST_VOLATILE)
13454                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
13455
13456                                                 call = mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
13457                                                 call->flags |= ins_flag;
13458
13459                                                 if (ins_flag & MONO_INST_VOLATILE)
13460                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
13461                                         } else {
13462                                                 MonoMethod *memset_method = get_memset_method ();
13463                                                 if (ins_flag & MONO_INST_VOLATILE) {
13464                                                         /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
13465                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
13466                                                 }
13467                                                 call = mono_emit_method_call (cfg, memset_method, iargs, NULL);
13468                                                 call->flags |= ins_flag;
13469                                         }
13470                                 }
13471                                 ip += 2;
13472                                 ins_flag = 0;
13473                                 inline_costs += 1;
13474                                 break;
13475                         }
13476                         case CEE_NO_:
13477                                 CHECK_OPSIZE (3);
13478                                 if (ip [2] & 0x1)
13479                                         ins_flag |= MONO_INST_NOTYPECHECK;
13480                                 if (ip [2] & 0x2)
13481                                         ins_flag |= MONO_INST_NORANGECHECK;
13482                                 /* we ignore the no-nullcheck for now since we
13483                                  * really do it explicitly only when doing callvirt->call
13484                                  */
13485                                 ip += 3;
13486                                 break;
13487                         case CEE_RETHROW: {
13488                                 MonoInst *load;
13489                                 int handler_offset = -1;
13490
13491                                 for (i = 0; i < header->num_clauses; ++i) {
13492                                         MonoExceptionClause *clause = &header->clauses [i];
13493                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
13494                                                 handler_offset = clause->handler_offset;
13495                                                 break;
13496                                         }
13497                                 }
13498
13499                                 cfg->cbb->flags |= BB_EXCEPTION_UNSAFE;
13500
13501                                 if (handler_offset == -1)
13502                                         UNVERIFIED;
13503
13504                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
13505                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
13506                                 ins->sreg1 = load->dreg;
13507                                 MONO_ADD_INS (cfg->cbb, ins);
13508
13509                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
13510                                 MONO_ADD_INS (cfg->cbb, ins);
13511
13512                                 sp = stack_start;
13513                                 link_bblock (cfg, cfg->cbb, end_bblock);
13514                                 start_new_bblock = 1;
13515                                 ip += 2;
13516                                 break;
13517                         }
13518                         case CEE_SIZEOF: {
13519                                 guint32 val;
13520                                 int ialign;
13521
13522                                 CHECK_STACK_OVF (1);
13523                                 CHECK_OPSIZE (6);
13524                                 token = read32 (ip + 2);
13525                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !image_is_dynamic (method->klass->image) && !generic_context) {
13526                                         MonoType *type = mono_type_create_from_typespec_checked (image, token, &cfg->error);
13527                                         CHECK_CFG_ERROR;
13528
13529                                         val = mono_type_size (type, &ialign);
13530                                 } else {
13531                                         MonoClass *klass = mini_get_class (method, token, generic_context);
13532                                         CHECK_TYPELOAD (klass);
13533
13534                                         val = mono_type_size (&klass->byval_arg, &ialign);
13535
13536                                         if (mini_is_gsharedvt_klass (klass))
13537                                                 GSHAREDVT_FAILURE (*ip);
13538                                 }
13539                                 EMIT_NEW_ICONST (cfg, ins, val);
13540                                 *sp++= ins;
13541                                 ip += 6;
13542                                 break;
13543                         }
13544                         case CEE_REFANYTYPE: {
13545                                 MonoInst *src_var, *src;
13546
13547                                 GSHAREDVT_FAILURE (*ip);
13548
13549                                 CHECK_STACK (1);
13550                                 --sp;
13551
13552                                 // FIXME:
13553                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
13554                                 if (!src_var)
13555                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
13556                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
13557                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type));
13558                                 *sp++ = ins;
13559                                 ip += 2;
13560                                 break;
13561                         }
13562                         case CEE_READONLY_:
13563                                 readonly = TRUE;
13564                                 ip += 2;
13565                                 break;
13566
13567                         case CEE_UNUSED56:
13568                         case CEE_UNUSED57:
13569                         case CEE_UNUSED70:
13570                         case CEE_UNUSED:
13571                         case CEE_UNUSED99:
13572                                 UNVERIFIED;
13573                                 
13574                         default:
13575                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
13576                                 UNVERIFIED;
13577                         }
13578                         break;
13579                 }
13580                 case CEE_UNUSED58:
13581                 case CEE_UNUSED1:
13582                         UNVERIFIED;
13583
13584                 default:
13585                         g_warning ("opcode 0x%02x not handled", *ip);
13586                         UNVERIFIED;
13587                 }
13588         }
13589         if (start_new_bblock != 1)
13590                 UNVERIFIED;
13591
13592         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
13593         if (cfg->cbb->next_bb) {
13594                 /* This could already be set because of inlining, #693905 */
13595                 MonoBasicBlock *bb = cfg->cbb;
13596
13597                 while (bb->next_bb)
13598                         bb = bb->next_bb;
13599                 bb->next_bb = end_bblock;
13600         } else {
13601                 cfg->cbb->next_bb = end_bblock;
13602         }
13603
13604         if (cfg->method == method && cfg->domainvar) {
13605                 MonoInst *store;
13606                 MonoInst *get_domain;
13607
13608                 cfg->cbb = init_localsbb;
13609
13610                 if ((get_domain = mono_get_domain_intrinsic (cfg))) {
13611                         MONO_ADD_INS (cfg->cbb, get_domain);
13612                 } else {
13613                         get_domain = mono_emit_jit_icall (cfg, mono_domain_get, NULL);
13614                 }
13615                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
13616                 MONO_ADD_INS (cfg->cbb, store);
13617         }
13618
13619 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
13620         if (cfg->compile_aot)
13621                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
13622                 mono_get_got_var (cfg);
13623 #endif
13624
13625         if (cfg->method == method && cfg->got_var)
13626                 mono_emit_load_got_addr (cfg);
13627
13628         if (init_localsbb) {
13629                 cfg->cbb = init_localsbb;
13630                 cfg->ip = NULL;
13631                 for (i = 0; i < header->num_locals; ++i) {
13632                         emit_init_local (cfg, i, header->locals [i], init_locals);
13633                 }
13634         }
13635
13636         if (cfg->init_ref_vars && cfg->method == method) {
13637                 /* Emit initialization for ref vars */
13638                 // FIXME: Avoid duplication initialization for IL locals.
13639                 for (i = 0; i < cfg->num_varinfo; ++i) {
13640                         MonoInst *ins = cfg->varinfo [i];
13641
13642                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
13643                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
13644                 }
13645         }
13646
13647         if (cfg->lmf_var && cfg->method == method && !cfg->llvm_only) {
13648                 cfg->cbb = init_localsbb;
13649                 emit_push_lmf (cfg);
13650         }
13651
13652         cfg->cbb = init_localsbb;
13653         emit_instrumentation_call (cfg, mono_profiler_method_enter);
13654
13655         if (seq_points) {
13656                 MonoBasicBlock *bb;
13657
13658                 /*
13659                  * Make seq points at backward branch targets interruptable.
13660                  */
13661                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
13662                         if (bb->code && bb->in_count > 1 && bb->code->opcode == OP_SEQ_POINT)
13663                                 bb->code->flags |= MONO_INST_SINGLE_STEP_LOC;
13664         }
13665
13666         /* Add a sequence point for method entry/exit events */
13667         if (seq_points && cfg->gen_sdb_seq_points) {
13668                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
13669                 MONO_ADD_INS (init_localsbb, ins);
13670                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
13671                 MONO_ADD_INS (cfg->bb_exit, ins);
13672         }
13673
13674         /*
13675          * Add seq points for IL offsets which have line number info, but wasn't generated a seq point during JITting because
13676          * the code they refer to was dead (#11880).
13677          */
13678         if (sym_seq_points) {
13679                 for (i = 0; i < header->code_size; ++i) {
13680                         if (mono_bitset_test_fast (seq_point_locs, i) && !mono_bitset_test_fast (seq_point_set_locs, i)) {
13681                                 MonoInst *ins;
13682
13683                                 NEW_SEQ_POINT (cfg, ins, i, FALSE);
13684                                 mono_add_seq_point (cfg, NULL, ins, SEQ_POINT_NATIVE_OFFSET_DEAD_CODE);
13685                         }
13686                 }
13687         }
13688
13689         cfg->ip = NULL;
13690
13691         if (cfg->method == method) {
13692                 MonoBasicBlock *bb;
13693                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13694                         if (bb == cfg->bb_init)
13695                                 bb->region = -1;
13696                         else
13697                                 bb->region = mono_find_block_region (cfg, bb->real_offset);
13698                         if (cfg->spvars)
13699                                 mono_create_spvar_for_region (cfg, bb->region);
13700                         if (cfg->verbose_level > 2)
13701                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
13702                 }
13703         } else {
13704                 MonoBasicBlock *bb;
13705                 /* get_most_deep_clause () in mini-llvm.c depends on this for inlined bblocks */
13706                 for (bb = start_bblock; bb != end_bblock; bb  = bb->next_bb) {
13707                         bb->real_offset = inline_offset;
13708                 }
13709         }
13710
13711         if (inline_costs < 0) {
13712                 char *mname;
13713
13714                 /* Method is too large */
13715                 mname = mono_method_full_name (method, TRUE);
13716                 mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Method %s is too complex.", mname));
13717                 g_free (mname);
13718         }
13719
13720         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
13721                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
13722
13723         goto cleanup;
13724
13725 mono_error_exit:
13726         g_assert (!mono_error_ok (&cfg->error));
13727         goto cleanup;
13728  
13729  exception_exit:
13730         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
13731         goto cleanup;
13732
13733  unverified:
13734         set_exception_type_from_invalid_il (cfg, method, ip);
13735         goto cleanup;
13736
13737  cleanup:
13738         g_slist_free (class_inits);
13739         mono_basic_block_free (original_bb);
13740         cfg->dont_inline = g_list_remove (cfg->dont_inline, method);
13741         if (cfg->exception_type)
13742                 return -1;
13743         else
13744                 return inline_costs;
13745 }
13746
13747 static int
13748 store_membase_reg_to_store_membase_imm (int opcode)
13749 {
13750         switch (opcode) {
13751         case OP_STORE_MEMBASE_REG:
13752                 return OP_STORE_MEMBASE_IMM;
13753         case OP_STOREI1_MEMBASE_REG:
13754                 return OP_STOREI1_MEMBASE_IMM;
13755         case OP_STOREI2_MEMBASE_REG:
13756                 return OP_STOREI2_MEMBASE_IMM;
13757         case OP_STOREI4_MEMBASE_REG:
13758                 return OP_STOREI4_MEMBASE_IMM;
13759         case OP_STOREI8_MEMBASE_REG:
13760                 return OP_STOREI8_MEMBASE_IMM;
13761         default:
13762                 g_assert_not_reached ();
13763         }
13764
13765         return -1;
13766 }               
13767
13768 int
13769 mono_op_to_op_imm (int opcode)
13770 {
13771         switch (opcode) {
13772         case OP_IADD:
13773                 return OP_IADD_IMM;
13774         case OP_ISUB:
13775                 return OP_ISUB_IMM;
13776         case OP_IDIV:
13777                 return OP_IDIV_IMM;
13778         case OP_IDIV_UN:
13779                 return OP_IDIV_UN_IMM;
13780         case OP_IREM:
13781                 return OP_IREM_IMM;
13782         case OP_IREM_UN:
13783                 return OP_IREM_UN_IMM;
13784         case OP_IMUL:
13785                 return OP_IMUL_IMM;
13786         case OP_IAND:
13787                 return OP_IAND_IMM;
13788         case OP_IOR:
13789                 return OP_IOR_IMM;
13790         case OP_IXOR:
13791                 return OP_IXOR_IMM;
13792         case OP_ISHL:
13793                 return OP_ISHL_IMM;
13794         case OP_ISHR:
13795                 return OP_ISHR_IMM;
13796         case OP_ISHR_UN:
13797                 return OP_ISHR_UN_IMM;
13798
13799         case OP_LADD:
13800                 return OP_LADD_IMM;
13801         case OP_LSUB:
13802                 return OP_LSUB_IMM;
13803         case OP_LAND:
13804                 return OP_LAND_IMM;
13805         case OP_LOR:
13806                 return OP_LOR_IMM;
13807         case OP_LXOR:
13808                 return OP_LXOR_IMM;
13809         case OP_LSHL:
13810                 return OP_LSHL_IMM;
13811         case OP_LSHR:
13812                 return OP_LSHR_IMM;
13813         case OP_LSHR_UN:
13814                 return OP_LSHR_UN_IMM;
13815 #if SIZEOF_REGISTER == 8
13816         case OP_LREM:
13817                 return OP_LREM_IMM;
13818 #endif
13819
13820         case OP_COMPARE:
13821                 return OP_COMPARE_IMM;
13822         case OP_ICOMPARE:
13823                 return OP_ICOMPARE_IMM;
13824         case OP_LCOMPARE:
13825                 return OP_LCOMPARE_IMM;
13826
13827         case OP_STORE_MEMBASE_REG:
13828                 return OP_STORE_MEMBASE_IMM;
13829         case OP_STOREI1_MEMBASE_REG:
13830                 return OP_STOREI1_MEMBASE_IMM;
13831         case OP_STOREI2_MEMBASE_REG:
13832                 return OP_STOREI2_MEMBASE_IMM;
13833         case OP_STOREI4_MEMBASE_REG:
13834                 return OP_STOREI4_MEMBASE_IMM;
13835
13836 #if defined(TARGET_X86) || defined (TARGET_AMD64)
13837         case OP_X86_PUSH:
13838                 return OP_X86_PUSH_IMM;
13839         case OP_X86_COMPARE_MEMBASE_REG:
13840                 return OP_X86_COMPARE_MEMBASE_IMM;
13841 #endif
13842 #if defined(TARGET_AMD64)
13843         case OP_AMD64_ICOMPARE_MEMBASE_REG:
13844                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13845 #endif
13846         case OP_VOIDCALL_REG:
13847                 return OP_VOIDCALL;
13848         case OP_CALL_REG:
13849                 return OP_CALL;
13850         case OP_LCALL_REG:
13851                 return OP_LCALL;
13852         case OP_FCALL_REG:
13853                 return OP_FCALL;
13854         case OP_LOCALLOC:
13855                 return OP_LOCALLOC_IMM;
13856         }
13857
13858         return -1;
13859 }
13860
13861 static int
13862 ldind_to_load_membase (int opcode)
13863 {
13864         switch (opcode) {
13865         case CEE_LDIND_I1:
13866                 return OP_LOADI1_MEMBASE;
13867         case CEE_LDIND_U1:
13868                 return OP_LOADU1_MEMBASE;
13869         case CEE_LDIND_I2:
13870                 return OP_LOADI2_MEMBASE;
13871         case CEE_LDIND_U2:
13872                 return OP_LOADU2_MEMBASE;
13873         case CEE_LDIND_I4:
13874                 return OP_LOADI4_MEMBASE;
13875         case CEE_LDIND_U4:
13876                 return OP_LOADU4_MEMBASE;
13877         case CEE_LDIND_I:
13878                 return OP_LOAD_MEMBASE;
13879         case CEE_LDIND_REF:
13880                 return OP_LOAD_MEMBASE;
13881         case CEE_LDIND_I8:
13882                 return OP_LOADI8_MEMBASE;
13883         case CEE_LDIND_R4:
13884                 return OP_LOADR4_MEMBASE;
13885         case CEE_LDIND_R8:
13886                 return OP_LOADR8_MEMBASE;
13887         default:
13888                 g_assert_not_reached ();
13889         }
13890
13891         return -1;
13892 }
13893
13894 static int
13895 stind_to_store_membase (int opcode)
13896 {
13897         switch (opcode) {
13898         case CEE_STIND_I1:
13899                 return OP_STOREI1_MEMBASE_REG;
13900         case CEE_STIND_I2:
13901                 return OP_STOREI2_MEMBASE_REG;
13902         case CEE_STIND_I4:
13903                 return OP_STOREI4_MEMBASE_REG;
13904         case CEE_STIND_I:
13905         case CEE_STIND_REF:
13906                 return OP_STORE_MEMBASE_REG;
13907         case CEE_STIND_I8:
13908                 return OP_STOREI8_MEMBASE_REG;
13909         case CEE_STIND_R4:
13910                 return OP_STORER4_MEMBASE_REG;
13911         case CEE_STIND_R8:
13912                 return OP_STORER8_MEMBASE_REG;
13913         default:
13914                 g_assert_not_reached ();
13915         }
13916
13917         return -1;
13918 }
13919
13920 int
13921 mono_load_membase_to_load_mem (int opcode)
13922 {
13923         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
13924 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13925         switch (opcode) {
13926         case OP_LOAD_MEMBASE:
13927                 return OP_LOAD_MEM;
13928         case OP_LOADU1_MEMBASE:
13929                 return OP_LOADU1_MEM;
13930         case OP_LOADU2_MEMBASE:
13931                 return OP_LOADU2_MEM;
13932         case OP_LOADI4_MEMBASE:
13933                 return OP_LOADI4_MEM;
13934         case OP_LOADU4_MEMBASE:
13935                 return OP_LOADU4_MEM;
13936 #if SIZEOF_REGISTER == 8
13937         case OP_LOADI8_MEMBASE:
13938                 return OP_LOADI8_MEM;
13939 #endif
13940         }
13941 #endif
13942
13943         return -1;
13944 }
13945
13946 static inline int
13947 op_to_op_dest_membase (int store_opcode, int opcode)
13948 {
13949 #if defined(TARGET_X86)
13950         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
13951                 return -1;
13952
13953         switch (opcode) {
13954         case OP_IADD:
13955                 return OP_X86_ADD_MEMBASE_REG;
13956         case OP_ISUB:
13957                 return OP_X86_SUB_MEMBASE_REG;
13958         case OP_IAND:
13959                 return OP_X86_AND_MEMBASE_REG;
13960         case OP_IOR:
13961                 return OP_X86_OR_MEMBASE_REG;
13962         case OP_IXOR:
13963                 return OP_X86_XOR_MEMBASE_REG;
13964         case OP_ADD_IMM:
13965         case OP_IADD_IMM:
13966                 return OP_X86_ADD_MEMBASE_IMM;
13967         case OP_SUB_IMM:
13968         case OP_ISUB_IMM:
13969                 return OP_X86_SUB_MEMBASE_IMM;
13970         case OP_AND_IMM:
13971         case OP_IAND_IMM:
13972                 return OP_X86_AND_MEMBASE_IMM;
13973         case OP_OR_IMM:
13974         case OP_IOR_IMM:
13975                 return OP_X86_OR_MEMBASE_IMM;
13976         case OP_XOR_IMM:
13977         case OP_IXOR_IMM:
13978                 return OP_X86_XOR_MEMBASE_IMM;
13979         case OP_MOVE:
13980                 return OP_NOP;
13981         }
13982 #endif
13983
13984 #if defined(TARGET_AMD64)
13985         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
13986                 return -1;
13987
13988         switch (opcode) {
13989         case OP_IADD:
13990                 return OP_X86_ADD_MEMBASE_REG;
13991         case OP_ISUB:
13992                 return OP_X86_SUB_MEMBASE_REG;
13993         case OP_IAND:
13994                 return OP_X86_AND_MEMBASE_REG;
13995         case OP_IOR:
13996                 return OP_X86_OR_MEMBASE_REG;
13997         case OP_IXOR:
13998                 return OP_X86_XOR_MEMBASE_REG;
13999         case OP_IADD_IMM:
14000                 return OP_X86_ADD_MEMBASE_IMM;
14001         case OP_ISUB_IMM:
14002                 return OP_X86_SUB_MEMBASE_IMM;
14003         case OP_IAND_IMM:
14004                 return OP_X86_AND_MEMBASE_IMM;
14005         case OP_IOR_IMM:
14006                 return OP_X86_OR_MEMBASE_IMM;
14007         case OP_IXOR_IMM:
14008                 return OP_X86_XOR_MEMBASE_IMM;
14009         case OP_LADD:
14010                 return OP_AMD64_ADD_MEMBASE_REG;
14011         case OP_LSUB:
14012                 return OP_AMD64_SUB_MEMBASE_REG;
14013         case OP_LAND:
14014                 return OP_AMD64_AND_MEMBASE_REG;
14015         case OP_LOR:
14016                 return OP_AMD64_OR_MEMBASE_REG;
14017         case OP_LXOR:
14018                 return OP_AMD64_XOR_MEMBASE_REG;
14019         case OP_ADD_IMM:
14020         case OP_LADD_IMM:
14021                 return OP_AMD64_ADD_MEMBASE_IMM;
14022         case OP_SUB_IMM:
14023         case OP_LSUB_IMM:
14024                 return OP_AMD64_SUB_MEMBASE_IMM;
14025         case OP_AND_IMM:
14026         case OP_LAND_IMM:
14027                 return OP_AMD64_AND_MEMBASE_IMM;
14028         case OP_OR_IMM:
14029         case OP_LOR_IMM:
14030                 return OP_AMD64_OR_MEMBASE_IMM;
14031         case OP_XOR_IMM:
14032         case OP_LXOR_IMM:
14033                 return OP_AMD64_XOR_MEMBASE_IMM;
14034         case OP_MOVE:
14035                 return OP_NOP;
14036         }
14037 #endif
14038
14039         return -1;
14040 }
14041
14042 static inline int
14043 op_to_op_store_membase (int store_opcode, int opcode)
14044 {
14045 #if defined(TARGET_X86) || defined(TARGET_AMD64)
14046         switch (opcode) {
14047         case OP_ICEQ:
14048                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
14049                         return OP_X86_SETEQ_MEMBASE;
14050         case OP_CNE:
14051                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
14052                         return OP_X86_SETNE_MEMBASE;
14053         }
14054 #endif
14055
14056         return -1;
14057 }
14058
14059 static inline int
14060 op_to_op_src1_membase (MonoCompile *cfg, int load_opcode, int opcode)
14061 {
14062 #ifdef TARGET_X86
14063         /* FIXME: This has sign extension issues */
14064         /*
14065         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
14066                 return OP_X86_COMPARE_MEMBASE8_IMM;
14067         */
14068
14069         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
14070                 return -1;
14071
14072         switch (opcode) {
14073         case OP_X86_PUSH:
14074                 return OP_X86_PUSH_MEMBASE;
14075         case OP_COMPARE_IMM:
14076         case OP_ICOMPARE_IMM:
14077                 return OP_X86_COMPARE_MEMBASE_IMM;
14078         case OP_COMPARE:
14079         case OP_ICOMPARE:
14080                 return OP_X86_COMPARE_MEMBASE_REG;
14081         }
14082 #endif
14083
14084 #ifdef TARGET_AMD64
14085         /* FIXME: This has sign extension issues */
14086         /*
14087         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
14088                 return OP_X86_COMPARE_MEMBASE8_IMM;
14089         */
14090
14091         switch (opcode) {
14092         case OP_X86_PUSH:
14093                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
14094                         return OP_X86_PUSH_MEMBASE;
14095                 break;
14096                 /* FIXME: This only works for 32 bit immediates
14097         case OP_COMPARE_IMM:
14098         case OP_LCOMPARE_IMM:
14099                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
14100                         return OP_AMD64_COMPARE_MEMBASE_IMM;
14101                 */
14102         case OP_ICOMPARE_IMM:
14103                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
14104                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
14105                 break;
14106         case OP_COMPARE:
14107         case OP_LCOMPARE:
14108                 if (cfg->backend->ilp32 && load_opcode == OP_LOAD_MEMBASE)
14109                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
14110                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
14111                         return OP_AMD64_COMPARE_MEMBASE_REG;
14112                 break;
14113         case OP_ICOMPARE:
14114                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
14115                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
14116                 break;
14117         }
14118 #endif
14119
14120         return -1;
14121 }
14122
14123 static inline int
14124 op_to_op_src2_membase (MonoCompile *cfg, int load_opcode, int opcode)
14125 {
14126 #ifdef TARGET_X86
14127         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
14128                 return -1;
14129         
14130         switch (opcode) {
14131         case OP_COMPARE:
14132         case OP_ICOMPARE:
14133                 return OP_X86_COMPARE_REG_MEMBASE;
14134         case OP_IADD:
14135                 return OP_X86_ADD_REG_MEMBASE;
14136         case OP_ISUB:
14137                 return OP_X86_SUB_REG_MEMBASE;
14138         case OP_IAND:
14139                 return OP_X86_AND_REG_MEMBASE;
14140         case OP_IOR:
14141                 return OP_X86_OR_REG_MEMBASE;
14142         case OP_IXOR:
14143                 return OP_X86_XOR_REG_MEMBASE;
14144         }
14145 #endif
14146
14147 #ifdef TARGET_AMD64
14148         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && cfg->backend->ilp32)) {
14149                 switch (opcode) {
14150                 case OP_ICOMPARE:
14151                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
14152                 case OP_IADD:
14153                         return OP_X86_ADD_REG_MEMBASE;
14154                 case OP_ISUB:
14155                         return OP_X86_SUB_REG_MEMBASE;
14156                 case OP_IAND:
14157                         return OP_X86_AND_REG_MEMBASE;
14158                 case OP_IOR:
14159                         return OP_X86_OR_REG_MEMBASE;
14160                 case OP_IXOR:
14161                         return OP_X86_XOR_REG_MEMBASE;
14162                 }
14163         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32)) {
14164                 switch (opcode) {
14165                 case OP_COMPARE:
14166                 case OP_LCOMPARE:
14167                         return OP_AMD64_COMPARE_REG_MEMBASE;
14168                 case OP_LADD:
14169                         return OP_AMD64_ADD_REG_MEMBASE;
14170                 case OP_LSUB:
14171                         return OP_AMD64_SUB_REG_MEMBASE;
14172                 case OP_LAND:
14173                         return OP_AMD64_AND_REG_MEMBASE;
14174                 case OP_LOR:
14175                         return OP_AMD64_OR_REG_MEMBASE;
14176                 case OP_LXOR:
14177                         return OP_AMD64_XOR_REG_MEMBASE;
14178                 }
14179         }
14180 #endif
14181
14182         return -1;
14183 }
14184
14185 int
14186 mono_op_to_op_imm_noemul (int opcode)
14187 {
14188         switch (opcode) {
14189 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
14190         case OP_LSHR:
14191         case OP_LSHL:
14192         case OP_LSHR_UN:
14193                 return -1;
14194 #endif
14195 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
14196         case OP_IDIV:
14197         case OP_IDIV_UN:
14198         case OP_IREM:
14199         case OP_IREM_UN:
14200                 return -1;
14201 #endif
14202 #if defined(MONO_ARCH_EMULATE_MUL_DIV)
14203         case OP_IMUL:
14204                 return -1;
14205 #endif
14206         default:
14207                 return mono_op_to_op_imm (opcode);
14208         }
14209 }
14210
14211 /**
14212  * mono_handle_global_vregs:
14213  *
14214  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
14215  * for them.
14216  */
14217 void
14218 mono_handle_global_vregs (MonoCompile *cfg)
14219 {
14220         gint32 *vreg_to_bb;
14221         MonoBasicBlock *bb;
14222         int i, pos;
14223
14224         vreg_to_bb = (gint32 *)mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
14225
14226 #ifdef MONO_ARCH_SIMD_INTRINSICS
14227         if (cfg->uses_simd_intrinsics)
14228                 mono_simd_simplify_indirection (cfg);
14229 #endif
14230
14231         /* Find local vregs used in more than one bb */
14232         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
14233                 MonoInst *ins = bb->code;       
14234                 int block_num = bb->block_num;
14235
14236                 if (cfg->verbose_level > 2)
14237                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
14238
14239                 cfg->cbb = bb;
14240                 for (; ins; ins = ins->next) {
14241                         const char *spec = INS_INFO (ins->opcode);
14242                         int regtype = 0, regindex;
14243                         gint32 prev_bb;
14244
14245                         if (G_UNLIKELY (cfg->verbose_level > 2))
14246                                 mono_print_ins (ins);
14247
14248                         g_assert (ins->opcode >= MONO_CEE_LAST);
14249
14250                         for (regindex = 0; regindex < 4; regindex ++) {
14251                                 int vreg = 0;
14252
14253                                 if (regindex == 0) {
14254                                         regtype = spec [MONO_INST_DEST];
14255                                         if (regtype == ' ')
14256                                                 continue;
14257                                         vreg = ins->dreg;
14258                                 } else if (regindex == 1) {
14259                                         regtype = spec [MONO_INST_SRC1];
14260                                         if (regtype == ' ')
14261                                                 continue;
14262                                         vreg = ins->sreg1;
14263                                 } else if (regindex == 2) {
14264                                         regtype = spec [MONO_INST_SRC2];
14265                                         if (regtype == ' ')
14266                                                 continue;
14267                                         vreg = ins->sreg2;
14268                                 } else if (regindex == 3) {
14269                                         regtype = spec [MONO_INST_SRC3];
14270                                         if (regtype == ' ')
14271                                                 continue;
14272                                         vreg = ins->sreg3;
14273                                 }
14274
14275 #if SIZEOF_REGISTER == 4
14276                                 /* In the LLVM case, the long opcodes are not decomposed */
14277                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
14278                                         /*
14279                                          * Since some instructions reference the original long vreg,
14280                                          * and some reference the two component vregs, it is quite hard
14281                                          * to determine when it needs to be global. So be conservative.
14282                                          */
14283                                         if (!get_vreg_to_inst (cfg, vreg)) {
14284                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
14285
14286                                                 if (cfg->verbose_level > 2)
14287                                                         printf ("LONG VREG R%d made global.\n", vreg);
14288                                         }
14289
14290                                         /*
14291                                          * Make the component vregs volatile since the optimizations can
14292                                          * get confused otherwise.
14293                                          */
14294                                         get_vreg_to_inst (cfg, MONO_LVREG_LS (vreg))->flags |= MONO_INST_VOLATILE;
14295                                         get_vreg_to_inst (cfg, MONO_LVREG_MS (vreg))->flags |= MONO_INST_VOLATILE;
14296                                 }
14297 #endif
14298
14299                                 g_assert (vreg != -1);
14300
14301                                 prev_bb = vreg_to_bb [vreg];
14302                                 if (prev_bb == 0) {
14303                                         /* 0 is a valid block num */
14304                                         vreg_to_bb [vreg] = block_num + 1;
14305                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
14306                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
14307                                                 continue;
14308
14309                                         if (!get_vreg_to_inst (cfg, vreg)) {
14310                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14311                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
14312
14313                                                 switch (regtype) {
14314                                                 case 'i':
14315                                                         if (vreg_is_ref (cfg, vreg))
14316                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg);
14317                                                         else
14318                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
14319                                                         break;
14320                                                 case 'l':
14321                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
14322                                                         break;
14323                                                 case 'f':
14324                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
14325                                                         break;
14326                                                 case 'v':
14327                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
14328                                                         break;
14329                                                 default:
14330                                                         g_assert_not_reached ();
14331                                                 }
14332                                         }
14333
14334                                         /* Flag as having been used in more than one bb */
14335                                         vreg_to_bb [vreg] = -1;
14336                                 }
14337                         }
14338                 }
14339         }
14340
14341         /* If a variable is used in only one bblock, convert it into a local vreg */
14342         for (i = 0; i < cfg->num_varinfo; i++) {
14343                 MonoInst *var = cfg->varinfo [i];
14344                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
14345
14346                 switch (var->type) {
14347                 case STACK_I4:
14348                 case STACK_OBJ:
14349                 case STACK_PTR:
14350                 case STACK_MP:
14351                 case STACK_VTYPE:
14352 #if SIZEOF_REGISTER == 8
14353                 case STACK_I8:
14354 #endif
14355 #if !defined(TARGET_X86)
14356                 /* Enabling this screws up the fp stack on x86 */
14357                 case STACK_R8:
14358 #endif
14359                         if (mono_arch_is_soft_float ())
14360                                 break;
14361
14362                         /*
14363                         if (var->type == STACK_VTYPE && cfg->gsharedvt && mini_is_gsharedvt_variable_type (var->inst_vtype))
14364                                 break;
14365                         */
14366
14367                         /* Arguments are implicitly global */
14368                         /* Putting R4 vars into registers doesn't work currently */
14369                         /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
14370                         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) {
14371                                 /* 
14372                                  * Make that the variable's liveness interval doesn't contain a call, since
14373                                  * that would cause the lvreg to be spilled, making the whole optimization
14374                                  * useless.
14375                                  */
14376                                 /* This is too slow for JIT compilation */
14377 #if 0
14378                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
14379                                         MonoInst *ins;
14380                                         int def_index, call_index, ins_index;
14381                                         gboolean spilled = FALSE;
14382
14383                                         def_index = -1;
14384                                         call_index = -1;
14385                                         ins_index = 0;
14386                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
14387                                                 const char *spec = INS_INFO (ins->opcode);
14388
14389                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
14390                                                         def_index = ins_index;
14391
14392                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
14393                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
14394                                                         if (call_index > def_index) {
14395                                                                 spilled = TRUE;
14396                                                                 break;
14397                                                         }
14398                                                 }
14399
14400                                                 if (MONO_IS_CALL (ins))
14401                                                         call_index = ins_index;
14402
14403                                                 ins_index ++;
14404                                         }
14405
14406                                         if (spilled)
14407                                                 break;
14408                                 }
14409 #endif
14410
14411                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14412                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
14413                                 var->flags |= MONO_INST_IS_DEAD;
14414                                 cfg->vreg_to_inst [var->dreg] = NULL;
14415                         }
14416                         break;
14417                 }
14418         }
14419
14420         /* 
14421          * Compress the varinfo and vars tables so the liveness computation is faster and
14422          * takes up less space.
14423          */
14424         pos = 0;
14425         for (i = 0; i < cfg->num_varinfo; ++i) {
14426                 MonoInst *var = cfg->varinfo [i];
14427                 if (pos < i && cfg->locals_start == i)
14428                         cfg->locals_start = pos;
14429                 if (!(var->flags & MONO_INST_IS_DEAD)) {
14430                         if (pos < i) {
14431                                 cfg->varinfo [pos] = cfg->varinfo [i];
14432                                 cfg->varinfo [pos]->inst_c0 = pos;
14433                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
14434                                 cfg->vars [pos].idx = pos;
14435 #if SIZEOF_REGISTER == 4
14436                                 if (cfg->varinfo [pos]->type == STACK_I8) {
14437                                         /* Modify the two component vars too */
14438                                         MonoInst *var1;
14439
14440                                         var1 = get_vreg_to_inst (cfg, MONO_LVREG_LS (cfg->varinfo [pos]->dreg));
14441                                         var1->inst_c0 = pos;
14442                                         var1 = get_vreg_to_inst (cfg, MONO_LVREG_MS (cfg->varinfo [pos]->dreg));
14443                                         var1->inst_c0 = pos;
14444                                 }
14445 #endif
14446                         }
14447                         pos ++;
14448                 }
14449         }
14450         cfg->num_varinfo = pos;
14451         if (cfg->locals_start > cfg->num_varinfo)
14452                 cfg->locals_start = cfg->num_varinfo;
14453 }
14454
14455 /*
14456  * mono_allocate_gsharedvt_vars:
14457  *
14458  *   Allocate variables with gsharedvt types to entries in the MonoGSharedVtMethodRuntimeInfo.entries array.
14459  * Initialize cfg->gsharedvt_vreg_to_idx with the mapping between vregs and indexes.
14460  */
14461 void
14462 mono_allocate_gsharedvt_vars (MonoCompile *cfg)
14463 {
14464         int i;
14465
14466         cfg->gsharedvt_vreg_to_idx = (int *)mono_mempool_alloc0 (cfg->mempool, sizeof (int) * cfg->next_vreg);
14467
14468         for (i = 0; i < cfg->num_varinfo; ++i) {
14469                 MonoInst *ins = cfg->varinfo [i];
14470                 int idx;
14471
14472                 if (mini_is_gsharedvt_variable_type (ins->inst_vtype)) {
14473                         if (i >= cfg->locals_start) {
14474                                 /* Local */
14475                                 idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
14476                                 cfg->gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
14477                                 ins->opcode = OP_GSHAREDVT_LOCAL;
14478                                 ins->inst_imm = idx;
14479                         } else {
14480                                 /* Arg */
14481                                 cfg->gsharedvt_vreg_to_idx [ins->dreg] = -1;
14482                                 ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
14483                         }
14484                 }
14485         }
14486 }
14487
14488 /**
14489  * mono_spill_global_vars:
14490  *
14491  *   Generate spill code for variables which are not allocated to registers, 
14492  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
14493  * code is generated which could be optimized by the local optimization passes.
14494  */
14495 void
14496 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
14497 {
14498         MonoBasicBlock *bb;
14499         char spec2 [16];
14500         int orig_next_vreg;
14501         guint32 *vreg_to_lvreg;
14502         guint32 *lvregs;
14503         guint32 i, lvregs_len;
14504         gboolean dest_has_lvreg = FALSE;
14505         MonoStackType stacktypes [128];
14506         MonoInst **live_range_start, **live_range_end;
14507         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
14508
14509         *need_local_opts = FALSE;
14510
14511         memset (spec2, 0, sizeof (spec2));
14512
14513         /* FIXME: Move this function to mini.c */
14514         stacktypes ['i'] = STACK_PTR;
14515         stacktypes ['l'] = STACK_I8;
14516         stacktypes ['f'] = STACK_R8;
14517 #ifdef MONO_ARCH_SIMD_INTRINSICS
14518         stacktypes ['x'] = STACK_VTYPE;
14519 #endif
14520
14521 #if SIZEOF_REGISTER == 4
14522         /* Create MonoInsts for longs */
14523         for (i = 0; i < cfg->num_varinfo; i++) {
14524                 MonoInst *ins = cfg->varinfo [i];
14525
14526                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
14527                         switch (ins->type) {
14528                         case STACK_R8:
14529                         case STACK_I8: {
14530                                 MonoInst *tree;
14531
14532                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
14533                                         break;
14534
14535                                 g_assert (ins->opcode == OP_REGOFFSET);
14536
14537                                 tree = get_vreg_to_inst (cfg, MONO_LVREG_LS (ins->dreg));
14538                                 g_assert (tree);
14539                                 tree->opcode = OP_REGOFFSET;
14540                                 tree->inst_basereg = ins->inst_basereg;
14541                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
14542
14543                                 tree = get_vreg_to_inst (cfg, MONO_LVREG_MS (ins->dreg));
14544                                 g_assert (tree);
14545                                 tree->opcode = OP_REGOFFSET;
14546                                 tree->inst_basereg = ins->inst_basereg;
14547                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
14548                                 break;
14549                         }
14550                         default:
14551                                 break;
14552                         }
14553                 }
14554         }
14555 #endif
14556
14557         if (cfg->compute_gc_maps) {
14558                 /* registers need liveness info even for !non refs */
14559                 for (i = 0; i < cfg->num_varinfo; i++) {
14560                         MonoInst *ins = cfg->varinfo [i];
14561
14562                         if (ins->opcode == OP_REGVAR)
14563                                 ins->flags |= MONO_INST_GC_TRACK;
14564                 }
14565         }
14566                 
14567         /* FIXME: widening and truncation */
14568
14569         /*
14570          * As an optimization, when a variable allocated to the stack is first loaded into 
14571          * an lvreg, we will remember the lvreg and use it the next time instead of loading
14572          * the variable again.
14573          */
14574         orig_next_vreg = cfg->next_vreg;
14575         vreg_to_lvreg = (guint32 *)mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
14576         lvregs = (guint32 *)mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
14577         lvregs_len = 0;
14578
14579         /* 
14580          * These arrays contain the first and last instructions accessing a given
14581          * variable.
14582          * Since we emit bblocks in the same order we process them here, and we
14583          * don't split live ranges, these will precisely describe the live range of
14584          * the variable, i.e. the instruction range where a valid value can be found
14585          * in the variables location.
14586          * The live range is computed using the liveness info computed by the liveness pass.
14587          * We can't use vmv->range, since that is an abstract live range, and we need
14588          * one which is instruction precise.
14589          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
14590          */
14591         /* FIXME: Only do this if debugging info is requested */
14592         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
14593         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
14594         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
14595         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
14596         
14597         /* Add spill loads/stores */
14598         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
14599                 MonoInst *ins;
14600
14601                 if (cfg->verbose_level > 2)
14602                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
14603
14604                 /* Clear vreg_to_lvreg array */
14605                 for (i = 0; i < lvregs_len; i++)
14606                         vreg_to_lvreg [lvregs [i]] = 0;
14607                 lvregs_len = 0;
14608
14609                 cfg->cbb = bb;
14610                 MONO_BB_FOR_EACH_INS (bb, ins) {
14611                         const char *spec = INS_INFO (ins->opcode);
14612                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
14613                         gboolean store, no_lvreg;
14614                         int sregs [MONO_MAX_SRC_REGS];
14615
14616                         if (G_UNLIKELY (cfg->verbose_level > 2))
14617                                 mono_print_ins (ins);
14618
14619                         if (ins->opcode == OP_NOP)
14620                                 continue;
14621
14622                         /* 
14623                          * We handle LDADDR here as well, since it can only be decomposed
14624                          * when variable addresses are known.
14625                          */
14626                         if (ins->opcode == OP_LDADDR) {
14627                                 MonoInst *var = (MonoInst *)ins->inst_p0;
14628
14629                                 if (var->opcode == OP_VTARG_ADDR) {
14630                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
14631                                         MonoInst *vtaddr = var->inst_left;
14632                                         if (vtaddr->opcode == OP_REGVAR) {
14633                                                 ins->opcode = OP_MOVE;
14634                                                 ins->sreg1 = vtaddr->dreg;
14635                                         }
14636                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
14637                                                 ins->opcode = OP_LOAD_MEMBASE;
14638                                                 ins->inst_basereg = vtaddr->inst_basereg;
14639                                                 ins->inst_offset = vtaddr->inst_offset;
14640                                         } else
14641                                                 NOT_IMPLEMENTED;
14642                                 } else if (cfg->gsharedvt && cfg->gsharedvt_vreg_to_idx [var->dreg] < 0) {
14643                                         /* gsharedvt arg passed by ref */
14644                                         g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
14645
14646                                         ins->opcode = OP_LOAD_MEMBASE;
14647                                         ins->inst_basereg = var->inst_basereg;
14648                                         ins->inst_offset = var->inst_offset;
14649                                 } else if (cfg->gsharedvt && cfg->gsharedvt_vreg_to_idx [var->dreg]) {
14650                                         MonoInst *load, *load2, *load3;
14651                                         int idx = cfg->gsharedvt_vreg_to_idx [var->dreg] - 1;
14652                                         int reg1, reg2, reg3;
14653                                         MonoInst *info_var = cfg->gsharedvt_info_var;
14654                                         MonoInst *locals_var = cfg->gsharedvt_locals_var;
14655
14656                                         /*
14657                                          * gsharedvt local.
14658                                          * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
14659                                          */
14660
14661                                         g_assert (var->opcode == OP_GSHAREDVT_LOCAL);
14662
14663                                         g_assert (info_var);
14664                                         g_assert (locals_var);
14665
14666                                         /* Mark the instruction used to compute the locals var as used */
14667                                         cfg->gsharedvt_locals_var_ins = NULL;
14668
14669                                         /* Load the offset */
14670                                         if (info_var->opcode == OP_REGOFFSET) {
14671                                                 reg1 = alloc_ireg (cfg);
14672                                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, reg1, info_var->inst_basereg, info_var->inst_offset);
14673                                         } else if (info_var->opcode == OP_REGVAR) {
14674                                                 load = NULL;
14675                                                 reg1 = info_var->dreg;
14676                                         } else {
14677                                                 g_assert_not_reached ();
14678                                         }
14679                                         reg2 = alloc_ireg (cfg);
14680                                         NEW_LOAD_MEMBASE (cfg, load2, OP_LOADI4_MEMBASE, reg2, reg1, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
14681                                         /* Load the locals area address */
14682                                         reg3 = alloc_ireg (cfg);
14683                                         if (locals_var->opcode == OP_REGOFFSET) {
14684                                                 NEW_LOAD_MEMBASE (cfg, load3, OP_LOAD_MEMBASE, reg3, locals_var->inst_basereg, locals_var->inst_offset);
14685                                         } else if (locals_var->opcode == OP_REGVAR) {
14686                                                 NEW_UNALU (cfg, load3, OP_MOVE, reg3, locals_var->dreg);
14687                                         } else {
14688                                                 g_assert_not_reached ();
14689                                         }
14690                                         /* Compute the address */
14691                                         ins->opcode = OP_PADD;
14692                                         ins->sreg1 = reg3;
14693                                         ins->sreg2 = reg2;
14694
14695                                         mono_bblock_insert_before_ins (bb, ins, load3);
14696                                         mono_bblock_insert_before_ins (bb, load3, load2);
14697                                         if (load)
14698                                                 mono_bblock_insert_before_ins (bb, load2, load);
14699                                 } else {
14700                                         g_assert (var->opcode == OP_REGOFFSET);
14701
14702                                         ins->opcode = OP_ADD_IMM;
14703                                         ins->sreg1 = var->inst_basereg;
14704                                         ins->inst_imm = var->inst_offset;
14705                                 }
14706
14707                                 *need_local_opts = TRUE;
14708                                 spec = INS_INFO (ins->opcode);
14709                         }
14710
14711                         if (ins->opcode < MONO_CEE_LAST) {
14712                                 mono_print_ins (ins);
14713                                 g_assert_not_reached ();
14714                         }
14715
14716                         /*
14717                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
14718                          * src register.
14719                          * FIXME:
14720                          */
14721                         if (MONO_IS_STORE_MEMBASE (ins)) {
14722                                 tmp_reg = ins->dreg;
14723                                 ins->dreg = ins->sreg2;
14724                                 ins->sreg2 = tmp_reg;
14725                                 store = TRUE;
14726
14727                                 spec2 [MONO_INST_DEST] = ' ';
14728                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14729                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14730                                 spec2 [MONO_INST_SRC3] = ' ';
14731                                 spec = spec2;
14732                         } else if (MONO_IS_STORE_MEMINDEX (ins))
14733                                 g_assert_not_reached ();
14734                         else
14735                                 store = FALSE;
14736                         no_lvreg = FALSE;
14737
14738                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
14739                                 printf ("\t %.3s %d", spec, ins->dreg);
14740                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
14741                                 for (srcindex = 0; srcindex < num_sregs; ++srcindex)
14742                                         printf (" %d", sregs [srcindex]);
14743                                 printf ("\n");
14744                         }
14745
14746                         /***************/
14747                         /*    DREG     */
14748                         /***************/
14749                         regtype = spec [MONO_INST_DEST];
14750                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
14751                         prev_dreg = -1;
14752
14753                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
14754                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
14755                                 MonoInst *store_ins;
14756                                 int store_opcode;
14757                                 MonoInst *def_ins = ins;
14758                                 int dreg = ins->dreg; /* The original vreg */
14759
14760                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
14761
14762                                 if (var->opcode == OP_REGVAR) {
14763                                         ins->dreg = var->dreg;
14764                                 } 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)) {
14765                                         /* 
14766                                          * Instead of emitting a load+store, use a _membase opcode.
14767                                          */
14768                                         g_assert (var->opcode == OP_REGOFFSET);
14769                                         if (ins->opcode == OP_MOVE) {
14770                                                 NULLIFY_INS (ins);
14771                                                 def_ins = NULL;
14772                                         } else {
14773                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
14774                                                 ins->inst_basereg = var->inst_basereg;
14775                                                 ins->inst_offset = var->inst_offset;
14776                                                 ins->dreg = -1;
14777                                         }
14778                                         spec = INS_INFO (ins->opcode);
14779                                 } else {
14780                                         guint32 lvreg;
14781
14782                                         g_assert (var->opcode == OP_REGOFFSET);
14783
14784                                         prev_dreg = ins->dreg;
14785
14786                                         /* Invalidate any previous lvreg for this vreg */
14787                                         vreg_to_lvreg [ins->dreg] = 0;
14788
14789                                         lvreg = 0;
14790
14791                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
14792                                                 regtype = 'l';
14793                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
14794                                         }
14795
14796                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
14797
14798 #if SIZEOF_REGISTER != 8
14799                                         if (regtype == 'l') {
14800                                                 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));
14801                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14802                                                 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));
14803                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14804                                                 def_ins = store_ins;
14805                                         }
14806                                         else
14807 #endif
14808                                         {
14809                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
14810
14811                                                 /* Try to fuse the store into the instruction itself */
14812                                                 /* FIXME: Add more instructions */
14813                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
14814                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
14815                                                         ins->inst_imm = ins->inst_c0;
14816                                                         ins->inst_destbasereg = var->inst_basereg;
14817                                                         ins->inst_offset = var->inst_offset;
14818                                                         spec = INS_INFO (ins->opcode);
14819                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE) || (ins->opcode == OP_RMOVE))) {
14820                                                         ins->opcode = store_opcode;
14821                                                         ins->inst_destbasereg = var->inst_basereg;
14822                                                         ins->inst_offset = var->inst_offset;
14823
14824                                                         no_lvreg = TRUE;
14825
14826                                                         tmp_reg = ins->dreg;
14827                                                         ins->dreg = ins->sreg2;
14828                                                         ins->sreg2 = tmp_reg;
14829                                                         store = TRUE;
14830
14831                                                         spec2 [MONO_INST_DEST] = ' ';
14832                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14833                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14834                                                         spec2 [MONO_INST_SRC3] = ' ';
14835                                                         spec = spec2;
14836                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
14837                                                         // FIXME: The backends expect the base reg to be in inst_basereg
14838                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
14839                                                         ins->dreg = -1;
14840                                                         ins->inst_basereg = var->inst_basereg;
14841                                                         ins->inst_offset = var->inst_offset;
14842                                                         spec = INS_INFO (ins->opcode);
14843                                                 } else {
14844                                                         /* printf ("INS: "); mono_print_ins (ins); */
14845                                                         /* Create a store instruction */
14846                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
14847
14848                                                         /* Insert it after the instruction */
14849                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
14850
14851                                                         def_ins = store_ins;
14852
14853                                                         /* 
14854                                                          * We can't assign ins->dreg to var->dreg here, since the
14855                                                          * sregs could use it. So set a flag, and do it after
14856                                                          * the sregs.
14857                                                          */
14858                                                         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)))
14859                                                                 dest_has_lvreg = TRUE;
14860                                                 }
14861                                         }
14862                                 }
14863
14864                                 if (def_ins && !live_range_start [dreg]) {
14865                                         live_range_start [dreg] = def_ins;
14866                                         live_range_start_bb [dreg] = bb;
14867                                 }
14868
14869                                 if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) {
14870                                         MonoInst *tmp;
14871
14872                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
14873                                         tmp->inst_c1 = dreg;
14874                                         mono_bblock_insert_after_ins (bb, def_ins, tmp);
14875                                 }
14876                         }
14877
14878                         /************/
14879                         /*  SREGS   */
14880                         /************/
14881                         num_sregs = mono_inst_get_src_registers (ins, sregs);
14882                         for (srcindex = 0; srcindex < 3; ++srcindex) {
14883                                 regtype = spec [MONO_INST_SRC1 + srcindex];
14884                                 sreg = sregs [srcindex];
14885
14886                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
14887                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
14888                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
14889                                         MonoInst *use_ins = ins;
14890                                         MonoInst *load_ins;
14891                                         guint32 load_opcode;
14892
14893                                         if (var->opcode == OP_REGVAR) {
14894                                                 sregs [srcindex] = var->dreg;
14895                                                 //mono_inst_set_src_registers (ins, sregs);
14896                                                 live_range_end [sreg] = use_ins;
14897                                                 live_range_end_bb [sreg] = bb;
14898
14899                                                 if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14900                                                         MonoInst *tmp;
14901
14902                                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14903                                                         /* var->dreg is a hreg */
14904                                                         tmp->inst_c1 = sreg;
14905                                                         mono_bblock_insert_after_ins (bb, ins, tmp);
14906                                                 }
14907
14908                                                 continue;
14909                                         }
14910
14911                                         g_assert (var->opcode == OP_REGOFFSET);
14912                                                 
14913                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
14914
14915                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
14916
14917                                         if (vreg_to_lvreg [sreg]) {
14918                                                 g_assert (vreg_to_lvreg [sreg] != -1);
14919
14920                                                 /* The variable is already loaded to an lvreg */
14921                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14922                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
14923                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
14924                                                 //mono_inst_set_src_registers (ins, sregs);
14925                                                 continue;
14926                                         }
14927
14928                                         /* Try to fuse the load into the instruction */
14929                                         if ((srcindex == 0) && (op_to_op_src1_membase (cfg, load_opcode, ins->opcode) != -1)) {
14930                                                 ins->opcode = op_to_op_src1_membase (cfg, load_opcode, ins->opcode);
14931                                                 sregs [0] = var->inst_basereg;
14932                                                 //mono_inst_set_src_registers (ins, sregs);
14933                                                 ins->inst_offset = var->inst_offset;
14934                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (cfg, load_opcode, ins->opcode) != -1)) {
14935                                                 ins->opcode = op_to_op_src2_membase (cfg, load_opcode, ins->opcode);
14936                                                 sregs [1] = var->inst_basereg;
14937                                                 //mono_inst_set_src_registers (ins, sregs);
14938                                                 ins->inst_offset = var->inst_offset;
14939                                         } else {
14940                                                 if (MONO_IS_REAL_MOVE (ins)) {
14941                                                         ins->opcode = OP_NOP;
14942                                                         sreg = ins->dreg;
14943                                                 } else {
14944                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
14945
14946                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
14947
14948                                                         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) {
14949                                                                 if (var->dreg == prev_dreg) {
14950                                                                         /*
14951                                                                          * sreg refers to the value loaded by the load
14952                                                                          * emitted below, but we need to use ins->dreg
14953                                                                          * since it refers to the store emitted earlier.
14954                                                                          */
14955                                                                         sreg = ins->dreg;
14956                                                                 }
14957                                                                 g_assert (sreg != -1);
14958                                                                 vreg_to_lvreg [var->dreg] = sreg;
14959                                                                 g_assert (lvregs_len < 1024);
14960                                                                 lvregs [lvregs_len ++] = var->dreg;
14961                                                         }
14962                                                 }
14963
14964                                                 sregs [srcindex] = sreg;
14965                                                 //mono_inst_set_src_registers (ins, sregs);
14966
14967 #if SIZEOF_REGISTER != 8
14968                                                 if (regtype == 'l') {
14969                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, MONO_LVREG_MS (sreg), var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
14970                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14971                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, MONO_LVREG_LS (sreg), var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
14972                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14973                                                         use_ins = load_ins;
14974                                                 }
14975                                                 else
14976 #endif
14977                                                 {
14978 #if SIZEOF_REGISTER == 4
14979                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
14980 #endif
14981                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
14982                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14983                                                         use_ins = load_ins;
14984                                                 }
14985                                         }
14986
14987                                         if (var->dreg < orig_next_vreg) {
14988                                                 live_range_end [var->dreg] = use_ins;
14989                                                 live_range_end_bb [var->dreg] = bb;
14990                                         }
14991
14992                                         if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14993                                                 MonoInst *tmp;
14994
14995                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14996                                                 tmp->inst_c1 = var->dreg;
14997                                                 mono_bblock_insert_after_ins (bb, ins, tmp);
14998                                         }
14999                                 }
15000                         }
15001                         mono_inst_set_src_registers (ins, sregs);
15002
15003                         if (dest_has_lvreg) {
15004                                 g_assert (ins->dreg != -1);
15005                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
15006                                 g_assert (lvregs_len < 1024);
15007                                 lvregs [lvregs_len ++] = prev_dreg;
15008                                 dest_has_lvreg = FALSE;
15009                         }
15010
15011                         if (store) {
15012                                 tmp_reg = ins->dreg;
15013                                 ins->dreg = ins->sreg2;
15014                                 ins->sreg2 = tmp_reg;
15015                         }
15016
15017                         if (MONO_IS_CALL (ins)) {
15018                                 /* Clear vreg_to_lvreg array */
15019                                 for (i = 0; i < lvregs_len; i++)
15020                                         vreg_to_lvreg [lvregs [i]] = 0;
15021                                 lvregs_len = 0;
15022                         } else if (ins->opcode == OP_NOP) {
15023                                 ins->dreg = -1;
15024                                 MONO_INST_NULLIFY_SREGS (ins);
15025                         }
15026
15027                         if (cfg->verbose_level > 2)
15028                                 mono_print_ins_index (1, ins);
15029                 }
15030
15031                 /* Extend the live range based on the liveness info */
15032                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
15033                         for (i = 0; i < cfg->num_varinfo; i ++) {
15034                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
15035
15036                                 if (vreg_is_volatile (cfg, vi->vreg))
15037                                         /* The liveness info is incomplete */
15038                                         continue;
15039
15040                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
15041                                         /* Live from at least the first ins of this bb */
15042                                         live_range_start [vi->vreg] = bb->code;
15043                                         live_range_start_bb [vi->vreg] = bb;
15044                                 }
15045
15046                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
15047                                         /* Live at least until the last ins of this bb */
15048                                         live_range_end [vi->vreg] = bb->last_ins;
15049                                         live_range_end_bb [vi->vreg] = bb;
15050                                 }
15051                         }
15052                 }
15053         }
15054         
15055         /*
15056          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
15057          * by storing the current native offset into MonoMethodVar->live_range_start/end.
15058          */
15059         if (cfg->backend->have_liverange_ops && cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
15060                 for (i = 0; i < cfg->num_varinfo; ++i) {
15061                         int vreg = MONO_VARINFO (cfg, i)->vreg;
15062                         MonoInst *ins;
15063
15064                         if (live_range_start [vreg]) {
15065                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
15066                                 ins->inst_c0 = i;
15067                                 ins->inst_c1 = vreg;
15068                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
15069                         }
15070                         if (live_range_end [vreg]) {
15071                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
15072                                 ins->inst_c0 = i;
15073                                 ins->inst_c1 = vreg;
15074                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
15075                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
15076                                 else
15077                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
15078                         }
15079                 }
15080         }
15081
15082         if (cfg->gsharedvt_locals_var_ins) {
15083                 /* Nullify if unused */
15084                 cfg->gsharedvt_locals_var_ins->opcode = OP_PCONST;
15085                 cfg->gsharedvt_locals_var_ins->inst_imm = 0;
15086         }
15087
15088         g_free (live_range_start);
15089         g_free (live_range_end);
15090         g_free (live_range_start_bb);
15091         g_free (live_range_end_bb);
15092 }
15093
15094 static void
15095 mono_decompose_typecheck (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins)
15096 {
15097         MonoInst *ret, *move, *source;
15098         MonoClass *klass = ins->klass;
15099         int context_used = mini_class_check_context_used (cfg, klass);
15100         int is_isinst = ins->opcode == OP_ISINST;
15101         g_assert (is_isinst || ins->opcode == OP_CASTCLASS);
15102         source = get_vreg_to_inst (cfg, ins->sreg1);
15103         if (!source || source == (MonoInst *) -1)
15104                 source = mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, ins->sreg1);
15105         g_assert (source && source != (MonoInst *) -1);
15106
15107         MonoBasicBlock *first_bb;
15108         NEW_BBLOCK (cfg, first_bb);
15109         cfg->cbb = first_bb;
15110
15111         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
15112                 if (is_isinst)
15113                         ret = emit_isinst_with_cache_nonshared (cfg, source, klass);
15114                 else
15115                         ret = emit_castclass_with_cache_nonshared (cfg, source, klass);
15116         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
15117                 MonoInst *iargs [1];
15118                 int costs;
15119
15120                 iargs [0] = source;
15121                 if (is_isinst) {
15122                         MonoMethod *wrapper = mono_marshal_get_isinst (klass);
15123                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), iargs, 0, 0, TRUE);
15124                 } else {
15125                         MonoMethod *wrapper = mono_marshal_get_castclass (klass);
15126                         save_cast_details (cfg, klass, source->dreg, TRUE);
15127                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), iargs, 0, 0, TRUE);
15128                         reset_cast_details (cfg);
15129                 }
15130                 g_assert (costs > 0);
15131                 ret = iargs [0];
15132         } else {
15133                 if (is_isinst)
15134                         ret = handle_isinst (cfg, klass, source, context_used);
15135                 else
15136                         ret = handle_castclass (cfg, klass, source, context_used);
15137         }
15138         EMIT_NEW_UNALU (cfg, move, OP_MOVE, ins->dreg, ret->dreg);
15139
15140         g_assert (cfg->cbb->code || first_bb->code);
15141         MonoInst *prev = ins->prev;
15142         mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
15143 }
15144
15145 void
15146 mono_decompose_typechecks (MonoCompile *cfg)
15147 {
15148         for (MonoBasicBlock *bb = cfg->bb_entry; bb; bb = bb->next_bb) {
15149                 MonoInst *ins;
15150                 MONO_BB_FOR_EACH_INS (bb, ins) {
15151                         switch (ins->opcode) {
15152                         case OP_ISINST:
15153                         case OP_CASTCLASS:
15154                                 mono_decompose_typecheck (cfg, bb, ins);
15155                                 break;
15156                         }
15157                 }
15158         }
15159 }
15160
15161
15162 /**
15163  * FIXME:
15164  * - use 'iadd' instead of 'int_add'
15165  * - handling ovf opcodes: decompose in method_to_ir.
15166  * - unify iregs/fregs
15167  *   -> partly done, the missing parts are:
15168  *   - a more complete unification would involve unifying the hregs as well, so
15169  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
15170  *     would no longer map to the machine hregs, so the code generators would need to
15171  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
15172  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
15173  *     fp/non-fp branches speeds it up by about 15%.
15174  * - use sext/zext opcodes instead of shifts
15175  * - add OP_ICALL
15176  * - get rid of TEMPLOADs if possible and use vregs instead
15177  * - clean up usage of OP_P/OP_ opcodes
15178  * - cleanup usage of DUMMY_USE
15179  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
15180  *   stack
15181  * - set the stack type and allocate a dreg in the EMIT_NEW macros
15182  * - get rid of all the <foo>2 stuff when the new JIT is ready.
15183  * - make sure handle_stack_args () is called before the branch is emitted
15184  * - when the new IR is done, get rid of all unused stuff
15185  * - COMPARE/BEQ as separate instructions or unify them ?
15186  *   - keeping them separate allows specialized compare instructions like
15187  *     compare_imm, compare_membase
15188  *   - most back ends unify fp compare+branch, fp compare+ceq
15189  * - integrate mono_save_args into inline_method
15190  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
15191  * - handle long shift opts on 32 bit platforms somehow: they require 
15192  *   3 sregs (2 for arg1 and 1 for arg2)
15193  * - make byref a 'normal' type.
15194  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
15195  *   variable if needed.
15196  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
15197  *   like inline_method.
15198  * - remove inlining restrictions
15199  * - fix LNEG and enable cfold of INEG
15200  * - generalize x86 optimizations like ldelema as a peephole optimization
15201  * - add store_mem_imm for amd64
15202  * - optimize the loading of the interruption flag in the managed->native wrappers
15203  * - avoid special handling of OP_NOP in passes
15204  * - move code inserting instructions into one function/macro.
15205  * - try a coalescing phase after liveness analysis
15206  * - add float -> vreg conversion + local optimizations on !x86
15207  * - figure out how to handle decomposed branches during optimizations, ie.
15208  *   compare+branch, op_jump_table+op_br etc.
15209  * - promote RuntimeXHandles to vregs
15210  * - vtype cleanups:
15211  *   - add a NEW_VARLOADA_VREG macro
15212  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
15213  *   accessing vtype fields.
15214  * - get rid of I8CONST on 64 bit platforms
15215  * - dealing with the increase in code size due to branches created during opcode
15216  *   decomposition:
15217  *   - use extended basic blocks
15218  *     - all parts of the JIT
15219  *     - handle_global_vregs () && local regalloc
15220  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
15221  * - sources of increase in code size:
15222  *   - vtypes
15223  *   - long compares
15224  *   - isinst and castclass
15225  *   - lvregs not allocated to global registers even if used multiple times
15226  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
15227  *   meaningful.
15228  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
15229  * - add all micro optimizations from the old JIT
15230  * - put tree optimizations into the deadce pass
15231  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
15232  *   specific function.
15233  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
15234  *   fcompare + branchCC.
15235  * - create a helper function for allocating a stack slot, taking into account 
15236  *   MONO_CFG_HAS_SPILLUP.
15237  * - merge r68207.
15238  * - merge the ia64 switch changes.
15239  * - optimize mono_regstate2_alloc_int/float.
15240  * - fix the pessimistic handling of variables accessed in exception handler blocks.
15241  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
15242  *   parts of the tree could be separated by other instructions, killing the tree
15243  *   arguments, or stores killing loads etc. Also, should we fold loads into other
15244  *   instructions if the result of the load is used multiple times ?
15245  * - make the REM_IMM optimization in mini-x86.c arch-independent.
15246  * - LAST MERGE: 108395.
15247  * - when returning vtypes in registers, generate IR and append it to the end of the
15248  *   last bb instead of doing it in the epilog.
15249  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
15250  */
15251
15252 /*
15253
15254 NOTES
15255 -----
15256
15257 - When to decompose opcodes:
15258   - earlier: this makes some optimizations hard to implement, since the low level IR
15259   no longer contains the neccessary information. But it is easier to do.
15260   - later: harder to implement, enables more optimizations.
15261 - Branches inside bblocks:
15262   - created when decomposing complex opcodes. 
15263     - branches to another bblock: harmless, but not tracked by the branch 
15264       optimizations, so need to branch to a label at the start of the bblock.
15265     - branches to inside the same bblock: very problematic, trips up the local
15266       reg allocator. Can be fixed by spitting the current bblock, but that is a
15267       complex operation, since some local vregs can become global vregs etc.
15268 - Local/global vregs:
15269   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
15270     local register allocator.
15271   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
15272     structure, created by mono_create_var (). Assigned to hregs or the stack by
15273     the global register allocator.
15274 - When to do optimizations like alu->alu_imm:
15275   - earlier -> saves work later on since the IR will be smaller/simpler
15276   - later -> can work on more instructions
15277 - Handling of valuetypes:
15278   - When a vtype is pushed on the stack, a new temporary is created, an 
15279     instruction computing its address (LDADDR) is emitted and pushed on
15280     the stack. Need to optimize cases when the vtype is used immediately as in
15281     argument passing, stloc etc.
15282 - Instead of the to_end stuff in the old JIT, simply call the function handling
15283   the values on the stack before emitting the last instruction of the bb.
15284 */
15285
15286 #endif /* DISABLE_JIT */