Merge pull request #3066 from alexanderkyte/pedump_sgen
[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
68 #include "trace.h"
69
70 #include "ir-emit.h"
71
72 #include "jit-icalls.h"
73 #include "jit.h"
74 #include "debugger-agent.h"
75 #include "seq-points.h"
76 #include "aot-compiler.h"
77 #include "mini-llvm.h"
78
79 #define BRANCH_COST 10
80 #define INLINE_LENGTH_LIMIT 20
81
82 /* These have 'cfg' as an implicit argument */
83 #define INLINE_FAILURE(msg) do {                                                                        \
84         if ((cfg->method != cfg->current_method) && (cfg->current_method->wrapper_type == MONO_WRAPPER_NONE)) { \
85                 inline_failure (cfg, msg);                                                                              \
86                 goto exception_exit;                                                                                    \
87         } \
88         } while (0)
89 #define CHECK_CFG_EXCEPTION do {\
90                 if (cfg->exception_type != MONO_EXCEPTION_NONE) \
91                         goto exception_exit;                                            \
92         } while (0)
93 #define FIELD_ACCESS_FAILURE(method, field) do {                                        \
94                 field_access_failure ((cfg), (method), (field));                        \
95                 goto exception_exit;    \
96         } while (0)
97 #define GENERIC_SHARING_FAILURE(opcode) do {            \
98                 if (cfg->gshared) {                                                                     \
99                         gshared_failure (cfg, opcode, __FILE__, __LINE__);      \
100                         goto exception_exit;    \
101                 }                       \
102         } while (0)
103 #define GSHAREDVT_FAILURE(opcode) do {          \
104         if (cfg->gsharedvt) {                                                                                           \
105                 gsharedvt_failure (cfg, opcode, __FILE__, __LINE__);                    \
106                 goto exception_exit;                                                                                    \
107         }                                                                                                                                       \
108         } while (0)
109 #define OUT_OF_MEMORY_FAILURE do {      \
110                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);                \
111                 mono_error_set_out_of_memory (&cfg->error, "");                                 \
112                 goto exception_exit;    \
113         } while (0)
114 #define DISABLE_AOT(cfg) do { \
115                 if ((cfg)->verbose_level >= 2)                                            \
116                         printf ("AOT disabled: %s:%d\n", __FILE__, __LINE__);   \
117                 (cfg)->disable_aot = TRUE;                                                        \
118         } while (0)
119 #define LOAD_ERROR do { \
120                 break_on_unverified ();                                                         \
121                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD); \
122                 goto exception_exit;                                                                    \
123         } while (0)
124
125 #define TYPE_LOAD_ERROR(klass) do { \
126                 cfg->exception_ptr = klass; \
127                 LOAD_ERROR;                                     \
128         } while (0)
129
130 #define CHECK_CFG_ERROR do {\
131                 if (!mono_error_ok (&cfg->error)) { \
132                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);        \
133                         goto mono_error_exit; \
134                 } \
135         } while (0)
136
137 /* Determine whenever 'ins' represents a load of the 'this' argument */
138 #define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && ((ins)->opcode == OP_MOVE) && ((ins)->sreg1 == cfg->args [0]->dreg))
139
140 static int ldind_to_load_membase (int opcode);
141 static int stind_to_store_membase (int opcode);
142
143 int mono_op_to_op_imm (int opcode);
144 int mono_op_to_op_imm_noemul (int opcode);
145
146 MONO_API MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
147
148 static int inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
149                                                   guchar *ip, guint real_offset, gboolean inline_always);
150 static MonoInst*
151 emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used, MonoInst **sp);
152
153 /* helper methods signatures */
154 static MonoMethodSignature *helper_sig_domain_get;
155 static MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline;
156 static MonoMethodSignature *helper_sig_llvmonly_imt_thunk;
157
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_thunk = 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 GList*
664 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
665 {
666         MonoMethodHeader *header = cfg->header;
667         MonoExceptionClause *clause;
668         int i;
669         GList *res = NULL;
670
671         for (i = 0; i < header->num_clauses; ++i) {
672                 clause = &header->clauses [i];
673                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
674                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
675                         if (clause->flags == type)
676                                 res = g_list_append (res, clause);
677                 }
678         }
679         return res;
680 }
681
682 static void
683 mono_create_spvar_for_region (MonoCompile *cfg, int region)
684 {
685         MonoInst *var;
686
687         var = (MonoInst *)g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
688         if (var)
689                 return;
690
691         var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
692         /* prevent it from being register allocated */
693         var->flags |= MONO_INST_VOLATILE;
694
695         g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
696 }
697
698 MonoInst *
699 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
700 {
701         return (MonoInst *)g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
702 }
703
704 static MonoInst*
705 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
706 {
707         MonoInst *var;
708
709         var = (MonoInst *)g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
710         if (var)
711                 return var;
712
713         var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
714         /* prevent it from being register allocated */
715         var->flags |= MONO_INST_VOLATILE;
716
717         g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
718
719         return var;
720 }
721
722 /*
723  * Returns the type used in the eval stack when @type is loaded.
724  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
725  */
726 void
727 type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
728 {
729         MonoClass *klass;
730
731         type = mini_get_underlying_type (type);
732         inst->klass = klass = mono_class_from_mono_type (type);
733         if (type->byref) {
734                 inst->type = STACK_MP;
735                 return;
736         }
737
738 handle_enum:
739         switch (type->type) {
740         case MONO_TYPE_VOID:
741                 inst->type = STACK_INV;
742                 return;
743         case MONO_TYPE_I1:
744         case MONO_TYPE_U1:
745         case MONO_TYPE_I2:
746         case MONO_TYPE_U2:
747         case MONO_TYPE_I4:
748         case MONO_TYPE_U4:
749                 inst->type = STACK_I4;
750                 return;
751         case MONO_TYPE_I:
752         case MONO_TYPE_U:
753         case MONO_TYPE_PTR:
754         case MONO_TYPE_FNPTR:
755                 inst->type = STACK_PTR;
756                 return;
757         case MONO_TYPE_CLASS:
758         case MONO_TYPE_STRING:
759         case MONO_TYPE_OBJECT:
760         case MONO_TYPE_SZARRAY:
761         case MONO_TYPE_ARRAY:    
762                 inst->type = STACK_OBJ;
763                 return;
764         case MONO_TYPE_I8:
765         case MONO_TYPE_U8:
766                 inst->type = STACK_I8;
767                 return;
768         case MONO_TYPE_R4:
769                 inst->type = cfg->r4_stack_type;
770                 break;
771         case MONO_TYPE_R8:
772                 inst->type = STACK_R8;
773                 return;
774         case MONO_TYPE_VALUETYPE:
775                 if (type->data.klass->enumtype) {
776                         type = mono_class_enum_basetype (type->data.klass);
777                         goto handle_enum;
778                 } else {
779                         inst->klass = klass;
780                         inst->type = STACK_VTYPE;
781                         return;
782                 }
783         case MONO_TYPE_TYPEDBYREF:
784                 inst->klass = mono_defaults.typed_reference_class;
785                 inst->type = STACK_VTYPE;
786                 return;
787         case MONO_TYPE_GENERICINST:
788                 type = &type->data.generic_class->container_class->byval_arg;
789                 goto handle_enum;
790         case MONO_TYPE_VAR:
791         case MONO_TYPE_MVAR:
792                 g_assert (cfg->gshared);
793                 if (mini_is_gsharedvt_type (type)) {
794                         g_assert (cfg->gsharedvt);
795                         inst->type = STACK_VTYPE;
796                 } else {
797                         type_to_eval_stack_type (cfg, mini_get_underlying_type (type), inst);
798                 }
799                 return;
800         default:
801                 g_error ("unknown type 0x%02x in eval stack type", type->type);
802         }
803 }
804
805 /*
806  * The following tables are used to quickly validate the IL code in type_from_op ().
807  */
808 static const char
809 bin_num_table [STACK_MAX] [STACK_MAX] = {
810         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
811         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
812         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
813         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
814         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV, STACK_R8},
815         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
816         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
817         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
818         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4}
819 };
820
821 static const char 
822 neg_table [] = {
823         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4
824 };
825
826 /* reduce the size of this table */
827 static const char
828 bin_int_table [STACK_MAX] [STACK_MAX] = {
829         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
830         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
831         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
832         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
833         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, 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_INV, STACK_INV, STACK_INV, STACK_INV}
837 };
838
839 static const char
840 bin_comp_table [STACK_MAX] [STACK_MAX] = {
841 /*      Inv i  L  p  F  &  O  vt r4 */
842         {0},
843         {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
844         {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
845         {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
846         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* F, R8 */
847         {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
848         {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
849         {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
850         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* r, r4 */
851 };
852
853 /* reduce the size of this table */
854 static const char
855 shift_table [STACK_MAX] [STACK_MAX] = {
856         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
857         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
858         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
859         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
860         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
861         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
862         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
863         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
864 };
865
866 /*
867  * Tables to map from the non-specific opcode to the matching
868  * type-specific opcode.
869  */
870 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
871 static const guint16
872 binops_op_map [STACK_MAX] = {
873         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
874 };
875
876 /* handles from CEE_NEG to CEE_CONV_U8 */
877 static const guint16
878 unops_op_map [STACK_MAX] = {
879         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
880 };
881
882 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
883 static const guint16
884 ovfops_op_map [STACK_MAX] = {
885         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
886 };
887
888 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
889 static const guint16
890 ovf2ops_op_map [STACK_MAX] = {
891         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
892 };
893
894 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
895 static const guint16
896 ovf3ops_op_map [STACK_MAX] = {
897         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
898 };
899
900 /* handles from CEE_BEQ to CEE_BLT_UN */
901 static const guint16
902 beqops_op_map [STACK_MAX] = {
903         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
904 };
905
906 /* handles from CEE_CEQ to CEE_CLT_UN */
907 static const guint16
908 ceqops_op_map [STACK_MAX] = {
909         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
910 };
911
912 /*
913  * Sets ins->type (the type on the eval stack) according to the
914  * type of the opcode and the arguments to it.
915  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
916  *
917  * FIXME: this function sets ins->type unconditionally in some cases, but
918  * it should set it to invalid for some types (a conv.x on an object)
919  */
920 static void
921 type_from_op (MonoCompile *cfg, MonoInst *ins, MonoInst *src1, MonoInst *src2)
922 {
923         switch (ins->opcode) {
924         /* binops */
925         case CEE_ADD:
926         case CEE_SUB:
927         case CEE_MUL:
928         case CEE_DIV:
929         case CEE_REM:
930                 /* FIXME: check unverifiable args for STACK_MP */
931                 ins->type = bin_num_table [src1->type] [src2->type];
932                 ins->opcode += binops_op_map [ins->type];
933                 break;
934         case CEE_DIV_UN:
935         case CEE_REM_UN:
936         case CEE_AND:
937         case CEE_OR:
938         case CEE_XOR:
939                 ins->type = bin_int_table [src1->type] [src2->type];
940                 ins->opcode += binops_op_map [ins->type];
941                 break;
942         case CEE_SHL:
943         case CEE_SHR:
944         case CEE_SHR_UN:
945                 ins->type = shift_table [src1->type] [src2->type];
946                 ins->opcode += binops_op_map [ins->type];
947                 break;
948         case OP_COMPARE:
949         case OP_LCOMPARE:
950         case OP_ICOMPARE:
951                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
952                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
953                         ins->opcode = OP_LCOMPARE;
954                 else if (src1->type == STACK_R4)
955                         ins->opcode = OP_RCOMPARE;
956                 else if (src1->type == STACK_R8)
957                         ins->opcode = OP_FCOMPARE;
958                 else
959                         ins->opcode = OP_ICOMPARE;
960                 break;
961         case OP_ICOMPARE_IMM:
962                 ins->type = bin_comp_table [src1->type] [src1->type] ? STACK_I4 : STACK_INV;
963                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
964                         ins->opcode = OP_LCOMPARE_IMM;          
965                 break;
966         case CEE_BEQ:
967         case CEE_BGE:
968         case CEE_BGT:
969         case CEE_BLE:
970         case CEE_BLT:
971         case CEE_BNE_UN:
972         case CEE_BGE_UN:
973         case CEE_BGT_UN:
974         case CEE_BLE_UN:
975         case CEE_BLT_UN:
976                 ins->opcode += beqops_op_map [src1->type];
977                 break;
978         case OP_CEQ:
979                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
980                 ins->opcode += ceqops_op_map [src1->type];
981                 break;
982         case OP_CGT:
983         case OP_CGT_UN:
984         case OP_CLT:
985         case OP_CLT_UN:
986                 ins->type = (bin_comp_table [src1->type] [src2->type] & 1) ? STACK_I4: STACK_INV;
987                 ins->opcode += ceqops_op_map [src1->type];
988                 break;
989         /* unops */
990         case CEE_NEG:
991                 ins->type = neg_table [src1->type];
992                 ins->opcode += unops_op_map [ins->type];
993                 break;
994         case CEE_NOT:
995                 if (src1->type >= STACK_I4 && src1->type <= STACK_PTR)
996                         ins->type = src1->type;
997                 else
998                         ins->type = STACK_INV;
999                 ins->opcode += unops_op_map [ins->type];
1000                 break;
1001         case CEE_CONV_I1:
1002         case CEE_CONV_I2:
1003         case CEE_CONV_I4:
1004         case CEE_CONV_U4:
1005                 ins->type = STACK_I4;
1006                 ins->opcode += unops_op_map [src1->type];
1007                 break;
1008         case CEE_CONV_R_UN:
1009                 ins->type = STACK_R8;
1010                 switch (src1->type) {
1011                 case STACK_I4:
1012                 case STACK_PTR:
1013                         ins->opcode = OP_ICONV_TO_R_UN;
1014                         break;
1015                 case STACK_I8:
1016                         ins->opcode = OP_LCONV_TO_R_UN; 
1017                         break;
1018                 }
1019                 break;
1020         case CEE_CONV_OVF_I1:
1021         case CEE_CONV_OVF_U1:
1022         case CEE_CONV_OVF_I2:
1023         case CEE_CONV_OVF_U2:
1024         case CEE_CONV_OVF_I4:
1025         case CEE_CONV_OVF_U4:
1026                 ins->type = STACK_I4;
1027                 ins->opcode += ovf3ops_op_map [src1->type];
1028                 break;
1029         case CEE_CONV_OVF_I_UN:
1030         case CEE_CONV_OVF_U_UN:
1031                 ins->type = STACK_PTR;
1032                 ins->opcode += ovf2ops_op_map [src1->type];
1033                 break;
1034         case CEE_CONV_OVF_I1_UN:
1035         case CEE_CONV_OVF_I2_UN:
1036         case CEE_CONV_OVF_I4_UN:
1037         case CEE_CONV_OVF_U1_UN:
1038         case CEE_CONV_OVF_U2_UN:
1039         case CEE_CONV_OVF_U4_UN:
1040                 ins->type = STACK_I4;
1041                 ins->opcode += ovf2ops_op_map [src1->type];
1042                 break;
1043         case CEE_CONV_U:
1044                 ins->type = STACK_PTR;
1045                 switch (src1->type) {
1046                 case STACK_I4:
1047                         ins->opcode = OP_ICONV_TO_U;
1048                         break;
1049                 case STACK_PTR:
1050                 case STACK_MP:
1051 #if SIZEOF_VOID_P == 8
1052                         ins->opcode = OP_LCONV_TO_U;
1053 #else
1054                         ins->opcode = OP_MOVE;
1055 #endif
1056                         break;
1057                 case STACK_I8:
1058                         ins->opcode = OP_LCONV_TO_U;
1059                         break;
1060                 case STACK_R8:
1061                         ins->opcode = OP_FCONV_TO_U;
1062                         break;
1063                 }
1064                 break;
1065         case CEE_CONV_I8:
1066         case CEE_CONV_U8:
1067                 ins->type = STACK_I8;
1068                 ins->opcode += unops_op_map [src1->type];
1069                 break;
1070         case CEE_CONV_OVF_I8:
1071         case CEE_CONV_OVF_U8:
1072                 ins->type = STACK_I8;
1073                 ins->opcode += ovf3ops_op_map [src1->type];
1074                 break;
1075         case CEE_CONV_OVF_U8_UN:
1076         case CEE_CONV_OVF_I8_UN:
1077                 ins->type = STACK_I8;
1078                 ins->opcode += ovf2ops_op_map [src1->type];
1079                 break;
1080         case CEE_CONV_R4:
1081                 ins->type = cfg->r4_stack_type;
1082                 ins->opcode += unops_op_map [src1->type];
1083                 break;
1084         case CEE_CONV_R8:
1085                 ins->type = STACK_R8;
1086                 ins->opcode += unops_op_map [src1->type];
1087                 break;
1088         case OP_CKFINITE:
1089                 ins->type = STACK_R8;           
1090                 break;
1091         case CEE_CONV_U2:
1092         case CEE_CONV_U1:
1093                 ins->type = STACK_I4;
1094                 ins->opcode += ovfops_op_map [src1->type];
1095                 break;
1096         case CEE_CONV_I:
1097         case CEE_CONV_OVF_I:
1098         case CEE_CONV_OVF_U:
1099                 ins->type = STACK_PTR;
1100                 ins->opcode += ovfops_op_map [src1->type];
1101                 break;
1102         case CEE_ADD_OVF:
1103         case CEE_ADD_OVF_UN:
1104         case CEE_MUL_OVF:
1105         case CEE_MUL_OVF_UN:
1106         case CEE_SUB_OVF:
1107         case CEE_SUB_OVF_UN:
1108                 ins->type = bin_num_table [src1->type] [src2->type];
1109                 ins->opcode += ovfops_op_map [src1->type];
1110                 if (ins->type == STACK_R8)
1111                         ins->type = STACK_INV;
1112                 break;
1113         case OP_LOAD_MEMBASE:
1114                 ins->type = STACK_PTR;
1115                 break;
1116         case OP_LOADI1_MEMBASE:
1117         case OP_LOADU1_MEMBASE:
1118         case OP_LOADI2_MEMBASE:
1119         case OP_LOADU2_MEMBASE:
1120         case OP_LOADI4_MEMBASE:
1121         case OP_LOADU4_MEMBASE:
1122                 ins->type = STACK_PTR;
1123                 break;
1124         case OP_LOADI8_MEMBASE:
1125                 ins->type = STACK_I8;
1126                 break;
1127         case OP_LOADR4_MEMBASE:
1128                 ins->type = cfg->r4_stack_type;
1129                 break;
1130         case OP_LOADR8_MEMBASE:
1131                 ins->type = STACK_R8;
1132                 break;
1133         default:
1134                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1135                 break;
1136         }
1137
1138         if (ins->type == STACK_MP)
1139                 ins->klass = mono_defaults.object_class;
1140 }
1141
1142 static const char 
1143 ldind_type [] = {
1144         STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
1145 };
1146
1147 #if 0
1148
1149 static const char
1150 param_table [STACK_MAX] [STACK_MAX] = {
1151         {0},
1152 };
1153
1154 static int
1155 check_values_to_signature (MonoInst *args, MonoType *this_ins, MonoMethodSignature *sig)
1156 {
1157         int i;
1158
1159         if (sig->hasthis) {
1160                 switch (args->type) {
1161                 case STACK_I4:
1162                 case STACK_I8:
1163                 case STACK_R8:
1164                 case STACK_VTYPE:
1165                 case STACK_INV:
1166                         return 0;
1167                 }
1168                 args++;
1169         }
1170         for (i = 0; i < sig->param_count; ++i) {
1171                 switch (args [i].type) {
1172                 case STACK_INV:
1173                         return 0;
1174                 case STACK_MP:
1175                         if (!sig->params [i]->byref)
1176                                 return 0;
1177                         continue;
1178                 case STACK_OBJ:
1179                         if (sig->params [i]->byref)
1180                                 return 0;
1181                         switch (sig->params [i]->type) {
1182                         case MONO_TYPE_CLASS:
1183                         case MONO_TYPE_STRING:
1184                         case MONO_TYPE_OBJECT:
1185                         case MONO_TYPE_SZARRAY:
1186                         case MONO_TYPE_ARRAY:
1187                                 break;
1188                         default:
1189                                 return 0;
1190                         }
1191                         continue;
1192                 case STACK_R8:
1193                         if (sig->params [i]->byref)
1194                                 return 0;
1195                         if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1196                                 return 0;
1197                         continue;
1198                 case STACK_PTR:
1199                 case STACK_I4:
1200                 case STACK_I8:
1201                 case STACK_VTYPE:
1202                         break;
1203                 }
1204                 /*if (!param_table [args [i].type] [sig->params [i]->type])
1205                         return 0;*/
1206         }
1207         return 1;
1208 }
1209 #endif
1210
1211 /*
1212  * When we need a pointer to the current domain many times in a method, we
1213  * call mono_domain_get() once and we store the result in a local variable.
1214  * This function returns the variable that represents the MonoDomain*.
1215  */
1216 inline static MonoInst *
1217 mono_get_domainvar (MonoCompile *cfg)
1218 {
1219         if (!cfg->domainvar)
1220                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1221         return cfg->domainvar;
1222 }
1223
1224 /*
1225  * The got_var contains the address of the Global Offset Table when AOT 
1226  * compiling.
1227  */
1228 MonoInst *
1229 mono_get_got_var (MonoCompile *cfg)
1230 {
1231         if (!cfg->compile_aot || !cfg->backend->need_got_var)
1232                 return NULL;
1233         if (!cfg->got_var) {
1234                 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1235         }
1236         return cfg->got_var;
1237 }
1238
1239 static MonoInst *
1240 mono_get_vtable_var (MonoCompile *cfg)
1241 {
1242         g_assert (cfg->gshared);
1243
1244         if (!cfg->rgctx_var) {
1245                 cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1246                 /* force the var to be stack allocated */
1247                 cfg->rgctx_var->flags |= MONO_INST_VOLATILE;
1248         }
1249
1250         return cfg->rgctx_var;
1251 }
1252
1253 static MonoType*
1254 type_from_stack_type (MonoInst *ins) {
1255         switch (ins->type) {
1256         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1257         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1258         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1259         case STACK_R4: return &mono_defaults.single_class->byval_arg;
1260         case STACK_R8: return &mono_defaults.double_class->byval_arg;
1261         case STACK_MP:
1262                 return &ins->klass->this_arg;
1263         case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1264         case STACK_VTYPE: return &ins->klass->byval_arg;
1265         default:
1266                 g_error ("stack type %d to monotype not handled\n", ins->type);
1267         }
1268         return NULL;
1269 }
1270
1271 static G_GNUC_UNUSED int
1272 type_to_stack_type (MonoCompile *cfg, MonoType *t)
1273 {
1274         t = mono_type_get_underlying_type (t);
1275         switch (t->type) {
1276         case MONO_TYPE_I1:
1277         case MONO_TYPE_U1:
1278         case MONO_TYPE_I2:
1279         case MONO_TYPE_U2:
1280         case MONO_TYPE_I4:
1281         case MONO_TYPE_U4:
1282                 return STACK_I4;
1283         case MONO_TYPE_I:
1284         case MONO_TYPE_U:
1285         case MONO_TYPE_PTR:
1286         case MONO_TYPE_FNPTR:
1287                 return STACK_PTR;
1288         case MONO_TYPE_CLASS:
1289         case MONO_TYPE_STRING:
1290         case MONO_TYPE_OBJECT:
1291         case MONO_TYPE_SZARRAY:
1292         case MONO_TYPE_ARRAY:    
1293                 return STACK_OBJ;
1294         case MONO_TYPE_I8:
1295         case MONO_TYPE_U8:
1296                 return STACK_I8;
1297         case MONO_TYPE_R4:
1298                 return cfg->r4_stack_type;
1299         case MONO_TYPE_R8:
1300                 return STACK_R8;
1301         case MONO_TYPE_VALUETYPE:
1302         case MONO_TYPE_TYPEDBYREF:
1303                 return STACK_VTYPE;
1304         case MONO_TYPE_GENERICINST:
1305                 if (mono_type_generic_inst_is_valuetype (t))
1306                         return STACK_VTYPE;
1307                 else
1308                         return STACK_OBJ;
1309                 break;
1310         default:
1311                 g_assert_not_reached ();
1312         }
1313
1314         return -1;
1315 }
1316
1317 static MonoClass*
1318 array_access_to_klass (int opcode)
1319 {
1320         switch (opcode) {
1321         case CEE_LDELEM_U1:
1322                 return mono_defaults.byte_class;
1323         case CEE_LDELEM_U2:
1324                 return mono_defaults.uint16_class;
1325         case CEE_LDELEM_I:
1326         case CEE_STELEM_I:
1327                 return mono_defaults.int_class;
1328         case CEE_LDELEM_I1:
1329         case CEE_STELEM_I1:
1330                 return mono_defaults.sbyte_class;
1331         case CEE_LDELEM_I2:
1332         case CEE_STELEM_I2:
1333                 return mono_defaults.int16_class;
1334         case CEE_LDELEM_I4:
1335         case CEE_STELEM_I4:
1336                 return mono_defaults.int32_class;
1337         case CEE_LDELEM_U4:
1338                 return mono_defaults.uint32_class;
1339         case CEE_LDELEM_I8:
1340         case CEE_STELEM_I8:
1341                 return mono_defaults.int64_class;
1342         case CEE_LDELEM_R4:
1343         case CEE_STELEM_R4:
1344                 return mono_defaults.single_class;
1345         case CEE_LDELEM_R8:
1346         case CEE_STELEM_R8:
1347                 return mono_defaults.double_class;
1348         case CEE_LDELEM_REF:
1349         case CEE_STELEM_REF:
1350                 return mono_defaults.object_class;
1351         default:
1352                 g_assert_not_reached ();
1353         }
1354         return NULL;
1355 }
1356
1357 /*
1358  * We try to share variables when possible
1359  */
1360 static MonoInst *
1361 mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
1362 {
1363         MonoInst *res;
1364         int pos, vnum;
1365
1366         /* inlining can result in deeper stacks */ 
1367         if (slot >= cfg->header->max_stack)
1368                 return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1369
1370         pos = ins->type - 1 + slot * STACK_MAX;
1371
1372         switch (ins->type) {
1373         case STACK_I4:
1374         case STACK_I8:
1375         case STACK_R8:
1376         case STACK_PTR:
1377         case STACK_MP:
1378         case STACK_OBJ:
1379                 if ((vnum = cfg->intvars [pos]))
1380                         return cfg->varinfo [vnum];
1381                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1382                 cfg->intvars [pos] = res->inst_c0;
1383                 break;
1384         default:
1385                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1386         }
1387         return res;
1388 }
1389
1390 static void
1391 mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
1392 {
1393         /* 
1394          * Don't use this if a generic_context is set, since that means AOT can't
1395          * look up the method using just the image+token.
1396          * table == 0 means this is a reference made from a wrapper.
1397          */
1398         if (cfg->compile_aot && !cfg->generic_context && (mono_metadata_token_table (token) > 0)) {
1399                 MonoJumpInfoToken *jump_info_token = (MonoJumpInfoToken *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
1400                 jump_info_token->image = image;
1401                 jump_info_token->token = token;
1402                 g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
1403         }
1404 }
1405
1406 /*
1407  * This function is called to handle items that are left on the evaluation stack
1408  * at basic block boundaries. What happens is that we save the values to local variables
1409  * and we reload them later when first entering the target basic block (with the
1410  * handle_loaded_temps () function).
1411  * A single joint point will use the same variables (stored in the array bb->out_stack or
1412  * bb->in_stack, if the basic block is before or after the joint point).
1413  *
1414  * This function needs to be called _before_ emitting the last instruction of
1415  * the bb (i.e. before emitting a branch).
1416  * If the stack merge fails at a join point, cfg->unverifiable is set.
1417  */
1418 static void
1419 handle_stack_args (MonoCompile *cfg, MonoInst **sp, int count)
1420 {
1421         int i, bindex;
1422         MonoBasicBlock *bb = cfg->cbb;
1423         MonoBasicBlock *outb;
1424         MonoInst *inst, **locals;
1425         gboolean found;
1426
1427         if (!count)
1428                 return;
1429         if (cfg->verbose_level > 3)
1430                 printf ("%d item(s) on exit from B%d\n", count, bb->block_num);
1431         if (!bb->out_scount) {
1432                 bb->out_scount = count;
1433                 //printf ("bblock %d has out:", bb->block_num);
1434                 found = FALSE;
1435                 for (i = 0; i < bb->out_count; ++i) {
1436                         outb = bb->out_bb [i];
1437                         /* exception handlers are linked, but they should not be considered for stack args */
1438                         if (outb->flags & BB_EXCEPTION_HANDLER)
1439                                 continue;
1440                         //printf (" %d", outb->block_num);
1441                         if (outb->in_stack) {
1442                                 found = TRUE;
1443                                 bb->out_stack = outb->in_stack;
1444                                 break;
1445                         }
1446                 }
1447                 //printf ("\n");
1448                 if (!found) {
1449                         bb->out_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1450                         for (i = 0; i < count; ++i) {
1451                                 /* 
1452                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
1453                                  * stack slot and if they are of the same type.
1454                                  * This won't cause conflicts since if 'local' is used to 
1455                                  * store one of the values in the in_stack of a bblock, then
1456                                  * the same variable will be used for the same outgoing stack 
1457                                  * slot as well. 
1458                                  * This doesn't work when inlining methods, since the bblocks
1459                                  * in the inlined methods do not inherit their in_stack from
1460                                  * the bblock they are inlined to. See bug #58863 for an
1461                                  * example.
1462                                  */
1463                                 if (cfg->inlined_method)
1464                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1465                                 else
1466                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
1467                         }
1468                 }
1469         }
1470
1471         for (i = 0; i < bb->out_count; ++i) {
1472                 outb = bb->out_bb [i];
1473                 /* exception handlers are linked, but they should not be considered for stack args */
1474                 if (outb->flags & BB_EXCEPTION_HANDLER)
1475                         continue;
1476                 if (outb->in_scount) {
1477                         if (outb->in_scount != bb->out_scount) {
1478                                 cfg->unverifiable = TRUE;
1479                                 return;
1480                         }
1481                         continue; /* check they are the same locals */
1482                 }
1483                 outb->in_scount = count;
1484                 outb->in_stack = bb->out_stack;
1485         }
1486
1487         locals = bb->out_stack;
1488         cfg->cbb = bb;
1489         for (i = 0; i < count; ++i) {
1490                 EMIT_NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
1491                 inst->cil_code = sp [i]->cil_code;
1492                 sp [i] = locals [i];
1493                 if (cfg->verbose_level > 3)
1494                         printf ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
1495         }
1496
1497         /*
1498          * It is possible that the out bblocks already have in_stack assigned, and
1499          * the in_stacks differ. In this case, we will store to all the different 
1500          * in_stacks.
1501          */
1502
1503         found = TRUE;
1504         bindex = 0;
1505         while (found) {
1506                 /* Find a bblock which has a different in_stack */
1507                 found = FALSE;
1508                 while (bindex < bb->out_count) {
1509                         outb = bb->out_bb [bindex];
1510                         /* exception handlers are linked, but they should not be considered for stack args */
1511                         if (outb->flags & BB_EXCEPTION_HANDLER) {
1512                                 bindex++;
1513                                 continue;
1514                         }
1515                         if (outb->in_stack != locals) {
1516                                 for (i = 0; i < count; ++i) {
1517                                         EMIT_NEW_TEMPSTORE (cfg, inst, outb->in_stack [i]->inst_c0, sp [i]);
1518                                         inst->cil_code = sp [i]->cil_code;
1519                                         sp [i] = locals [i];
1520                                         if (cfg->verbose_level > 3)
1521                                                 printf ("storing %d to temp %d\n", i, (int)outb->in_stack [i]->inst_c0);
1522                                 }
1523                                 locals = outb->in_stack;
1524                                 found = TRUE;
1525                                 break;
1526                         }
1527                         bindex ++;
1528                 }
1529         }
1530 }
1531
1532 static MonoInst*
1533 emit_runtime_constant (MonoCompile *cfg, MonoJumpInfoType patch_type, gpointer data)
1534 {
1535         MonoInst *ins;
1536
1537         if (cfg->compile_aot) {
1538                 EMIT_NEW_AOTCONST (cfg, ins, patch_type, data);
1539         } else {
1540                 MonoJumpInfo ji;
1541                 gpointer target;
1542                 MonoError error;
1543
1544                 ji.type = patch_type;
1545                 ji.data.target = data;
1546                 target = mono_resolve_patch_target (NULL, cfg->domain, NULL, &ji, FALSE, &error);
1547                 mono_error_assert_ok (&error);
1548
1549                 EMIT_NEW_PCONST (cfg, ins, target);
1550         }
1551         return ins;
1552 }
1553
1554 static void
1555 mini_emit_interface_bitmap_check (MonoCompile *cfg, int intf_bit_reg, int base_reg, int offset, MonoClass *klass)
1556 {
1557         int ibitmap_reg = alloc_preg (cfg);
1558 #ifdef COMPRESSED_INTERFACE_BITMAP
1559         MonoInst *args [2];
1560         MonoInst *res, *ins;
1561         NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, ibitmap_reg, base_reg, offset);
1562         MONO_ADD_INS (cfg->cbb, ins);
1563         args [0] = ins;
1564         args [1] = emit_runtime_constant (cfg, MONO_PATCH_INFO_IID, klass);
1565         res = mono_emit_jit_icall (cfg, mono_class_interface_match, args);
1566         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, intf_bit_reg, res->dreg);
1567 #else
1568         int ibitmap_byte_reg = alloc_preg (cfg);
1569
1570         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, base_reg, offset);
1571
1572         if (cfg->compile_aot) {
1573                 int iid_reg = alloc_preg (cfg);
1574                 int shifted_iid_reg = alloc_preg (cfg);
1575                 int ibitmap_byte_address_reg = alloc_preg (cfg);
1576                 int masked_iid_reg = alloc_preg (cfg);
1577                 int iid_one_bit_reg = alloc_preg (cfg);
1578                 int iid_bit_reg = alloc_preg (cfg);
1579                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1580                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, shifted_iid_reg, iid_reg, 3);
1581                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ibitmap_byte_address_reg, ibitmap_reg, shifted_iid_reg);
1582                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, ibitmap_byte_reg, ibitmap_byte_address_reg, 0);
1583                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, masked_iid_reg, iid_reg, 7);
1584                 MONO_EMIT_NEW_ICONST (cfg, iid_one_bit_reg, 1);
1585                 MONO_EMIT_NEW_BIALU (cfg, OP_ISHL, iid_bit_reg, iid_one_bit_reg, masked_iid_reg);
1586                 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, intf_bit_reg, ibitmap_byte_reg, iid_bit_reg);
1587         } else {
1588                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, klass->interface_id >> 3);
1589                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (klass->interface_id & 7));
1590         }
1591 #endif
1592 }
1593
1594 /* 
1595  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoClass
1596  * stored in "klass_reg" implements the interface "klass".
1597  */
1598 static void
1599 mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass_reg, MonoClass *klass)
1600 {
1601         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, interface_bitmap), klass);
1602 }
1603
1604 /* 
1605  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoVTable
1606  * stored in "vtable_reg" implements the interface "klass".
1607  */
1608 static void
1609 mini_emit_load_intf_bit_reg_vtable (MonoCompile *cfg, int intf_bit_reg, int vtable_reg, MonoClass *klass)
1610 {
1611         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, interface_bitmap), klass);
1612 }
1613
1614 /* 
1615  * Emit code which checks whenever the interface id of @klass is smaller than
1616  * than the value given by max_iid_reg.
1617 */
1618 static void
1619 mini_emit_max_iid_check (MonoCompile *cfg, int max_iid_reg, MonoClass *klass,
1620                                                  MonoBasicBlock *false_target)
1621 {
1622         if (cfg->compile_aot) {
1623                 int iid_reg = alloc_preg (cfg);
1624                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1625                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, max_iid_reg, iid_reg);
1626         }
1627         else
1628                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, max_iid_reg, klass->interface_id);
1629         if (false_target)
1630                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1631         else
1632                 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1633 }
1634
1635 /* Same as above, but obtains max_iid from a vtable */
1636 static void
1637 mini_emit_max_iid_check_vtable (MonoCompile *cfg, int vtable_reg, MonoClass *klass,
1638                                                                  MonoBasicBlock *false_target)
1639 {
1640         int max_iid_reg = alloc_preg (cfg);
1641                 
1642         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, max_interface_id));
1643         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1644 }
1645
1646 /* Same as above, but obtains max_iid from a klass */
1647 static void
1648 mini_emit_max_iid_check_class (MonoCompile *cfg, int klass_reg, MonoClass *klass,
1649                                                                  MonoBasicBlock *false_target)
1650 {
1651         int max_iid_reg = alloc_preg (cfg);
1652
1653         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, max_interface_id));
1654         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1655 }
1656
1657 static void
1658 mini_emit_isninst_cast_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_ins, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1659 {
1660         int idepth_reg = alloc_preg (cfg);
1661         int stypes_reg = alloc_preg (cfg);
1662         int stype = alloc_preg (cfg);
1663
1664         mono_class_setup_supertypes (klass);
1665
1666         if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1667                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1668                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1669                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1670         }
1671         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1672         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1673         if (klass_ins) {
1674                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, klass_ins->dreg);
1675         } else if (cfg->compile_aot) {
1676                 int const_reg = alloc_preg (cfg);
1677                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1678                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, const_reg);
1679         } else {
1680                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, stype, klass);
1681         }
1682         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, true_target);
1683 }
1684
1685 static void
1686 mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1687 {
1688         mini_emit_isninst_cast_inst (cfg, klass_reg, klass, NULL, false_target, true_target);
1689 }
1690
1691 static void
1692 mini_emit_iface_cast (MonoCompile *cfg, int vtable_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1693 {
1694         int intf_reg = alloc_preg (cfg);
1695
1696         mini_emit_max_iid_check_vtable (cfg, vtable_reg, klass, false_target);
1697         mini_emit_load_intf_bit_reg_vtable (cfg, intf_reg, vtable_reg, klass);
1698         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_reg, 0);
1699         if (true_target)
1700                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1701         else
1702                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");               
1703 }
1704
1705 /*
1706  * Variant of the above that takes a register to the class, not the vtable.
1707  */
1708 static void
1709 mini_emit_iface_class_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1710 {
1711         int intf_bit_reg = alloc_preg (cfg);
1712
1713         mini_emit_max_iid_check_class (cfg, klass_reg, klass, false_target);
1714         mini_emit_load_intf_bit_reg_class (cfg, intf_bit_reg, klass_reg, klass);
1715         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_bit_reg, 0);
1716         if (true_target)
1717                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1718         else
1719                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
1720 }
1721
1722 static inline void
1723 mini_emit_class_check_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_inst)
1724 {
1725         if (klass_inst) {
1726                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_inst->dreg);
1727         } else {
1728                 MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
1729                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, ins->dreg);
1730         }
1731         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1732 }
1733
1734 static inline void
1735 mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass)
1736 {
1737         mini_emit_class_check_inst (cfg, klass_reg, klass, NULL);
1738 }
1739
1740 static inline void
1741 mini_emit_class_check_branch (MonoCompile *cfg, int klass_reg, MonoClass *klass, int branch_op, MonoBasicBlock *target)
1742 {
1743         if (cfg->compile_aot) {
1744                 int const_reg = alloc_preg (cfg);
1745                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1746                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1747         } else {
1748                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1749         }
1750         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, branch_op, target);
1751 }
1752
1753 static void
1754 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null);
1755         
1756 static void
1757 mini_emit_castclass_inst (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoInst *klass_inst, MonoBasicBlock *object_is_null)
1758 {
1759         if (klass->rank) {
1760                 int rank_reg = alloc_preg (cfg);
1761                 int eclass_reg = alloc_preg (cfg);
1762
1763                 g_assert (!klass_inst);
1764                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, rank));
1765                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
1766                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1767                 //              MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
1768                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
1769                 if (klass->cast_class == mono_defaults.object_class) {
1770                         int parent_reg = alloc_preg (cfg);
1771                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
1772                         mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, object_is_null);
1773                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1774                 } else if (klass->cast_class == mono_defaults.enum_class->parent) {
1775                         mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, object_is_null);
1776                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1777                 } else if (klass->cast_class == mono_defaults.enum_class) {
1778                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1779                 } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1780                         mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, NULL, NULL);
1781                 } else {
1782                         // Pass -1 as obj_reg to skip the check below for arrays of arrays
1783                         mini_emit_castclass (cfg, -1, eclass_reg, klass->cast_class, object_is_null);
1784                 }
1785
1786                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY) && (obj_reg != -1)) {
1787                         /* Check that the object is a vector too */
1788                         int bounds_reg = alloc_preg (cfg);
1789                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
1790                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
1791                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1792                 }
1793         } else {
1794                 int idepth_reg = alloc_preg (cfg);
1795                 int stypes_reg = alloc_preg (cfg);
1796                 int stype = alloc_preg (cfg);
1797
1798                 mono_class_setup_supertypes (klass);
1799
1800                 if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1801                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1802                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1803                         MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1804                 }
1805                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1806                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1807                 mini_emit_class_check_inst (cfg, stype, klass, klass_inst);
1808         }
1809 }
1810
1811 static void
1812 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null)
1813 {
1814         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, NULL, object_is_null);
1815 }
1816
1817 static void 
1818 mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align)
1819 {
1820         int val_reg;
1821
1822         g_assert (val == 0);
1823
1824         if (align == 0)
1825                 align = 4;
1826
1827         if ((size <= SIZEOF_REGISTER) && (size <= align)) {
1828                 switch (size) {
1829                 case 1:
1830                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, destreg, offset, val);
1831                         return;
1832                 case 2:
1833                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI2_MEMBASE_IMM, destreg, offset, val);
1834                         return;
1835                 case 4:
1836                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI4_MEMBASE_IMM, destreg, offset, val);
1837                         return;
1838 #if SIZEOF_REGISTER == 8
1839                 case 8:
1840                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI8_MEMBASE_IMM, destreg, offset, val);
1841                         return;
1842 #endif
1843                 }
1844         }
1845
1846         val_reg = alloc_preg (cfg);
1847
1848         if (SIZEOF_REGISTER == 8)
1849                 MONO_EMIT_NEW_I8CONST (cfg, val_reg, val);
1850         else
1851                 MONO_EMIT_NEW_ICONST (cfg, val_reg, val);
1852
1853         if (align < 4) {
1854                 /* This could be optimized further if neccesary */
1855                 while (size >= 1) {
1856                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1857                         offset += 1;
1858                         size -= 1;
1859                 }
1860                 return;
1861         }       
1862
1863         if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
1864                 if (offset % 8) {
1865                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1866                         offset += 4;
1867                         size -= 4;
1868                 }
1869                 while (size >= 8) {
1870                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, offset, val_reg);
1871                         offset += 8;
1872                         size -= 8;
1873                 }
1874         }       
1875
1876         while (size >= 4) {
1877                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1878                 offset += 4;
1879                 size -= 4;
1880         }
1881         while (size >= 2) {
1882                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, val_reg);
1883                 offset += 2;
1884                 size -= 2;
1885         }
1886         while (size >= 1) {
1887                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1888                 offset += 1;
1889                 size -= 1;
1890         }
1891 }
1892
1893 void 
1894 mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align)
1895 {
1896         int cur_reg;
1897
1898         if (align == 0)
1899                 align = 4;
1900
1901         /*FIXME arbitrary hack to avoid unbound code expansion.*/
1902         g_assert (size < 10000);
1903
1904         if (align < 4) {
1905                 /* This could be optimized further if neccesary */
1906                 while (size >= 1) {
1907                         cur_reg = alloc_preg (cfg);
1908                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1909                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1910                         doffset += 1;
1911                         soffset += 1;
1912                         size -= 1;
1913                 }
1914         }
1915
1916         if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
1917                 while (size >= 8) {
1918                         cur_reg = alloc_preg (cfg);
1919                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI8_MEMBASE, cur_reg, srcreg, soffset);
1920                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, doffset, cur_reg);
1921                         doffset += 8;
1922                         soffset += 8;
1923                         size -= 8;
1924                 }
1925         }       
1926
1927         while (size >= 4) {
1928                 cur_reg = alloc_preg (cfg);
1929                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, cur_reg, srcreg, soffset);
1930                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, doffset, cur_reg);
1931                 doffset += 4;
1932                 soffset += 4;
1933                 size -= 4;
1934         }
1935         while (size >= 2) {
1936                 cur_reg = alloc_preg (cfg);
1937                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, cur_reg, srcreg, soffset);
1938                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, doffset, cur_reg);
1939                 doffset += 2;
1940                 soffset += 2;
1941                 size -= 2;
1942         }
1943         while (size >= 1) {
1944                 cur_reg = alloc_preg (cfg);
1945                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1946                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1947                 doffset += 1;
1948                 soffset += 1;
1949                 size -= 1;
1950         }
1951 }
1952
1953 static void
1954 emit_tls_set (MonoCompile *cfg, int sreg1, MonoTlsKey tls_key)
1955 {
1956         MonoInst *ins, *c;
1957
1958         if (cfg->compile_aot) {
1959                 EMIT_NEW_TLS_OFFSETCONST (cfg, c, tls_key);
1960                 MONO_INST_NEW (cfg, ins, OP_TLS_SET_REG);
1961                 ins->sreg1 = sreg1;
1962                 ins->sreg2 = c->dreg;
1963                 MONO_ADD_INS (cfg->cbb, ins);
1964         } else {
1965                 MONO_INST_NEW (cfg, ins, OP_TLS_SET);
1966                 ins->sreg1 = sreg1;
1967                 ins->inst_offset = mini_get_tls_offset (tls_key);
1968                 MONO_ADD_INS (cfg->cbb, ins);
1969         }
1970 }
1971
1972 /*
1973  * emit_push_lmf:
1974  *
1975  *   Emit IR to push the current LMF onto the LMF stack.
1976  */
1977 static void
1978 emit_push_lmf (MonoCompile *cfg)
1979 {
1980         /*
1981          * Emit IR to push the LMF:
1982          * lmf_addr = <lmf_addr from tls>
1983          * lmf->lmf_addr = lmf_addr
1984          * lmf->prev_lmf = *lmf_addr
1985          * *lmf_addr = lmf
1986          */
1987         int lmf_reg, prev_lmf_reg;
1988         MonoInst *ins, *lmf_ins;
1989
1990         if (!cfg->lmf_ir)
1991                 return;
1992
1993         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
1994                 /* Load current lmf */
1995                 lmf_ins = mono_get_lmf_intrinsic (cfg);
1996                 g_assert (lmf_ins);
1997                 MONO_ADD_INS (cfg->cbb, lmf_ins);
1998                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
1999                 lmf_reg = ins->dreg;
2000                 /* Save previous_lmf */
2001                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), lmf_ins->dreg);
2002                 /* Set new LMF */
2003                 emit_tls_set (cfg, lmf_reg, TLS_KEY_LMF);
2004         } else {
2005                 /*
2006                  * Store lmf_addr in a variable, so it can be allocated to a global register.
2007                  */
2008                 if (!cfg->lmf_addr_var)
2009                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2010
2011 #ifdef HOST_WIN32
2012                 ins = mono_get_jit_tls_intrinsic (cfg);
2013                 if (ins) {
2014                         int jit_tls_dreg = ins->dreg;
2015
2016                         MONO_ADD_INS (cfg->cbb, ins);
2017                         lmf_reg = alloc_preg (cfg);
2018                         EMIT_NEW_BIALU_IMM (cfg, lmf_ins, OP_PADD_IMM, lmf_reg, jit_tls_dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2019                 } else {
2020                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2021                 }
2022 #else
2023                 lmf_ins = mono_get_lmf_addr_intrinsic (cfg);
2024                 if (lmf_ins) {
2025                         MONO_ADD_INS (cfg->cbb, lmf_ins);
2026                 } else {
2027 #ifdef TARGET_IOS
2028                         MonoInst *args [16], *jit_tls_ins, *ins;
2029
2030                         /* Inline mono_get_lmf_addr () */
2031                         /* jit_tls = pthread_getspecific (mono_jit_tls_id); lmf_addr = &jit_tls->lmf; */
2032
2033                         /* Load mono_jit_tls_id */
2034                         if (cfg->compile_aot)
2035                                 EMIT_NEW_AOTCONST (cfg, args [0], MONO_PATCH_INFO_JIT_TLS_ID, NULL);
2036                         else
2037                                 EMIT_NEW_ICONST (cfg, args [0], mono_jit_tls_id);
2038                         /* call pthread_getspecific () */
2039                         jit_tls_ins = mono_emit_jit_icall (cfg, pthread_getspecific, args);
2040                         /* lmf_addr = &jit_tls->lmf */
2041                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, cfg->lmf_addr_var->dreg, jit_tls_ins->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2042                         lmf_ins = ins;
2043 #else
2044                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2045 #endif
2046                 }
2047 #endif
2048                 lmf_ins->dreg = cfg->lmf_addr_var->dreg;
2049
2050                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2051                 lmf_reg = ins->dreg;
2052
2053                 prev_lmf_reg = alloc_preg (cfg);
2054                 /* Save previous_lmf */
2055                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, cfg->lmf_addr_var->dreg, 0);
2056                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), prev_lmf_reg);
2057                 /* Set new lmf */
2058                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, cfg->lmf_addr_var->dreg, 0, lmf_reg);
2059         }
2060 }
2061
2062 /*
2063  * emit_pop_lmf:
2064  *
2065  *   Emit IR to pop the current LMF from the LMF stack.
2066  */
2067 static void
2068 emit_pop_lmf (MonoCompile *cfg)
2069 {
2070         int lmf_reg, lmf_addr_reg, prev_lmf_reg;
2071         MonoInst *ins;
2072
2073         if (!cfg->lmf_ir)
2074                 return;
2075
2076         EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2077         lmf_reg = ins->dreg;
2078
2079         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
2080                 /* Load previous_lmf */
2081                 prev_lmf_reg = alloc_preg (cfg);
2082                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2083                 /* Set new LMF */
2084                 emit_tls_set (cfg, prev_lmf_reg, TLS_KEY_LMF);
2085         } else {
2086                 /*
2087                  * Emit IR to pop the LMF:
2088                  * *(lmf->lmf_addr) = lmf->prev_lmf
2089                  */
2090                 /* This could be called before emit_push_lmf () */
2091                 if (!cfg->lmf_addr_var)
2092                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2093                 lmf_addr_reg = cfg->lmf_addr_var->dreg;
2094
2095                 prev_lmf_reg = alloc_preg (cfg);
2096                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2097                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_addr_reg, 0, prev_lmf_reg);
2098         }
2099 }
2100
2101 static void
2102 emit_instrumentation_call (MonoCompile *cfg, void *func)
2103 {
2104         MonoInst *iargs [1];
2105
2106         /*
2107          * Avoid instrumenting inlined methods since it can
2108          * distort profiling results.
2109          */
2110         if (cfg->method != cfg->current_method)
2111                 return;
2112
2113         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
2114                 EMIT_NEW_METHODCONST (cfg, iargs [0], cfg->method);
2115                 mono_emit_jit_icall (cfg, func, iargs);
2116         }
2117 }
2118
2119 static int
2120 ret_type_to_call_opcode (MonoCompile *cfg, MonoType *type, int calli, int virt)
2121 {
2122 handle_enum:
2123         type = mini_get_underlying_type (type);
2124         switch (type->type) {
2125         case MONO_TYPE_VOID:
2126                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALL_MEMBASE: OP_VOIDCALL;
2127         case MONO_TYPE_I1:
2128         case MONO_TYPE_U1:
2129         case MONO_TYPE_I2:
2130         case MONO_TYPE_U2:
2131         case MONO_TYPE_I4:
2132         case MONO_TYPE_U4:
2133                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2134         case MONO_TYPE_I:
2135         case MONO_TYPE_U:
2136         case MONO_TYPE_PTR:
2137         case MONO_TYPE_FNPTR:
2138                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2139         case MONO_TYPE_CLASS:
2140         case MONO_TYPE_STRING:
2141         case MONO_TYPE_OBJECT:
2142         case MONO_TYPE_SZARRAY:
2143         case MONO_TYPE_ARRAY:    
2144                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2145         case MONO_TYPE_I8:
2146         case MONO_TYPE_U8:
2147                 return calli? OP_LCALL_REG: virt? OP_LCALL_MEMBASE: OP_LCALL;
2148         case MONO_TYPE_R4:
2149                 if (cfg->r4fp)
2150                         return calli? OP_RCALL_REG: virt? OP_RCALL_MEMBASE: OP_RCALL;
2151                 else
2152                         return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2153         case MONO_TYPE_R8:
2154                 return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2155         case MONO_TYPE_VALUETYPE:
2156                 if (type->data.klass->enumtype) {
2157                         type = mono_class_enum_basetype (type->data.klass);
2158                         goto handle_enum;
2159                 } else
2160                         return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2161         case MONO_TYPE_TYPEDBYREF:
2162                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2163         case MONO_TYPE_GENERICINST:
2164                 type = &type->data.generic_class->container_class->byval_arg;
2165                 goto handle_enum;
2166         case MONO_TYPE_VAR:
2167         case MONO_TYPE_MVAR:
2168                 /* gsharedvt */
2169                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2170         default:
2171                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
2172         }
2173         return -1;
2174 }
2175
2176 //XXX this ignores if t is byref
2177 #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)))))
2178
2179 /*
2180  * target_type_is_incompatible:
2181  * @cfg: MonoCompile context
2182  *
2183  * Check that the item @arg on the evaluation stack can be stored
2184  * in the target type (can be a local, or field, etc).
2185  * The cfg arg can be used to check if we need verification or just
2186  * validity checks.
2187  *
2188  * Returns: non-0 value if arg can't be stored on a target.
2189  */
2190 static int
2191 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
2192 {
2193         MonoType *simple_type;
2194         MonoClass *klass;
2195
2196         if (target->byref) {
2197                 /* FIXME: check that the pointed to types match */
2198                 if (arg->type == STACK_MP) {
2199                         if (cfg->verbose_level) printf ("ok\n");
2200                         /* This is needed to handle gshared types + ldaddr. We lower the types so we can handle enums and other typedef-like types. */
2201                         MonoClass *target_class_lowered = mono_class_from_mono_type (mini_get_underlying_type (&mono_class_from_mono_type (target)->byval_arg));
2202                         MonoClass *source_class_lowered = mono_class_from_mono_type (mini_get_underlying_type (&arg->klass->byval_arg));
2203
2204                         /* if the target is native int& or same type */
2205                         if (target->type == MONO_TYPE_I || target_class_lowered == source_class_lowered)
2206                                 return 0;
2207
2208                         /* Both are primitive type byrefs and the source points to a larger type that the destination */
2209                         if (MONO_TYPE_IS_PRIMITIVE_SCALAR (&target_class_lowered->byval_arg) && MONO_TYPE_IS_PRIMITIVE_SCALAR (&source_class_lowered->byval_arg) &&
2210                                 mono_class_instance_size (target_class_lowered) <= mono_class_instance_size (source_class_lowered))
2211                                 return 0;
2212                         return 1;
2213                 }
2214                 if (arg->type == STACK_PTR)
2215                         return 0;
2216                 return 1;
2217         }
2218
2219         simple_type = mini_get_underlying_type (target);
2220         switch (simple_type->type) {
2221         case MONO_TYPE_VOID:
2222                 return 1;
2223         case MONO_TYPE_I1:
2224         case MONO_TYPE_U1:
2225         case MONO_TYPE_I2:
2226         case MONO_TYPE_U2:
2227         case MONO_TYPE_I4:
2228         case MONO_TYPE_U4:
2229                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2230                         return 1;
2231                 return 0;
2232         case MONO_TYPE_PTR:
2233                 /* STACK_MP is needed when setting pinned locals */
2234                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2235                         return 1;
2236                 return 0;
2237         case MONO_TYPE_I:
2238         case MONO_TYPE_U:
2239         case MONO_TYPE_FNPTR:
2240                 /* 
2241                  * Some opcodes like ldloca returns 'transient pointers' which can be stored in
2242                  * in native int. (#688008).
2243                  */
2244                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2245                         return 1;
2246                 return 0;
2247         case MONO_TYPE_CLASS:
2248         case MONO_TYPE_STRING:
2249         case MONO_TYPE_OBJECT:
2250         case MONO_TYPE_SZARRAY:
2251         case MONO_TYPE_ARRAY:    
2252                 if (arg->type != STACK_OBJ)
2253                         return 1;
2254                 /* FIXME: check type compatibility */
2255                 return 0;
2256         case MONO_TYPE_I8:
2257         case MONO_TYPE_U8:
2258                 if (arg->type != STACK_I8)
2259                         return 1;
2260                 return 0;
2261         case MONO_TYPE_R4:
2262                 if (arg->type != cfg->r4_stack_type)
2263                         return 1;
2264                 return 0;
2265         case MONO_TYPE_R8:
2266                 if (arg->type != STACK_R8)
2267                         return 1;
2268                 return 0;
2269         case MONO_TYPE_VALUETYPE:
2270                 if (arg->type != STACK_VTYPE)
2271                         return 1;
2272                 klass = mono_class_from_mono_type (simple_type);
2273                 if (klass != arg->klass)
2274                         return 1;
2275                 return 0;
2276         case MONO_TYPE_TYPEDBYREF:
2277                 if (arg->type != STACK_VTYPE)
2278                         return 1;
2279                 klass = mono_class_from_mono_type (simple_type);
2280                 if (klass != arg->klass)
2281                         return 1;
2282                 return 0;
2283         case MONO_TYPE_GENERICINST:
2284                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
2285                         MonoClass *target_class;
2286                         if (arg->type != STACK_VTYPE)
2287                                 return 1;
2288                         klass = mono_class_from_mono_type (simple_type);
2289                         target_class = mono_class_from_mono_type (target);
2290                         /* The second cases is needed when doing partial sharing */
2291                         if (klass != arg->klass && target_class != arg->klass && target_class != mono_class_from_mono_type (mini_get_underlying_type (&arg->klass->byval_arg)))
2292                                 return 1;
2293                         return 0;
2294                 } else {
2295                         if (arg->type != STACK_OBJ)
2296                                 return 1;
2297                         /* FIXME: check type compatibility */
2298                         return 0;
2299                 }
2300         case MONO_TYPE_VAR:
2301         case MONO_TYPE_MVAR:
2302                 g_assert (cfg->gshared);
2303                 if (mini_type_var_is_vt (simple_type)) {
2304                         if (arg->type != STACK_VTYPE)
2305                                 return 1;
2306                 } else {
2307                         if (arg->type != STACK_OBJ)
2308                                 return 1;
2309                 }
2310                 return 0;
2311         default:
2312                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
2313         }
2314         return 1;
2315 }
2316
2317 /*
2318  * Prepare arguments for passing to a function call.
2319  * Return a non-zero value if the arguments can't be passed to the given
2320  * signature.
2321  * The type checks are not yet complete and some conversions may need
2322  * casts on 32 or 64 bit architectures.
2323  *
2324  * FIXME: implement this using target_type_is_incompatible ()
2325  */
2326 static int
2327 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2328 {
2329         MonoType *simple_type;
2330         int i;
2331
2332         if (sig->hasthis) {
2333                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2334                         return 1;
2335                 args++;
2336         }
2337         for (i = 0; i < sig->param_count; ++i) {
2338                 if (sig->params [i]->byref) {
2339                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2340                                 return 1;
2341                         continue;
2342                 }
2343                 simple_type = mini_get_underlying_type (sig->params [i]);
2344 handle_enum:
2345                 switch (simple_type->type) {
2346                 case MONO_TYPE_VOID:
2347                         return 1;
2348                         continue;
2349                 case MONO_TYPE_I1:
2350                 case MONO_TYPE_U1:
2351                 case MONO_TYPE_I2:
2352                 case MONO_TYPE_U2:
2353                 case MONO_TYPE_I4:
2354                 case MONO_TYPE_U4:
2355                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2356                                 return 1;
2357                         continue;
2358                 case MONO_TYPE_I:
2359                 case MONO_TYPE_U:
2360                 case MONO_TYPE_PTR:
2361                 case MONO_TYPE_FNPTR:
2362                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2363                                 return 1;
2364                         continue;
2365                 case MONO_TYPE_CLASS:
2366                 case MONO_TYPE_STRING:
2367                 case MONO_TYPE_OBJECT:
2368                 case MONO_TYPE_SZARRAY:
2369                 case MONO_TYPE_ARRAY:    
2370                         if (args [i]->type != STACK_OBJ)
2371                                 return 1;
2372                         continue;
2373                 case MONO_TYPE_I8:
2374                 case MONO_TYPE_U8:
2375                         if (args [i]->type != STACK_I8)
2376                                 return 1;
2377                         continue;
2378                 case MONO_TYPE_R4:
2379                         if (args [i]->type != cfg->r4_stack_type)
2380                                 return 1;
2381                         continue;
2382                 case MONO_TYPE_R8:
2383                         if (args [i]->type != STACK_R8)
2384                                 return 1;
2385                         continue;
2386                 case MONO_TYPE_VALUETYPE:
2387                         if (simple_type->data.klass->enumtype) {
2388                                 simple_type = mono_class_enum_basetype (simple_type->data.klass);
2389                                 goto handle_enum;
2390                         }
2391                         if (args [i]->type != STACK_VTYPE)
2392                                 return 1;
2393                         continue;
2394                 case MONO_TYPE_TYPEDBYREF:
2395                         if (args [i]->type != STACK_VTYPE)
2396                                 return 1;
2397                         continue;
2398                 case MONO_TYPE_GENERICINST:
2399                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2400                         goto handle_enum;
2401                 case MONO_TYPE_VAR:
2402                 case MONO_TYPE_MVAR:
2403                         /* gsharedvt */
2404                         if (args [i]->type != STACK_VTYPE)
2405                                 return 1;
2406                         continue;
2407                 default:
2408                         g_error ("unknown type 0x%02x in check_call_signature",
2409                                  simple_type->type);
2410                 }
2411         }
2412         return 0;
2413 }
2414
2415 static int
2416 callvirt_to_call (int opcode)
2417 {
2418         switch (opcode) {
2419         case OP_CALL_MEMBASE:
2420                 return OP_CALL;
2421         case OP_VOIDCALL_MEMBASE:
2422                 return OP_VOIDCALL;
2423         case OP_FCALL_MEMBASE:
2424                 return OP_FCALL;
2425         case OP_RCALL_MEMBASE:
2426                 return OP_RCALL;
2427         case OP_VCALL_MEMBASE:
2428                 return OP_VCALL;
2429         case OP_LCALL_MEMBASE:
2430                 return OP_LCALL;
2431         default:
2432                 g_assert_not_reached ();
2433         }
2434
2435         return -1;
2436 }
2437
2438 static int
2439 callvirt_to_call_reg (int opcode)
2440 {
2441         switch (opcode) {
2442         case OP_CALL_MEMBASE:
2443                 return OP_CALL_REG;
2444         case OP_VOIDCALL_MEMBASE:
2445                 return OP_VOIDCALL_REG;
2446         case OP_FCALL_MEMBASE:
2447                 return OP_FCALL_REG;
2448         case OP_RCALL_MEMBASE:
2449                 return OP_RCALL_REG;
2450         case OP_VCALL_MEMBASE:
2451                 return OP_VCALL_REG;
2452         case OP_LCALL_MEMBASE:
2453                 return OP_LCALL_REG;
2454         default:
2455                 g_assert_not_reached ();
2456         }
2457
2458         return -1;
2459 }
2460
2461 /* Either METHOD or IMT_ARG needs to be set */
2462 static void
2463 emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoMethod *method, MonoInst *imt_arg)
2464 {
2465         int method_reg;
2466
2467         if (COMPILE_LLVM (cfg)) {
2468                 if (imt_arg) {
2469                         method_reg = alloc_preg (cfg);
2470                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2471                 } else {
2472                         MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHODCONST, method);
2473                         method_reg = ins->dreg;
2474                 }
2475
2476 #ifdef ENABLE_LLVM
2477                 call->imt_arg_reg = method_reg;
2478 #endif
2479                 mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2480                 return;
2481         }
2482
2483         if (imt_arg) {
2484                 method_reg = alloc_preg (cfg);
2485                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2486         } else {
2487                 MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHODCONST, method);
2488                 method_reg = ins->dreg;
2489         }
2490
2491         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2492 }
2493
2494 static MonoJumpInfo *
2495 mono_patch_info_new (MonoMemPool *mp, int ip, MonoJumpInfoType type, gconstpointer target)
2496 {
2497         MonoJumpInfo *ji = (MonoJumpInfo *)mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
2498
2499         ji->ip.i = ip;
2500         ji->type = type;
2501         ji->data.target = target;
2502
2503         return ji;
2504 }
2505
2506 static int
2507 mini_class_check_context_used (MonoCompile *cfg, MonoClass *klass)
2508 {
2509         if (cfg->gshared)
2510                 return mono_class_check_context_used (klass);
2511         else
2512                 return 0;
2513 }
2514
2515 static int
2516 mini_method_check_context_used (MonoCompile *cfg, MonoMethod *method)
2517 {
2518         if (cfg->gshared)
2519                 return mono_method_check_context_used (method);
2520         else
2521                 return 0;
2522 }
2523
2524 /*
2525  * check_method_sharing:
2526  *
2527  *   Check whenever the vtable or an mrgctx needs to be passed when calling CMETHOD.
2528  */
2529 static void
2530 check_method_sharing (MonoCompile *cfg, MonoMethod *cmethod, gboolean *out_pass_vtable, gboolean *out_pass_mrgctx)
2531 {
2532         gboolean pass_vtable = FALSE;
2533         gboolean pass_mrgctx = FALSE;
2534
2535         if (((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
2536                 (cmethod->klass->generic_class || cmethod->klass->generic_container)) {
2537                 gboolean sharable = FALSE;
2538
2539                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE))
2540                         sharable = TRUE;
2541
2542                 /*
2543                  * Pass vtable iff target method might
2544                  * be shared, which means that sharing
2545                  * is enabled for its class and its
2546                  * context is sharable (and it's not a
2547                  * generic method).
2548                  */
2549                 if (sharable && !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
2550                         pass_vtable = TRUE;
2551         }
2552
2553         if (mini_method_get_context (cmethod) &&
2554                 mini_method_get_context (cmethod)->method_inst) {
2555                 g_assert (!pass_vtable);
2556
2557                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE)) {
2558                         pass_mrgctx = TRUE;
2559                 } else {
2560                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (mono_method_signature (cmethod)))
2561                                 pass_mrgctx = TRUE;
2562                 }
2563         }
2564
2565         if (out_pass_vtable)
2566                 *out_pass_vtable = pass_vtable;
2567         if (out_pass_mrgctx)
2568                 *out_pass_mrgctx = pass_mrgctx;
2569 }
2570
2571 inline static MonoCallInst *
2572 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
2573                                          MonoInst **args, int calli, int virtual_, int tail, int rgctx, int unbox_trampoline)
2574 {
2575         MonoType *sig_ret;
2576         MonoCallInst *call;
2577 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2578         int i;
2579 #endif
2580
2581         if (cfg->llvm_only)
2582                 tail = FALSE;
2583
2584         if (tail) {
2585                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
2586
2587                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
2588         } else
2589                 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (cfg, sig->ret, calli, virtual_));
2590
2591         call->args = args;
2592         call->signature = sig;
2593         call->rgctx_reg = rgctx;
2594         sig_ret = mini_get_underlying_type (sig->ret);
2595
2596         type_to_eval_stack_type ((cfg), sig_ret, &call->inst);
2597
2598         if (tail) {
2599                 if (mini_type_is_vtype (sig_ret)) {
2600                         call->vret_var = cfg->vret_addr;
2601                         //g_assert_not_reached ();
2602                 }
2603         } else if (mini_type_is_vtype (sig_ret)) {
2604                 MonoInst *temp = mono_compile_create_var (cfg, sig_ret, OP_LOCAL);
2605                 MonoInst *loada;
2606
2607                 temp->backend.is_pinvoke = sig->pinvoke;
2608
2609                 /*
2610                  * We use a new opcode OP_OUTARG_VTRETADDR instead of LDADDR for emitting the
2611                  * address of return value to increase optimization opportunities.
2612                  * Before vtype decomposition, the dreg of the call ins itself represents the
2613                  * fact the call modifies the return value. After decomposition, the call will
2614                  * be transformed into one of the OP_VOIDCALL opcodes, and the VTRETADDR opcode
2615                  * will be transformed into an LDADDR.
2616                  */
2617                 MONO_INST_NEW (cfg, loada, OP_OUTARG_VTRETADDR);
2618                 loada->dreg = alloc_preg (cfg);
2619                 loada->inst_p0 = temp;
2620                 /* We reference the call too since call->dreg could change during optimization */
2621                 loada->inst_p1 = call;
2622                 MONO_ADD_INS (cfg->cbb, loada);
2623
2624                 call->inst.dreg = temp->dreg;
2625
2626                 call->vret_var = loada;
2627         } else if (!MONO_TYPE_IS_VOID (sig_ret))
2628                 call->inst.dreg = alloc_dreg (cfg, (MonoStackType)call->inst.type);
2629
2630 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2631         if (COMPILE_SOFT_FLOAT (cfg)) {
2632                 /* 
2633                  * If the call has a float argument, we would need to do an r8->r4 conversion using 
2634                  * an icall, but that cannot be done during the call sequence since it would clobber
2635                  * the call registers + the stack. So we do it before emitting the call.
2636                  */
2637                 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2638                         MonoType *t;
2639                         MonoInst *in = call->args [i];
2640
2641                         if (i >= sig->hasthis)
2642                                 t = sig->params [i - sig->hasthis];
2643                         else
2644                                 t = &mono_defaults.int_class->byval_arg;
2645                         t = mono_type_get_underlying_type (t);
2646
2647                         if (!t->byref && t->type == MONO_TYPE_R4) {
2648                                 MonoInst *iargs [1];
2649                                 MonoInst *conv;
2650
2651                                 iargs [0] = in;
2652                                 conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
2653
2654                                 /* The result will be in an int vreg */
2655                                 call->args [i] = conv;
2656                         }
2657                 }
2658         }
2659 #endif
2660
2661         call->need_unbox_trampoline = unbox_trampoline;
2662
2663 #ifdef ENABLE_LLVM
2664         if (COMPILE_LLVM (cfg))
2665                 mono_llvm_emit_call (cfg, call);
2666         else
2667                 mono_arch_emit_call (cfg, call);
2668 #else
2669         mono_arch_emit_call (cfg, call);
2670 #endif
2671
2672         cfg->param_area = MAX (cfg->param_area, call->stack_usage);
2673         cfg->flags |= MONO_CFG_HAS_CALLS;
2674         
2675         return call;
2676 }
2677
2678 static void
2679 set_rgctx_arg (MonoCompile *cfg, MonoCallInst *call, int rgctx_reg, MonoInst *rgctx_arg)
2680 {
2681         mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
2682         cfg->uses_rgctx_reg = TRUE;
2683         call->rgctx_reg = TRUE;
2684 #ifdef ENABLE_LLVM
2685         call->rgctx_arg_reg = rgctx_reg;
2686 #endif
2687 }       
2688
2689 inline static MonoInst*
2690 mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg)
2691 {
2692         MonoCallInst *call;
2693         MonoInst *ins;
2694         int rgctx_reg = -1;
2695         gboolean check_sp = FALSE;
2696
2697         if (cfg->check_pinvoke_callconv && cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
2698                 WrapperInfo *info = mono_marshal_get_wrapper_info (cfg->method);
2699
2700                 if (info && info->subtype == WRAPPER_SUBTYPE_PINVOKE)
2701                         check_sp = TRUE;
2702         }
2703
2704         if (rgctx_arg) {
2705                 rgctx_reg = mono_alloc_preg (cfg);
2706                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2707         }
2708
2709         if (check_sp) {
2710                 if (!cfg->stack_inbalance_var)
2711                         cfg->stack_inbalance_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2712
2713                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2714                 ins->dreg = cfg->stack_inbalance_var->dreg;
2715                 MONO_ADD_INS (cfg->cbb, ins);
2716         }
2717
2718         call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE, FALSE);
2719
2720         call->inst.sreg1 = addr->dreg;
2721
2722         if (imt_arg)
2723                 emit_imt_argument (cfg, call, NULL, imt_arg);
2724
2725         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2726
2727         if (check_sp) {
2728                 int sp_reg;
2729
2730                 sp_reg = mono_alloc_preg (cfg);
2731
2732                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2733                 ins->dreg = sp_reg;
2734                 MONO_ADD_INS (cfg->cbb, ins);
2735
2736                 /* Restore the stack so we don't crash when throwing the exception */
2737                 MONO_INST_NEW (cfg, ins, OP_SET_SP);
2738                 ins->sreg1 = cfg->stack_inbalance_var->dreg;
2739                 MONO_ADD_INS (cfg->cbb, ins);
2740
2741                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, cfg->stack_inbalance_var->dreg, sp_reg);
2742                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ExecutionEngineException");
2743         }
2744
2745         if (rgctx_arg)
2746                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2747
2748         return (MonoInst*)call;
2749 }
2750
2751 static MonoInst*
2752 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2753
2754 static MonoInst*
2755 emit_get_rgctx_method (MonoCompile *cfg, int context_used, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type);
2756 static MonoInst*
2757 emit_get_rgctx_klass (MonoCompile *cfg, int context_used, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2758
2759 static MonoInst*
2760 mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig, gboolean tail,
2761                                                         MonoInst **args, MonoInst *this_ins, MonoInst *imt_arg, MonoInst *rgctx_arg)
2762 {
2763 #ifndef DISABLE_REMOTING
2764         gboolean might_be_remote = FALSE;
2765 #endif
2766         gboolean virtual_ = this_ins != NULL;
2767         gboolean enable_for_aot = TRUE;
2768         int context_used;
2769         MonoCallInst *call;
2770         MonoInst *call_target = NULL;
2771         int rgctx_reg = 0;
2772         gboolean need_unbox_trampoline;
2773
2774         if (!sig)
2775                 sig = mono_method_signature (method);
2776
2777         if (cfg->llvm_only && (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE))
2778                 g_assert_not_reached ();
2779
2780         if (rgctx_arg) {
2781                 rgctx_reg = mono_alloc_preg (cfg);
2782                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2783         }
2784
2785         if (method->string_ctor) {
2786                 /* Create the real signature */
2787                 /* FIXME: Cache these */
2788                 MonoMethodSignature *ctor_sig = mono_metadata_signature_dup_mempool (cfg->mempool, sig);
2789                 ctor_sig->ret = &mono_defaults.string_class->byval_arg;
2790
2791                 sig = ctor_sig;
2792         }
2793
2794         context_used = mini_method_check_context_used (cfg, method);
2795
2796 #ifndef DISABLE_REMOTING
2797         might_be_remote = this_ins && sig->hasthis &&
2798                 (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) &&
2799                 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && (!MONO_CHECK_THIS (this_ins) || context_used);
2800
2801         if (might_be_remote && context_used) {
2802                 MonoInst *addr;
2803
2804                 g_assert (cfg->gshared);
2805
2806                 addr = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK);
2807
2808                 return mono_emit_calli (cfg, sig, args, addr, NULL, NULL);
2809         }
2810 #endif
2811
2812         if (cfg->llvm_only && !call_target && virtual_ && (method->flags & METHOD_ATTRIBUTE_VIRTUAL))
2813                 return emit_llvmonly_virtual_call (cfg, method, sig, 0, args);
2814
2815         need_unbox_trampoline = method->klass == mono_defaults.object_class || (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
2816
2817         call = mono_emit_call_args (cfg, sig, args, FALSE, virtual_, tail, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline);
2818
2819 #ifndef DISABLE_REMOTING
2820         if (might_be_remote)
2821                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2822         else
2823 #endif
2824                 call->method = method;
2825         call->inst.flags |= MONO_INST_HAS_METHOD;
2826         call->inst.inst_left = this_ins;
2827         call->tail_call = tail;
2828
2829         if (virtual_) {
2830                 int vtable_reg, slot_reg, this_reg;
2831                 int offset;
2832
2833                 this_reg = this_ins->dreg;
2834
2835                 if (!cfg->llvm_only && (method->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (method->name, "Invoke")) {
2836                         MonoInst *dummy_use;
2837
2838                         MONO_EMIT_NULL_CHECK (cfg, this_reg);
2839
2840                         /* Make a call to delegate->invoke_impl */
2841                         call->inst.inst_basereg = this_reg;
2842                         call->inst.inst_offset = MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl);
2843                         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2844
2845                         /* We must emit a dummy use here because the delegate trampoline will
2846                         replace the 'this' argument with the delegate target making this activation
2847                         no longer a root for the delegate.
2848                         This is an issue for delegates that target collectible code such as dynamic
2849                         methods of GC'able assemblies.
2850
2851                         For a test case look into #667921.
2852
2853                         FIXME: a dummy use is not the best way to do it as the local register allocator
2854                         will put it on a caller save register and spil it around the call. 
2855                         Ideally, we would either put it on a callee save register or only do the store part.  
2856                          */
2857                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, args [0]);
2858
2859                         return (MonoInst*)call;
2860                 }
2861
2862                 if ((!cfg->compile_aot || enable_for_aot) && 
2863                         (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || 
2864                          (MONO_METHOD_IS_FINAL (method) &&
2865                           method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)) &&
2866                         !(mono_class_is_marshalbyref (method->klass) && context_used)) {
2867                         /* 
2868                          * the method is not virtual, we just need to ensure this is not null
2869                          * and then we can call the method directly.
2870                          */
2871 #ifndef DISABLE_REMOTING
2872                         if (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) {
2873                                 /* 
2874                                  * The check above ensures method is not gshared, this is needed since
2875                                  * gshared methods can't have wrappers.
2876                                  */
2877                                 method = call->method = mono_marshal_get_remoting_invoke_with_check (method);
2878                         }
2879 #endif
2880
2881                         if (!method->string_ctor)
2882                                 MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2883
2884                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2885                 } else if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && MONO_METHOD_IS_FINAL (method)) {
2886                         /*
2887                          * the method is virtual, but we can statically dispatch since either
2888                          * it's class or the method itself are sealed.
2889                          * But first we need to ensure it's not a null reference.
2890                          */
2891                         MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2892
2893                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2894                 } else if (call_target) {
2895                         vtable_reg = alloc_preg (cfg);
2896                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2897
2898                         call->inst.opcode = callvirt_to_call_reg (call->inst.opcode);
2899                         call->inst.sreg1 = call_target->dreg;
2900                         call->inst.flags &= !MONO_INST_HAS_METHOD;
2901                 } else {
2902                         vtable_reg = alloc_preg (cfg);
2903                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2904                         if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2905                                 guint32 imt_slot = mono_method_get_imt_slot (method);
2906                                 emit_imt_argument (cfg, call, call->method, imt_arg);
2907                                 slot_reg = vtable_reg;
2908                                 offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
2909                         } else {
2910                                 slot_reg = vtable_reg;
2911                                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) +
2912                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
2913                                 if (imt_arg) {
2914                                         g_assert (mono_method_signature (method)->generic_param_count);
2915                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2916                                 }
2917                         }
2918
2919                         call->inst.sreg1 = slot_reg;
2920                         call->inst.inst_offset = offset;
2921                         call->is_virtual = TRUE;
2922                 }
2923         }
2924
2925         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2926
2927         if (rgctx_arg)
2928                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2929
2930         return (MonoInst*)call;
2931 }
2932
2933 MonoInst*
2934 mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoInst **args, MonoInst *this_ins)
2935 {
2936         return mono_emit_method_call_full (cfg, method, mono_method_signature (method), FALSE, args, this_ins, NULL, NULL);
2937 }
2938
2939 MonoInst*
2940 mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig,
2941                                            MonoInst **args)
2942 {
2943         MonoCallInst *call;
2944
2945         g_assert (sig);
2946
2947         call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE, FALSE, FALSE);
2948         call->fptr = func;
2949
2950         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2951
2952         return (MonoInst*)call;
2953 }
2954
2955 MonoInst*
2956 mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args)
2957 {
2958         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2959
2960         g_assert (info);
2961
2962         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2963 }
2964
2965 /*
2966  * mono_emit_abs_call:
2967  *
2968  *   Emit a call to the runtime function described by PATCH_TYPE and DATA.
2969  */
2970 inline static MonoInst*
2971 mono_emit_abs_call (MonoCompile *cfg, MonoJumpInfoType patch_type, gconstpointer data, 
2972                                         MonoMethodSignature *sig, MonoInst **args)
2973 {
2974         MonoJumpInfo *ji = mono_patch_info_new (cfg->mempool, 0, patch_type, data);
2975         MonoInst *ins;
2976
2977         /* 
2978          * We pass ji as the call address, the PATCH_INFO_ABS resolving code will
2979          * handle it.
2980          */
2981         if (cfg->abs_patches == NULL)
2982                 cfg->abs_patches = g_hash_table_new (NULL, NULL);
2983         g_hash_table_insert (cfg->abs_patches, ji, ji);
2984         ins = mono_emit_native_call (cfg, ji, sig, args);
2985         ((MonoCallInst*)ins)->fptr_is_patch = TRUE;
2986         return ins;
2987 }
2988
2989 static MonoMethodSignature*
2990 sig_to_rgctx_sig (MonoMethodSignature *sig)
2991 {
2992         // FIXME: memory allocation
2993         MonoMethodSignature *res;
2994         int i;
2995
2996         res = (MonoMethodSignature *)g_malloc (MONO_SIZEOF_METHOD_SIGNATURE + (sig->param_count + 1) * sizeof (MonoType*));
2997         memcpy (res, sig, MONO_SIZEOF_METHOD_SIGNATURE);
2998         res->param_count = sig->param_count + 1;
2999         for (i = 0; i < sig->param_count; ++i)
3000                 res->params [i] = sig->params [i];
3001         res->params [sig->param_count] = &mono_defaults.int_class->this_arg;
3002         return res;
3003 }
3004
3005 /* Make an indirect call to FSIG passing an additional argument */
3006 static MonoInst*
3007 emit_extra_arg_calli (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **orig_args, int arg_reg, MonoInst *call_target)
3008 {
3009         MonoMethodSignature *csig;
3010         MonoInst *args_buf [16];
3011         MonoInst **args;
3012         int i, pindex, tmp_reg;
3013
3014         /* Make a call with an rgctx/extra arg */
3015         if (fsig->param_count + 2 < 16)
3016                 args = args_buf;
3017         else
3018                 args = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (fsig->param_count + 2));
3019         pindex = 0;
3020         if (fsig->hasthis)
3021                 args [pindex ++] = orig_args [0];
3022         for (i = 0; i < fsig->param_count; ++i)
3023                 args [pindex ++] = orig_args [fsig->hasthis + i];
3024         tmp_reg = alloc_preg (cfg);
3025         EMIT_NEW_UNALU (cfg, args [pindex], OP_MOVE, tmp_reg, arg_reg);
3026         csig = sig_to_rgctx_sig (fsig);
3027         return mono_emit_calli (cfg, csig, args, call_target, NULL, NULL);
3028 }
3029
3030 /* Emit an indirect call to the function descriptor ADDR */
3031 static MonoInst*
3032 emit_llvmonly_calli (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, MonoInst *addr)
3033 {
3034         int addr_reg, arg_reg;
3035         MonoInst *call_target;
3036
3037         g_assert (cfg->llvm_only);
3038
3039         /*
3040          * addr points to a <addr, arg> pair, load both of them, and
3041          * make a call to addr, passing arg as an extra arg.
3042          */
3043         addr_reg = alloc_preg (cfg);
3044         EMIT_NEW_LOAD_MEMBASE (cfg, call_target, OP_LOAD_MEMBASE, addr_reg, addr->dreg, 0);
3045         arg_reg = alloc_preg (cfg);
3046         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, arg_reg, addr->dreg, sizeof (gpointer));
3047
3048         return emit_extra_arg_calli (cfg, fsig, args, arg_reg, call_target);
3049 }
3050
3051 static gboolean
3052 direct_icalls_enabled (MonoCompile *cfg)
3053 {
3054         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
3055 #ifdef TARGET_AMD64
3056         if (cfg->compile_llvm && !cfg->llvm_only)
3057                 return FALSE;
3058 #endif
3059         if (cfg->gen_sdb_seq_points || cfg->disable_direct_icalls)
3060                 return FALSE;
3061         return TRUE;
3062 }
3063
3064 MonoInst*
3065 mono_emit_jit_icall_by_info (MonoCompile *cfg, int il_offset, MonoJitICallInfo *info, MonoInst **args)
3066 {
3067         /*
3068          * Call the jit icall without a wrapper if possible.
3069          * The wrapper is needed for the following reasons:
3070          * - to handle exceptions thrown using mono_raise_exceptions () from the
3071          *   icall function. The EH code needs the lmf frame pushed by the
3072          *   wrapper to be able to unwind back to managed code.
3073          * - to be able to do stack walks for asynchronously suspended
3074          *   threads when debugging.
3075          */
3076         if (info->no_raise && direct_icalls_enabled (cfg)) {
3077                 char *name;
3078                 int costs;
3079
3080                 if (!info->wrapper_method) {
3081                         name = g_strdup_printf ("__icall_wrapper_%s", info->name);
3082                         info->wrapper_method = mono_marshal_get_icall_wrapper (info->sig, name, info->func, TRUE);
3083                         g_free (name);
3084                         mono_memory_barrier ();
3085                 }
3086
3087                 /*
3088                  * Inline the wrapper method, which is basically a call to the C icall, and
3089                  * an exception check.
3090                  */
3091                 costs = inline_method (cfg, info->wrapper_method, NULL,
3092                                                            args, NULL, il_offset, TRUE);
3093                 g_assert (costs > 0);
3094                 g_assert (!MONO_TYPE_IS_VOID (info->sig->ret));
3095
3096                 return args [0];
3097         } else {
3098                 return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
3099         }
3100 }
3101  
3102 static MonoInst*
3103 mono_emit_widen_call_res (MonoCompile *cfg, MonoInst *ins, MonoMethodSignature *fsig)
3104 {
3105         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
3106                 if ((fsig->pinvoke || LLVM_ENABLED) && !fsig->ret->byref) {
3107                         int widen_op = -1;
3108
3109                         /* 
3110                          * Native code might return non register sized integers 
3111                          * without initializing the upper bits.
3112                          */
3113                         switch (mono_type_to_load_membase (cfg, fsig->ret)) {
3114                         case OP_LOADI1_MEMBASE:
3115                                 widen_op = OP_ICONV_TO_I1;
3116                                 break;
3117                         case OP_LOADU1_MEMBASE:
3118                                 widen_op = OP_ICONV_TO_U1;
3119                                 break;
3120                         case OP_LOADI2_MEMBASE:
3121                                 widen_op = OP_ICONV_TO_I2;
3122                                 break;
3123                         case OP_LOADU2_MEMBASE:
3124                                 widen_op = OP_ICONV_TO_U2;
3125                                 break;
3126                         default:
3127                                 break;
3128                         }
3129
3130                         if (widen_op != -1) {
3131                                 int dreg = alloc_preg (cfg);
3132                                 MonoInst *widen;
3133
3134                                 EMIT_NEW_UNALU (cfg, widen, widen_op, dreg, ins->dreg);
3135                                 widen->type = ins->type;
3136                                 ins = widen;
3137                         }
3138                 }
3139         }
3140
3141         return ins;
3142 }
3143
3144
3145 static void
3146 emit_method_access_failure (MonoCompile *cfg, MonoMethod *method, MonoMethod *cil_method)
3147 {
3148         MonoInst *args [16];
3149
3150         args [0] = emit_get_rgctx_method (cfg, mono_method_check_context_used (method), method, MONO_RGCTX_INFO_METHOD);
3151         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cil_method), cil_method, MONO_RGCTX_INFO_METHOD);
3152
3153         mono_emit_jit_icall (cfg, mono_throw_method_access, args);
3154 }
3155
3156 static MonoMethod*
3157 get_memcpy_method (void)
3158 {
3159         static MonoMethod *memcpy_method = NULL;
3160         if (!memcpy_method) {
3161                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
3162                 if (!memcpy_method)
3163                         g_error ("Old corlib found. Install a new one");
3164         }
3165         return memcpy_method;
3166 }
3167
3168 static void
3169 create_write_barrier_bitmap (MonoCompile *cfg, MonoClass *klass, unsigned *wb_bitmap, int offset)
3170 {
3171         MonoClassField *field;
3172         gpointer iter = NULL;
3173
3174         while ((field = mono_class_get_fields (klass, &iter))) {
3175                 int foffset;
3176
3177                 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3178                         continue;
3179                 foffset = klass->valuetype ? field->offset - sizeof (MonoObject): field->offset;
3180                 if (mini_type_is_reference (mono_field_get_type (field))) {
3181                         g_assert ((foffset % SIZEOF_VOID_P) == 0);
3182                         *wb_bitmap |= 1 << ((offset + foffset) / SIZEOF_VOID_P);
3183                 } else {
3184                         MonoClass *field_class = mono_class_from_mono_type (field->type);
3185                         if (field_class->has_references)
3186                                 create_write_barrier_bitmap (cfg, field_class, wb_bitmap, offset + foffset);
3187                 }
3188         }
3189 }
3190
3191 static void
3192 emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value)
3193 {
3194         int card_table_shift_bits;
3195         gpointer card_table_mask;
3196         guint8 *card_table;
3197         MonoInst *dummy_use;
3198         int nursery_shift_bits;
3199         size_t nursery_size;
3200
3201         if (!cfg->gen_write_barriers)
3202                 return;
3203
3204         card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
3205
3206         mono_gc_get_nursery (&nursery_shift_bits, &nursery_size);
3207
3208         if (cfg->backend->have_card_table_wb && !cfg->compile_aot && card_table && nursery_shift_bits > 0 && !COMPILE_LLVM (cfg)) {
3209                 MonoInst *wbarrier;
3210
3211                 MONO_INST_NEW (cfg, wbarrier, OP_CARD_TABLE_WBARRIER);
3212                 wbarrier->sreg1 = ptr->dreg;
3213                 wbarrier->sreg2 = value->dreg;
3214                 MONO_ADD_INS (cfg->cbb, wbarrier);
3215         } else if (card_table && !cfg->compile_aot && !mono_gc_card_table_nursery_check ()) {
3216                 int offset_reg = alloc_preg (cfg);
3217                 int card_reg;
3218                 MonoInst *ins;
3219
3220                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, offset_reg, ptr->dreg, card_table_shift_bits);
3221                 if (card_table_mask)
3222                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, offset_reg, offset_reg, card_table_mask);
3223
3224                 /*We can't use PADD_IMM since the cardtable might end up in high addresses and amd64 doesn't support
3225                  * IMM's larger than 32bits.
3226                  */
3227                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
3228                 card_reg = ins->dreg;
3229
3230                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, offset_reg, offset_reg, card_reg);
3231                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, offset_reg, 0, 1);
3232         } else {
3233                 MonoMethod *write_barrier = mono_gc_get_write_barrier ();
3234                 mono_emit_method_call (cfg, write_barrier, &ptr, NULL);
3235         }
3236
3237         EMIT_NEW_DUMMY_USE (cfg, dummy_use, value);
3238 }
3239
3240 static gboolean
3241 mono_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align)
3242 {
3243         int dest_ptr_reg, tmp_reg, destreg, srcreg, offset;
3244         unsigned need_wb = 0;
3245
3246         if (align == 0)
3247                 align = 4;
3248
3249         /*types with references can't have alignment smaller than sizeof(void*) */
3250         if (align < SIZEOF_VOID_P)
3251                 return FALSE;
3252
3253         /*This value cannot be bigger than 32 due to the way we calculate the required wb bitmap.*/
3254         if (size > 32 * SIZEOF_VOID_P)
3255                 return FALSE;
3256
3257         create_write_barrier_bitmap (cfg, klass, &need_wb, 0);
3258
3259         /* We don't unroll more than 5 stores to avoid code bloat. */
3260         if (size > 5 * SIZEOF_VOID_P) {
3261                 /*This is harmless and simplify mono_gc_wbarrier_value_copy_bitmap */
3262                 size += (SIZEOF_VOID_P - 1);
3263                 size &= ~(SIZEOF_VOID_P - 1);
3264
3265                 EMIT_NEW_ICONST (cfg, iargs [2], size);
3266                 EMIT_NEW_ICONST (cfg, iargs [3], need_wb);
3267                 mono_emit_jit_icall (cfg, mono_gc_wbarrier_value_copy_bitmap, iargs);
3268                 return TRUE;
3269         }
3270
3271         destreg = iargs [0]->dreg;
3272         srcreg = iargs [1]->dreg;
3273         offset = 0;
3274
3275         dest_ptr_reg = alloc_preg (cfg);
3276         tmp_reg = alloc_preg (cfg);
3277
3278         /*tmp = dreg*/
3279         EMIT_NEW_UNALU (cfg, iargs [0], OP_MOVE, dest_ptr_reg, destreg);
3280
3281         while (size >= SIZEOF_VOID_P) {
3282                 MonoInst *load_inst;
3283                 MONO_INST_NEW (cfg, load_inst, OP_LOAD_MEMBASE);
3284                 load_inst->dreg = tmp_reg;
3285                 load_inst->inst_basereg = srcreg;
3286                 load_inst->inst_offset = offset;
3287                 MONO_ADD_INS (cfg->cbb, load_inst);
3288
3289                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, dest_ptr_reg, 0, tmp_reg);
3290
3291                 if (need_wb & 0x1)
3292                         emit_write_barrier (cfg, iargs [0], load_inst);
3293
3294                 offset += SIZEOF_VOID_P;
3295                 size -= SIZEOF_VOID_P;
3296                 need_wb >>= 1;
3297
3298                 /*tmp += sizeof (void*)*/
3299                 if (size >= SIZEOF_VOID_P) {
3300                         NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dest_ptr_reg, dest_ptr_reg, SIZEOF_VOID_P);
3301                         MONO_ADD_INS (cfg->cbb, iargs [0]);
3302                 }
3303         }
3304
3305         /* Those cannot be references since size < sizeof (void*) */
3306         while (size >= 4) {
3307                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tmp_reg, srcreg, offset);
3308                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, tmp_reg);
3309                 offset += 4;
3310                 size -= 4;
3311         }
3312
3313         while (size >= 2) {
3314                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmp_reg, srcreg, offset);
3315                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, tmp_reg);
3316                 offset += 2;
3317                 size -= 2;
3318         }
3319
3320         while (size >= 1) {
3321                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmp_reg, srcreg, offset);
3322                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, tmp_reg);
3323                 offset += 1;
3324                 size -= 1;
3325         }
3326
3327         return TRUE;
3328 }
3329
3330 /*
3331  * Emit code to copy a valuetype of type @klass whose address is stored in
3332  * @src->dreg to memory whose address is stored at @dest->dreg.
3333  */
3334 void
3335 mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native)
3336 {
3337         MonoInst *iargs [4];
3338         int n;
3339         guint32 align = 0;
3340         MonoMethod *memcpy_method;
3341         MonoInst *size_ins = NULL;
3342         MonoInst *memcpy_ins = NULL;
3343
3344         g_assert (klass);
3345         if (cfg->gshared)
3346                 klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg));
3347
3348         /*
3349          * This check breaks with spilled vars... need to handle it during verification anyway.
3350          * g_assert (klass && klass == src->klass && klass == dest->klass);
3351          */
3352
3353         if (mini_is_gsharedvt_klass (klass)) {
3354                 g_assert (!native);
3355                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3356                 memcpy_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_MEMCPY);
3357         }
3358
3359         if (native)
3360                 n = mono_class_native_size (klass, &align);
3361         else
3362                 n = mono_class_value_size (klass, &align);
3363
3364         /* if native is true there should be no references in the struct */
3365         if (cfg->gen_write_barriers && (klass->has_references || size_ins) && !native) {
3366                 /* Avoid barriers when storing to the stack */
3367                 if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) ||
3368                           (dest->opcode == OP_LDADDR))) {
3369                         int context_used;
3370
3371                         iargs [0] = dest;
3372                         iargs [1] = src;
3373
3374                         context_used = mini_class_check_context_used (cfg, klass);
3375
3376                         /* It's ok to intrinsify under gsharing since shared code types are layout stable. */
3377                         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && mono_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
3378                                 return;
3379                         } else if (context_used) {
3380                                 iargs [2] = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3381                         }  else {
3382                                 iargs [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
3383                                 if (!cfg->compile_aot)
3384                                         mono_class_compute_gc_descriptor (klass);
3385                         }
3386
3387                         if (size_ins)
3388                                 mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs);
3389                         else
3390                                 mono_emit_jit_icall (cfg, mono_value_copy, iargs);
3391                         return;
3392                 }
3393         }
3394
3395         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 8) {
3396                 /* FIXME: Optimize the case when src/dest is OP_LDADDR */
3397                 mini_emit_memcpy (cfg, dest->dreg, 0, src->dreg, 0, n, align);
3398         } else {
3399                 iargs [0] = dest;
3400                 iargs [1] = src;
3401                 if (size_ins)
3402                         iargs [2] = size_ins;
3403                 else
3404                         EMIT_NEW_ICONST (cfg, iargs [2], n);
3405                 
3406                 memcpy_method = get_memcpy_method ();
3407                 if (memcpy_ins)
3408                         mono_emit_calli (cfg, mono_method_signature (memcpy_method), iargs, memcpy_ins, NULL, NULL);
3409                 else
3410                         mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
3411         }
3412 }
3413
3414 static MonoMethod*
3415 get_memset_method (void)
3416 {
3417         static MonoMethod *memset_method = NULL;
3418         if (!memset_method) {
3419                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
3420                 if (!memset_method)
3421                         g_error ("Old corlib found. Install a new one");
3422         }
3423         return memset_method;
3424 }
3425
3426 void
3427 mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass)
3428 {
3429         MonoInst *iargs [3];
3430         int n;
3431         guint32 align;
3432         MonoMethod *memset_method;
3433         MonoInst *size_ins = NULL;
3434         MonoInst *bzero_ins = NULL;
3435         static MonoMethod *bzero_method;
3436
3437         /* FIXME: Optimize this for the case when dest is an LDADDR */
3438         mono_class_init (klass);
3439         if (mini_is_gsharedvt_klass (klass)) {
3440                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3441                 bzero_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_BZERO);
3442                 if (!bzero_method)
3443                         bzero_method = mono_class_get_method_from_name (mono_defaults.string_class, "bzero_aligned_1", 2);
3444                 g_assert (bzero_method);
3445                 iargs [0] = dest;
3446                 iargs [1] = size_ins;
3447                 mono_emit_calli (cfg, mono_method_signature (bzero_method), iargs, bzero_ins, NULL, NULL);
3448                 return;
3449         }
3450
3451         klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg));
3452
3453         n = mono_class_value_size (klass, &align);
3454
3455         if (n <= sizeof (gpointer) * 8) {
3456                 mini_emit_memset (cfg, dest->dreg, 0, n, 0, align);
3457         }
3458         else {
3459                 memset_method = get_memset_method ();
3460                 iargs [0] = dest;
3461                 EMIT_NEW_ICONST (cfg, iargs [1], 0);
3462                 EMIT_NEW_ICONST (cfg, iargs [2], n);
3463                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
3464         }
3465 }
3466
3467 /*
3468  * emit_get_rgctx:
3469  *
3470  *   Emit IR to return either the this pointer for instance method,
3471  * or the mrgctx for static methods.
3472  */
3473 static MonoInst*
3474 emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used)
3475 {
3476         MonoInst *this_ins = NULL;
3477
3478         g_assert (cfg->gshared);
3479
3480         if (!(method->flags & METHOD_ATTRIBUTE_STATIC) &&
3481                         !(context_used & MONO_GENERIC_CONTEXT_USED_METHOD) &&
3482                         !method->klass->valuetype)
3483                 EMIT_NEW_ARGLOAD (cfg, this_ins, 0);
3484
3485         if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
3486                 MonoInst *mrgctx_loc, *mrgctx_var;
3487
3488                 g_assert (!this_ins);
3489                 g_assert (method->is_inflated && mono_method_get_context (method)->method_inst);
3490
3491                 mrgctx_loc = mono_get_vtable_var (cfg);
3492                 EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
3493
3494                 return mrgctx_var;
3495         } else if (method->flags & METHOD_ATTRIBUTE_STATIC || method->klass->valuetype) {
3496                 MonoInst *vtable_loc, *vtable_var;
3497
3498                 g_assert (!this_ins);
3499
3500                 vtable_loc = mono_get_vtable_var (cfg);
3501                 EMIT_NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
3502
3503                 if (method->is_inflated && mono_method_get_context (method)->method_inst) {
3504                         MonoInst *mrgctx_var = vtable_var;
3505                         int vtable_reg;
3506
3507                         vtable_reg = alloc_preg (cfg);
3508                         EMIT_NEW_LOAD_MEMBASE (cfg, vtable_var, OP_LOAD_MEMBASE, vtable_reg, mrgctx_var->dreg, MONO_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, class_vtable));
3509                         vtable_var->type = STACK_PTR;
3510                 }
3511
3512                 return vtable_var;
3513         } else {
3514                 MonoInst *ins;
3515                 int vtable_reg;
3516         
3517                 vtable_reg = alloc_preg (cfg);
3518                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, vtable_reg, this_ins->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3519                 return ins;
3520         }
3521 }
3522
3523 static MonoJumpInfoRgctxEntry *
3524 mono_patch_info_rgctx_entry_new (MonoMemPool *mp, MonoMethod *method, gboolean in_mrgctx, MonoJumpInfoType patch_type, gconstpointer patch_data, MonoRgctxInfoType info_type)
3525 {
3526         MonoJumpInfoRgctxEntry *res = (MonoJumpInfoRgctxEntry *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoRgctxEntry));
3527         res->method = method;
3528         res->in_mrgctx = in_mrgctx;
3529         res->data = (MonoJumpInfo *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
3530         res->data->type = patch_type;
3531         res->data->data.target = patch_data;
3532         res->info_type = info_type;
3533
3534         return res;
3535 }
3536
3537 static inline MonoInst*
3538 emit_rgctx_fetch_inline (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3539 {
3540         MonoInst *args [16];
3541         MonoInst *call;
3542
3543         // FIXME: No fastpath since the slot is not a compile time constant
3544         args [0] = rgctx;
3545         EMIT_NEW_AOTCONST (cfg, args [1], MONO_PATCH_INFO_RGCTX_SLOT_INDEX, entry);
3546         if (entry->in_mrgctx)
3547                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3548         else
3549                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3550         return call;
3551 #if 0
3552         /*
3553          * FIXME: This can be called during decompose, which is a problem since it creates
3554          * new bblocks.
3555          * Also, the fastpath doesn't work since the slot number is dynamically allocated.
3556          */
3557         int i, slot, depth, index, rgctx_reg, val_reg, res_reg;
3558         gboolean mrgctx;
3559         MonoBasicBlock *is_null_bb, *end_bb;
3560         MonoInst *res, *ins, *call;
3561         MonoInst *args[16];
3562
3563         slot = mini_get_rgctx_entry_slot (entry);
3564
3565         mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot);
3566         index = MONO_RGCTX_SLOT_INDEX (slot);
3567         if (mrgctx)
3568                 index += MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
3569         for (depth = 0; ; ++depth) {
3570                 int size = mono_class_rgctx_get_array_size (depth, mrgctx);
3571
3572                 if (index < size - 1)
3573                         break;
3574                 index -= size - 1;
3575         }
3576
3577         NEW_BBLOCK (cfg, end_bb);
3578         NEW_BBLOCK (cfg, is_null_bb);
3579
3580         if (mrgctx) {
3581                 rgctx_reg = rgctx->dreg;
3582         } else {
3583                 rgctx_reg = alloc_preg (cfg);
3584
3585                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, rgctx_reg, rgctx->dreg, MONO_STRUCT_OFFSET (MonoVTable, runtime_generic_context));
3586                 // FIXME: Avoid this check by allocating the table when the vtable is created etc.
3587                 NEW_BBLOCK (cfg, is_null_bb);
3588
3589                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3590                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3591         }
3592
3593         for (i = 0; i < depth; ++i) {
3594                 int array_reg = alloc_preg (cfg);
3595
3596                 /* load ptr to next array */
3597                 if (mrgctx && i == 0)
3598                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT);
3599                 else
3600                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, 0);
3601                 rgctx_reg = array_reg;
3602                 /* is the ptr null? */
3603                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3604                 /* if yes, jump to actual trampoline */
3605                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3606         }
3607
3608         /* fetch slot */
3609         val_reg = alloc_preg (cfg);
3610         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, val_reg, rgctx_reg, (index + 1) * sizeof (gpointer));
3611         /* is the slot null? */
3612         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, val_reg, 0);
3613         /* if yes, jump to actual trampoline */
3614         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3615
3616         /* Fastpath */
3617         res_reg = alloc_preg (cfg);
3618         MONO_INST_NEW (cfg, ins, OP_MOVE);
3619         ins->dreg = res_reg;
3620         ins->sreg1 = val_reg;
3621         MONO_ADD_INS (cfg->cbb, ins);
3622         res = ins;
3623         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3624
3625         /* Slowpath */
3626         MONO_START_BB (cfg, is_null_bb);
3627         args [0] = rgctx;
3628         EMIT_NEW_ICONST (cfg, args [1], index);
3629         if (mrgctx)
3630                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3631         else
3632                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3633         MONO_INST_NEW (cfg, ins, OP_MOVE);
3634         ins->dreg = res_reg;
3635         ins->sreg1 = call->dreg;
3636         MONO_ADD_INS (cfg->cbb, ins);
3637         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3638
3639         MONO_START_BB (cfg, end_bb);
3640
3641         return res;
3642 #endif
3643 }
3644
3645 /*
3646  * emit_rgctx_fetch:
3647  *
3648  *   Emit IR to load the value of the rgctx entry ENTRY from the rgctx
3649  * given by RGCTX.
3650  */
3651 static inline MonoInst*
3652 emit_rgctx_fetch (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3653 {
3654         if (cfg->llvm_only)
3655                 return emit_rgctx_fetch_inline (cfg, rgctx, entry);
3656         else
3657                 return mono_emit_abs_call (cfg, MONO_PATCH_INFO_RGCTX_FETCH, entry, helper_sig_rgctx_lazy_fetch_trampoline, &rgctx);
3658 }
3659
3660 static MonoInst*
3661 emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
3662                                           MonoClass *klass, MonoRgctxInfoType rgctx_type)
3663 {
3664         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);
3665         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3666
3667         return emit_rgctx_fetch (cfg, rgctx, entry);
3668 }
3669
3670 static MonoInst*
3671 emit_get_rgctx_sig (MonoCompile *cfg, int context_used,
3672                                         MonoMethodSignature *sig, MonoRgctxInfoType rgctx_type)
3673 {
3674         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);
3675         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3676
3677         return emit_rgctx_fetch (cfg, rgctx, entry);
3678 }
3679
3680 static MonoInst*
3681 emit_get_rgctx_gsharedvt_call (MonoCompile *cfg, int context_used,
3682                                                            MonoMethodSignature *sig, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3683 {
3684         MonoJumpInfoGSharedVtCall *call_info;
3685         MonoJumpInfoRgctxEntry *entry;
3686         MonoInst *rgctx;
3687
3688         call_info = (MonoJumpInfoGSharedVtCall *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoGSharedVtCall));
3689         call_info->sig = sig;
3690         call_info->method = cmethod;
3691
3692         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);
3693         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3694
3695         return emit_rgctx_fetch (cfg, rgctx, entry);
3696 }
3697
3698 /*
3699  * emit_get_rgctx_virt_method:
3700  *
3701  *   Return data for method VIRT_METHOD for a receiver of type KLASS.
3702  */
3703 static MonoInst*
3704 emit_get_rgctx_virt_method (MonoCompile *cfg, int context_used,
3705                                                         MonoClass *klass, MonoMethod *virt_method, MonoRgctxInfoType rgctx_type)
3706 {
3707         MonoJumpInfoVirtMethod *info;
3708         MonoJumpInfoRgctxEntry *entry;
3709         MonoInst *rgctx;
3710
3711         info = (MonoJumpInfoVirtMethod *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoVirtMethod));
3712         info->klass = klass;
3713         info->method = virt_method;
3714
3715         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);
3716         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3717
3718         return emit_rgctx_fetch (cfg, rgctx, entry);
3719 }
3720
3721 static MonoInst*
3722 emit_get_rgctx_gsharedvt_method (MonoCompile *cfg, int context_used,
3723                                                                  MonoMethod *cmethod, MonoGSharedVtMethodInfo *info)
3724 {
3725         MonoJumpInfoRgctxEntry *entry;
3726         MonoInst *rgctx;
3727
3728         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);
3729         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3730
3731         return emit_rgctx_fetch (cfg, rgctx, entry);
3732 }
3733
3734 /*
3735  * emit_get_rgctx_method:
3736  *
3737  *   Emit IR to load the property RGCTX_TYPE of CMETHOD. If context_used is 0, emit
3738  * normal constants, else emit a load from the rgctx.
3739  */
3740 static MonoInst*
3741 emit_get_rgctx_method (MonoCompile *cfg, int context_used,
3742                                            MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3743 {
3744         if (!context_used) {
3745                 MonoInst *ins;
3746
3747                 switch (rgctx_type) {
3748                 case MONO_RGCTX_INFO_METHOD:
3749                         EMIT_NEW_METHODCONST (cfg, ins, cmethod);
3750                         return ins;
3751                 case MONO_RGCTX_INFO_METHOD_RGCTX:
3752                         EMIT_NEW_METHOD_RGCTX_CONST (cfg, ins, cmethod);
3753                         return ins;
3754                 default:
3755                         g_assert_not_reached ();
3756                 }
3757         } else {
3758                 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);
3759                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3760
3761                 return emit_rgctx_fetch (cfg, rgctx, entry);
3762         }
3763 }
3764
3765 static MonoInst*
3766 emit_get_rgctx_field (MonoCompile *cfg, int context_used,
3767                                           MonoClassField *field, MonoRgctxInfoType rgctx_type)
3768 {
3769         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);
3770         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3771
3772         return emit_rgctx_fetch (cfg, rgctx, entry);
3773 }
3774
3775 static int
3776 get_gsharedvt_info_slot (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3777 {
3778         MonoGSharedVtMethodInfo *info = cfg->gsharedvt_info;
3779         MonoRuntimeGenericContextInfoTemplate *template_;
3780         int i, idx;
3781
3782         g_assert (info);
3783
3784         for (i = 0; i < info->num_entries; ++i) {
3785                 MonoRuntimeGenericContextInfoTemplate *otemplate = &info->entries [i];
3786
3787                 if (otemplate->info_type == rgctx_type && otemplate->data == data && rgctx_type != MONO_RGCTX_INFO_LOCAL_OFFSET)
3788                         return i;
3789         }
3790
3791         if (info->num_entries == info->count_entries) {
3792                 MonoRuntimeGenericContextInfoTemplate *new_entries;
3793                 int new_count_entries = info->count_entries ? info->count_entries * 2 : 16;
3794
3795                 new_entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * new_count_entries);
3796
3797                 memcpy (new_entries, info->entries, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
3798                 info->entries = new_entries;
3799                 info->count_entries = new_count_entries;
3800         }
3801
3802         idx = info->num_entries;
3803         template_ = &info->entries [idx];
3804         template_->info_type = rgctx_type;
3805         template_->data = data;
3806
3807         info->num_entries ++;
3808
3809         return idx;
3810 }
3811
3812 /*
3813  * emit_get_gsharedvt_info:
3814  *
3815  *   This is similar to emit_get_rgctx_.., but loads the data from the gsharedvt info var instead of calling an rgctx fetch trampoline.
3816  */
3817 static MonoInst*
3818 emit_get_gsharedvt_info (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3819 {
3820         MonoInst *ins;
3821         int idx, dreg;
3822
3823         idx = get_gsharedvt_info_slot (cfg, data, rgctx_type);
3824         /* Load info->entries [idx] */
3825         dreg = alloc_preg (cfg);
3826         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, cfg->gsharedvt_info_var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
3827
3828         return ins;
3829 }
3830
3831 static MonoInst*
3832 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type)
3833 {
3834         return emit_get_gsharedvt_info (cfg, &klass->byval_arg, rgctx_type);
3835 }
3836
3837 /*
3838  * On return the caller must check @klass for load errors.
3839  */
3840 static void
3841 emit_class_init (MonoCompile *cfg, MonoClass *klass)
3842 {
3843         MonoInst *vtable_arg;
3844         int context_used;
3845
3846         context_used = mini_class_check_context_used (cfg, klass);
3847
3848         if (context_used) {
3849                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
3850                                                                                    klass, MONO_RGCTX_INFO_VTABLE);
3851         } else {
3852                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3853
3854                 if (!vtable)
3855                         return;
3856                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
3857         }
3858
3859         if (!COMPILE_LLVM (cfg) && cfg->backend->have_op_generic_class_init) {
3860                 MonoInst *ins;
3861
3862                 /*
3863                  * Using an opcode instead of emitting IR here allows the hiding of the call inside the opcode,
3864                  * so this doesn't have to clobber any regs and it doesn't break basic blocks.
3865                  */
3866                 MONO_INST_NEW (cfg, ins, OP_GENERIC_CLASS_INIT);
3867                 ins->sreg1 = vtable_arg->dreg;
3868                 MONO_ADD_INS (cfg->cbb, ins);
3869         } else {
3870                 static int byte_offset = -1;
3871                 static guint8 bitmask;
3872                 int bits_reg, inited_reg;
3873                 MonoBasicBlock *inited_bb;
3874                 MonoInst *args [16];
3875
3876                 if (byte_offset < 0)
3877                         mono_marshal_find_bitfield_offset (MonoVTable, initialized, &byte_offset, &bitmask);
3878
3879                 bits_reg = alloc_ireg (cfg);
3880                 inited_reg = alloc_ireg (cfg);
3881
3882                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, bits_reg, vtable_arg->dreg, byte_offset);
3883                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, inited_reg, bits_reg, bitmask);
3884
3885                 NEW_BBLOCK (cfg, inited_bb);
3886
3887                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, inited_reg, 0);
3888                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, inited_bb);
3889
3890                 args [0] = vtable_arg;
3891                 mono_emit_jit_icall (cfg, mono_generic_class_init, args);
3892
3893                 MONO_START_BB (cfg, inited_bb);
3894         }
3895 }
3896
3897 static void
3898 emit_seq_point (MonoCompile *cfg, MonoMethod *method, guint8* ip, gboolean intr_loc, gboolean nonempty_stack)
3899 {
3900         MonoInst *ins;
3901
3902         if (cfg->gen_seq_points && cfg->method == method) {
3903                 NEW_SEQ_POINT (cfg, ins, ip - cfg->header->code, intr_loc);
3904                 if (nonempty_stack)
3905                         ins->flags |= MONO_INST_NONEMPTY_STACK;
3906                 MONO_ADD_INS (cfg->cbb, ins);
3907         }
3908 }
3909
3910 static void
3911 save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean null_check)
3912 {
3913         if (mini_get_debug_options ()->better_cast_details) {
3914                 int vtable_reg = alloc_preg (cfg);
3915                 int klass_reg = alloc_preg (cfg);
3916                 MonoBasicBlock *is_null_bb = NULL;
3917                 MonoInst *tls_get;
3918                 int to_klass_reg, context_used;
3919
3920                 if (null_check) {
3921                         NEW_BBLOCK (cfg, is_null_bb);
3922
3923                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3924                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3925                 }
3926
3927                 tls_get = mono_get_jit_tls_intrinsic (cfg);
3928                 if (!tls_get) {
3929                         fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
3930                         exit (1);
3931                 }
3932
3933                 MONO_ADD_INS (cfg->cbb, tls_get);
3934                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3935                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3936
3937                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg);
3938
3939                 context_used = mini_class_check_context_used (cfg, klass);
3940                 if (context_used) {
3941                         MonoInst *class_ins;
3942
3943                         class_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3944                         to_klass_reg = class_ins->dreg;
3945                 } else {
3946                         to_klass_reg = alloc_preg (cfg);
3947                         MONO_EMIT_NEW_CLASSCONST (cfg, to_klass_reg, klass);
3948                 }
3949                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg);
3950
3951                 if (null_check)
3952                         MONO_START_BB (cfg, is_null_bb);
3953         }
3954 }
3955
3956 static void
3957 reset_cast_details (MonoCompile *cfg)
3958 {
3959         /* Reset the variables holding the cast details */
3960         if (mini_get_debug_options ()->better_cast_details) {
3961                 MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
3962
3963                 MONO_ADD_INS (cfg->cbb, tls_get);
3964                 /* It is enough to reset the from field */
3965                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0);
3966         }
3967 }
3968
3969 /*
3970  * On return the caller must check @array_class for load errors
3971  */
3972 static void
3973 mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_class)
3974 {
3975         int vtable_reg = alloc_preg (cfg);
3976         int context_used;
3977
3978         context_used = mini_class_check_context_used (cfg, array_class);
3979
3980         save_cast_details (cfg, array_class, obj->dreg, FALSE);
3981
3982         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3983
3984         if (cfg->opt & MONO_OPT_SHARED) {
3985                 int class_reg = alloc_preg (cfg);
3986                 MonoInst *ins;
3987
3988                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, class_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3989                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, array_class);
3990                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, class_reg, ins->dreg);
3991         } else if (context_used) {
3992                 MonoInst *vtable_ins;
3993
3994                 vtable_ins = emit_get_rgctx_klass (cfg, context_used, array_class, MONO_RGCTX_INFO_VTABLE);
3995                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vtable_ins->dreg);
3996         } else {
3997                 if (cfg->compile_aot) {
3998                         int vt_reg;
3999                         MonoVTable *vtable;
4000
4001                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
4002                                 return;
4003                         vt_reg = alloc_preg (cfg);
4004                         MONO_EMIT_NEW_VTABLECONST (cfg, vt_reg, vtable);
4005                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vt_reg);
4006                 } else {
4007                         MonoVTable *vtable;
4008                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
4009                                 return;
4010                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vtable);
4011                 }
4012         }
4013         
4014         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException");
4015
4016         reset_cast_details (cfg);
4017 }
4018
4019 /**
4020  * Handles unbox of a Nullable<T>. If context_used is non zero, then shared 
4021  * generic code is generated.
4022  */
4023 static MonoInst*
4024 handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int context_used)
4025 {
4026         MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
4027
4028         if (context_used) {
4029                 MonoInst *rgctx, *addr;
4030
4031                 /* FIXME: What if the class is shared?  We might not
4032                    have to get the address of the method from the
4033                    RGCTX. */
4034                 addr = emit_get_rgctx_method (cfg, context_used, method,
4035                                                                           MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4036                 if (cfg->llvm_only && cfg->gsharedvt) {
4037                         return emit_llvmonly_calli (cfg, mono_method_signature (method), &val, addr);
4038                 } else {
4039                         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
4040
4041                         return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
4042                 }
4043         } else {
4044                 gboolean pass_vtable, pass_mrgctx;
4045                 MonoInst *rgctx_arg = NULL;
4046
4047                 check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
4048                 g_assert (!pass_mrgctx);
4049
4050                 if (pass_vtable) {
4051                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4052
4053                         g_assert (vtable);
4054                         EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
4055                 }
4056
4057                 return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4058         }
4059 }
4060
4061 static MonoInst*
4062 handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_used)
4063 {
4064         MonoInst *add;
4065         int obj_reg;
4066         int vtable_reg = alloc_dreg (cfg ,STACK_PTR);
4067         int klass_reg = alloc_dreg (cfg ,STACK_PTR);
4068         int eclass_reg = alloc_dreg (cfg ,STACK_PTR);
4069         int rank_reg = alloc_dreg (cfg ,STACK_I4);
4070
4071         obj_reg = sp [0]->dreg;
4072         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4073         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
4074
4075         /* FIXME: generics */
4076         g_assert (klass->rank == 0);
4077                         
4078         // Check rank == 0
4079         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, 0);
4080         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4081
4082         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4083         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, element_class));
4084
4085         if (context_used) {
4086                 MonoInst *element_class;
4087
4088                 /* This assertion is from the unboxcast insn */
4089                 g_assert (klass->rank == 0);
4090
4091                 element_class = emit_get_rgctx_klass (cfg, context_used,
4092                                 klass, MONO_RGCTX_INFO_ELEMENT_KLASS);
4093
4094                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, eclass_reg, element_class->dreg);
4095                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4096         } else {
4097                 save_cast_details (cfg, klass->element_class, obj_reg, FALSE);
4098                 mini_emit_class_check (cfg, eclass_reg, klass->element_class);
4099                 reset_cast_details (cfg);
4100         }
4101
4102         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), obj_reg, sizeof (MonoObject));
4103         MONO_ADD_INS (cfg->cbb, add);
4104         add->type = STACK_MP;
4105         add->klass = klass;
4106
4107         return add;
4108 }
4109
4110 static MonoInst*
4111 handle_unbox_gsharedvt (MonoCompile *cfg, MonoClass *klass, MonoInst *obj)
4112 {
4113         MonoInst *addr, *klass_inst, *is_ref, *args[16];
4114         MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4115         MonoInst *ins;
4116         int dreg, addr_reg;
4117
4118         klass_inst = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_KLASS);
4119
4120         /* obj */
4121         args [0] = obj;
4122
4123         /* klass */
4124         args [1] = klass_inst;
4125
4126         /* CASTCLASS */
4127         obj = mono_emit_jit_icall (cfg, mono_object_castclass_unbox, args);
4128
4129         NEW_BBLOCK (cfg, is_ref_bb);
4130         NEW_BBLOCK (cfg, is_nullable_bb);
4131         NEW_BBLOCK (cfg, end_bb);
4132         is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4133         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
4134         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4135
4136         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
4137         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4138
4139         /* This will contain either the address of the unboxed vtype, or an address of the temporary where the ref is stored */
4140         addr_reg = alloc_dreg (cfg, STACK_MP);
4141
4142         /* Non-ref case */
4143         /* UNBOX */
4144         NEW_BIALU_IMM (cfg, addr, OP_ADD_IMM, addr_reg, obj->dreg, sizeof (MonoObject));
4145         MONO_ADD_INS (cfg->cbb, addr);
4146
4147         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4148
4149         /* Ref case */
4150         MONO_START_BB (cfg, is_ref_bb);
4151
4152         /* Save the ref to a temporary */
4153         dreg = alloc_ireg (cfg);
4154         EMIT_NEW_VARLOADA_VREG (cfg, addr, dreg, &klass->byval_arg);
4155         addr->dreg = addr_reg;
4156         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, obj->dreg);
4157         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4158
4159         /* Nullable case */
4160         MONO_START_BB (cfg, is_nullable_bb);
4161
4162         {
4163                 MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX);
4164                 MonoInst *unbox_call;
4165                 MonoMethodSignature *unbox_sig;
4166
4167                 unbox_sig = (MonoMethodSignature *)mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4168                 unbox_sig->ret = &klass->byval_arg;
4169                 unbox_sig->param_count = 1;
4170                 unbox_sig->params [0] = &mono_defaults.object_class->byval_arg;
4171
4172                 if (cfg->llvm_only)
4173                         unbox_call = emit_llvmonly_calli (cfg, unbox_sig, &obj, addr);
4174                 else
4175                         unbox_call = mono_emit_calli (cfg, unbox_sig, &obj, addr, NULL, NULL);
4176
4177                 EMIT_NEW_VARLOADA_VREG (cfg, addr, unbox_call->dreg, &klass->byval_arg);
4178                 addr->dreg = addr_reg;
4179         }
4180
4181         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4182
4183         /* End */
4184         MONO_START_BB (cfg, end_bb);
4185
4186         /* LDOBJ */
4187         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr_reg, 0);
4188
4189         return ins;
4190 }
4191
4192 /*
4193  * Returns NULL and set the cfg exception on error.
4194  */
4195 static MonoInst*
4196 handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_used)
4197 {
4198         MonoInst *iargs [2];
4199         void *alloc_ftn;
4200
4201         if (context_used) {
4202                 MonoInst *data;
4203                 MonoRgctxInfoType rgctx_info;
4204                 MonoInst *iargs [2];
4205                 gboolean known_instance_size = !mini_is_gsharedvt_klass (klass);
4206
4207                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (klass, for_box, known_instance_size);
4208
4209                 if (cfg->opt & MONO_OPT_SHARED)
4210                         rgctx_info = MONO_RGCTX_INFO_KLASS;
4211                 else
4212                         rgctx_info = MONO_RGCTX_INFO_VTABLE;
4213                 data = emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
4214
4215                 if (cfg->opt & MONO_OPT_SHARED) {
4216                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4217                         iargs [1] = data;
4218                         alloc_ftn = ves_icall_object_new;
4219                 } else {
4220                         iargs [0] = data;
4221                         alloc_ftn = ves_icall_object_new_specific;
4222                 }
4223
4224                 if (managed_alloc && !(cfg->opt & MONO_OPT_SHARED)) {
4225                         if (known_instance_size) {
4226                                 int size = mono_class_instance_size (klass);
4227                                 if (size < sizeof (MonoObject))
4228                                         g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4229
4230                                 EMIT_NEW_ICONST (cfg, iargs [1], size);
4231                         }
4232                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4233                 }
4234
4235                 return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4236         }
4237
4238         if (cfg->opt & MONO_OPT_SHARED) {
4239                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4240                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
4241
4242                 alloc_ftn = ves_icall_object_new;
4243         } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !klass->generic_class) {
4244                 /* This happens often in argument checking code, eg. throw new FooException... */
4245                 /* Avoid relocations and save some space by calling a helper function specialized to mscorlib */
4246                 EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
4247                 return mono_emit_jit_icall (cfg, mono_helper_newobj_mscorlib, iargs);
4248         } else {
4249                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
4250                 MonoMethod *managed_alloc = NULL;
4251                 gboolean pass_lw;
4252
4253                 if (!vtable) {
4254                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4255                         cfg->exception_ptr = klass;
4256                         return NULL;
4257                 }
4258
4259                 managed_alloc = mono_gc_get_managed_allocator (klass, for_box, TRUE);
4260
4261                 if (managed_alloc) {
4262                         int size = mono_class_instance_size (klass);
4263                         if (size < sizeof (MonoObject))
4264                                 g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4265
4266                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4267                         EMIT_NEW_ICONST (cfg, iargs [1], size);
4268                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4269                 }
4270                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
4271                 if (pass_lw) {
4272                         guint32 lw = vtable->klass->instance_size;
4273                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
4274                         EMIT_NEW_ICONST (cfg, iargs [0], lw);
4275                         EMIT_NEW_VTABLECONST (cfg, iargs [1], vtable);
4276                 }
4277                 else {
4278                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4279                 }
4280         }
4281
4282         return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4283 }
4284         
4285 /*
4286  * Returns NULL and set the cfg exception on error.
4287  */     
4288 static MonoInst*
4289 handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used)
4290 {
4291         MonoInst *alloc, *ins;
4292
4293         if (mono_class_is_nullable (klass)) {
4294                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
4295
4296                 if (context_used) {
4297                         if (cfg->llvm_only && cfg->gsharedvt) {
4298                                 MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4299                                                                                                                 MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4300                                 return emit_llvmonly_calli (cfg, mono_method_signature (method), &val, addr);
4301                         } else {
4302                                 /* FIXME: What if the class is shared?  We might not
4303                                    have to get the method address from the RGCTX. */
4304                                 MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4305                                                                                                                 MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4306                                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
4307
4308                                 return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
4309                         }
4310                 } else {
4311                         gboolean pass_vtable, pass_mrgctx;
4312                         MonoInst *rgctx_arg = NULL;
4313
4314                         check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
4315                         g_assert (!pass_mrgctx);
4316
4317                         if (pass_vtable) {
4318                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4319
4320                                 g_assert (vtable);
4321                                 EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
4322                         }
4323
4324                         return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4325                 }
4326         }
4327
4328         if (mini_is_gsharedvt_klass (klass)) {
4329                 MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4330                 MonoInst *res, *is_ref, *src_var, *addr;
4331                 int dreg;
4332
4333                 dreg = alloc_ireg (cfg);
4334
4335                 NEW_BBLOCK (cfg, is_ref_bb);
4336                 NEW_BBLOCK (cfg, is_nullable_bb);
4337                 NEW_BBLOCK (cfg, end_bb);
4338                 is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4339                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
4340                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4341
4342                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
4343                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4344
4345                 /* Non-ref case */
4346                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4347                 if (!alloc)
4348                         return NULL;
4349                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4350                 ins->opcode = OP_STOREV_MEMBASE;
4351
4352                 EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, alloc->dreg);
4353                 res->type = STACK_OBJ;
4354                 res->klass = klass;
4355                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4356                 
4357                 /* Ref case */
4358                 MONO_START_BB (cfg, is_ref_bb);
4359
4360                 /* val is a vtype, so has to load the value manually */
4361                 src_var = get_vreg_to_inst (cfg, val->dreg);
4362                 if (!src_var)
4363                         src_var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, val->dreg);
4364                 EMIT_NEW_VARLOADA (cfg, addr, src_var, src_var->inst_vtype);
4365                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, addr->dreg, 0);
4366                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4367
4368                 /* Nullable case */
4369                 MONO_START_BB (cfg, is_nullable_bb);
4370
4371                 {
4372                         MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass,
4373                                                                                                         MONO_RGCTX_INFO_NULLABLE_CLASS_BOX);
4374                         MonoInst *box_call;
4375                         MonoMethodSignature *box_sig;
4376
4377                         /*
4378                          * klass is Nullable<T>, need to call Nullable<T>.Box () using a gsharedvt signature, but we cannot
4379                          * construct that method at JIT time, so have to do things by hand.
4380                          */
4381                         box_sig = (MonoMethodSignature *)mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4382                         box_sig->ret = &mono_defaults.object_class->byval_arg;
4383                         box_sig->param_count = 1;
4384                         box_sig->params [0] = &klass->byval_arg;
4385
4386                         if (cfg->llvm_only)
4387                                 box_call = emit_llvmonly_calli (cfg, box_sig, &val, addr);
4388                         else
4389                                 box_call = mono_emit_calli (cfg, box_sig, &val, addr, NULL, NULL);
4390                         EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, box_call->dreg);
4391                         res->type = STACK_OBJ;
4392                         res->klass = klass;
4393                 }
4394
4395                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4396
4397                 MONO_START_BB (cfg, end_bb);
4398
4399                 return res;
4400         } else {
4401                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4402                 if (!alloc)
4403                         return NULL;
4404
4405                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4406                 return alloc;
4407         }
4408 }
4409
4410 static gboolean
4411 mini_class_has_reference_variant_generic_argument (MonoCompile *cfg, MonoClass *klass, int context_used)
4412 {
4413         int i;
4414         MonoGenericContainer *container;
4415         MonoGenericInst *ginst;
4416
4417         if (klass->generic_class) {
4418                 container = klass->generic_class->container_class->generic_container;
4419                 ginst = klass->generic_class->context.class_inst;
4420         } else if (klass->generic_container && context_used) {
4421                 container = klass->generic_container;
4422                 ginst = container->context.class_inst;
4423         } else {
4424                 return FALSE;
4425         }
4426
4427         for (i = 0; i < container->type_argc; ++i) {
4428                 MonoType *type;
4429                 if (!(mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT)))
4430                         continue;
4431                 type = ginst->type_argv [i];
4432                 if (mini_type_is_reference (type))
4433                         return TRUE;
4434         }
4435         return FALSE;
4436 }
4437
4438 static GHashTable* direct_icall_type_hash;
4439
4440 static gboolean
4441 icall_is_direct_callable (MonoCompile *cfg, MonoMethod *cmethod)
4442 {
4443         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
4444         if (!direct_icalls_enabled (cfg))
4445                 return FALSE;
4446
4447         /*
4448          * An icall is directly callable if it doesn't directly or indirectly call mono_raise_exception ().
4449          * Whitelist a few icalls for now.
4450          */
4451         if (!direct_icall_type_hash) {
4452                 GHashTable *h = g_hash_table_new (g_str_hash, g_str_equal);
4453
4454                 g_hash_table_insert (h, (char*)"Decimal", GUINT_TO_POINTER (1));
4455                 g_hash_table_insert (h, (char*)"Number", GUINT_TO_POINTER (1));
4456                 g_hash_table_insert (h, (char*)"Buffer", GUINT_TO_POINTER (1));
4457                 g_hash_table_insert (h, (char*)"Monitor", GUINT_TO_POINTER (1));
4458                 mono_memory_barrier ();
4459                 direct_icall_type_hash = h;
4460         }
4461
4462         if (cmethod->klass == mono_defaults.math_class)
4463                 return TRUE;
4464         /* No locking needed */
4465         if (cmethod->klass->image == mono_defaults.corlib && g_hash_table_lookup (direct_icall_type_hash, cmethod->klass->name))
4466                 return TRUE;
4467         return FALSE;
4468 }
4469
4470 #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)
4471
4472 static MonoInst*
4473 emit_castclass_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args)
4474 {
4475         MonoMethod *mono_castclass;
4476         MonoInst *res;
4477
4478         mono_castclass = mono_marshal_get_castclass_with_cache ();
4479
4480         save_cast_details (cfg, klass, args [0]->dreg, TRUE);
4481         res = mono_emit_method_call (cfg, mono_castclass, args, NULL);
4482         reset_cast_details (cfg);
4483
4484         return res;
4485 }
4486
4487 static int
4488 get_castclass_cache_idx (MonoCompile *cfg)
4489 {
4490         /* Each CASTCLASS_CACHE patch needs a unique index which identifies the call site */
4491         cfg->castclass_cache_index ++;
4492         return (cfg->method_index << 16) | cfg->castclass_cache_index;
4493 }
4494
4495 static MonoInst*
4496 emit_castclass_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass *klass)
4497 {
4498         MonoInst *args [3];
4499         int idx;
4500
4501         /* obj */
4502         args [0] = obj;
4503
4504         /* klass */
4505         EMIT_NEW_CLASSCONST (cfg, args [1], klass);
4506
4507         /* inline cache*/
4508         idx = get_castclass_cache_idx (cfg);
4509         args [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
4510
4511         /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
4512         return emit_castclass_with_cache (cfg, klass, args);
4513 }
4514
4515 /*
4516  * Returns NULL and set the cfg exception on error.
4517  */
4518 static MonoInst*
4519 handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, guint8 *ip, int *inline_costs)
4520 {
4521         MonoBasicBlock *is_null_bb;
4522         int obj_reg = src->dreg;
4523         int vtable_reg = alloc_preg (cfg);
4524         int context_used;
4525         MonoInst *klass_inst = NULL, *res;
4526
4527         if (src->opcode == OP_PCONST && src->inst_p0 == 0)
4528                 return src;
4529
4530         context_used = mini_class_check_context_used (cfg, klass);
4531
4532         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
4533                 res = emit_castclass_with_cache_nonshared (cfg, src, klass);
4534                 (*inline_costs) += 2;
4535                 return res;
4536         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
4537                 MonoMethod *mono_castclass;
4538                 MonoInst *iargs [1];
4539                 int costs;
4540
4541                 mono_castclass = mono_marshal_get_castclass (klass); 
4542                 iargs [0] = src;
4543                                 
4544                 save_cast_details (cfg, klass, src->dreg, TRUE);
4545                 costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
4546                                                            iargs, ip, cfg->real_offset, TRUE);
4547                 reset_cast_details (cfg);
4548                 CHECK_CFG_EXCEPTION;
4549                 g_assert (costs > 0);
4550                                 
4551                 cfg->real_offset += 5;
4552
4553                 (*inline_costs) += costs;
4554
4555                 return src;
4556         }
4557
4558         if (context_used) {
4559                 MonoInst *args [3];
4560
4561                 if (mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4562                         MonoInst *cache_ins;
4563
4564                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4565
4566                         /* obj */
4567                         args [0] = src;
4568
4569                         /* klass - it's the second element of the cache entry*/
4570                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4571
4572                         /* cache */
4573                         args [2] = cache_ins;
4574
4575                         return emit_castclass_with_cache (cfg, klass, args);
4576                 }
4577
4578                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4579         }
4580
4581         NEW_BBLOCK (cfg, is_null_bb);
4582
4583         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4584         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
4585
4586         save_cast_details (cfg, klass, obj_reg, FALSE);
4587
4588         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4589                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4590                 mini_emit_iface_cast (cfg, vtable_reg, klass, NULL, NULL);
4591         } else {
4592                 int klass_reg = alloc_preg (cfg);
4593
4594                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4595
4596                 if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4597                         /* the remoting code is broken, access the class for now */
4598                         if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4599                                 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4600                                 if (!vt) {
4601                                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4602                                         cfg->exception_ptr = klass;
4603                                         return NULL;
4604                                 }
4605                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4606                         } else {
4607                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4608                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4609                         }
4610                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4611                 } else {
4612                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4613                         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, klass_inst, is_null_bb);
4614                 }
4615         }
4616
4617         MONO_START_BB (cfg, is_null_bb);
4618
4619         reset_cast_details (cfg);
4620
4621         return src;
4622
4623 exception_exit:
4624         return NULL;
4625 }
4626
4627 /*
4628  * Returns NULL and set the cfg exception on error.
4629  */
4630 static MonoInst*
4631 handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
4632 {
4633         MonoInst *ins;
4634         MonoBasicBlock *is_null_bb, *false_bb, *end_bb;
4635         int obj_reg = src->dreg;
4636         int vtable_reg = alloc_preg (cfg);
4637         int res_reg = alloc_ireg_ref (cfg);
4638         MonoInst *klass_inst = NULL;
4639
4640         if (context_used) {
4641                 MonoInst *args [3];
4642
4643                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4644                         MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
4645                         MonoInst *cache_ins;
4646
4647                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4648
4649                         /* obj */
4650                         args [0] = src;
4651
4652                         /* klass - it's the second element of the cache entry*/
4653                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4654
4655                         /* cache */
4656                         args [2] = cache_ins;
4657
4658                         return mono_emit_method_call (cfg, mono_isinst, args, NULL);
4659                 }
4660
4661                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4662         }
4663
4664         NEW_BBLOCK (cfg, is_null_bb);
4665         NEW_BBLOCK (cfg, false_bb);
4666         NEW_BBLOCK (cfg, end_bb);
4667
4668         /* Do the assignment at the beginning, so the other assignment can be if converted */
4669         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, res_reg, obj_reg);
4670         ins->type = STACK_OBJ;
4671         ins->klass = klass;
4672
4673         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4674         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_null_bb);
4675
4676         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4677
4678         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4679                 g_assert (!context_used);
4680                 /* the is_null_bb target simply copies the input register to the output */
4681                 mini_emit_iface_cast (cfg, vtable_reg, klass, false_bb, is_null_bb);
4682         } else {
4683                 int klass_reg = alloc_preg (cfg);
4684
4685                 if (klass->rank) {
4686                         int rank_reg = alloc_preg (cfg);
4687                         int eclass_reg = alloc_preg (cfg);
4688
4689                         g_assert (!context_used);
4690                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
4691                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
4692                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4693                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4694                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
4695                         if (klass->cast_class == mono_defaults.object_class) {
4696                                 int parent_reg = alloc_preg (cfg);
4697                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
4698                                 mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, is_null_bb);
4699                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4700                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4701                         } else if (klass->cast_class == mono_defaults.enum_class->parent) {
4702                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, is_null_bb);
4703                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);                          
4704                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4705                         } else if (klass->cast_class == mono_defaults.enum_class) {
4706                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4707                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4708                         } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
4709                                 mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4710                         } else {
4711                                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY)) {
4712                                         /* Check that the object is a vector too */
4713                                         int bounds_reg = alloc_preg (cfg);
4714                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
4715                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
4716                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4717                                 }
4718
4719                                 /* the is_null_bb target simply copies the input register to the output */
4720                                 mini_emit_isninst_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4721                         }
4722                 } else if (mono_class_is_nullable (klass)) {
4723                         g_assert (!context_used);
4724                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4725                         /* the is_null_bb target simply copies the input register to the output */
4726                         mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb);
4727                 } else {
4728                         if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4729                                 g_assert (!context_used);
4730                                 /* the remoting code is broken, access the class for now */
4731                                 if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4732                                         MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4733                                         if (!vt) {
4734                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4735                                                 cfg->exception_ptr = klass;
4736                                                 return NULL;
4737                                         }
4738                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4739                                 } else {
4740                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4741                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4742                                 }
4743                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4744                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
4745                         } else {
4746                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4747                                 /* the is_null_bb target simply copies the input register to the output */
4748                                 mini_emit_isninst_cast_inst (cfg, klass_reg, klass, klass_inst, false_bb, is_null_bb);
4749                         }
4750                 }
4751         }
4752
4753         MONO_START_BB (cfg, false_bb);
4754
4755         MONO_EMIT_NEW_PCONST (cfg, res_reg, 0);
4756         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4757
4758         MONO_START_BB (cfg, is_null_bb);
4759
4760         MONO_START_BB (cfg, end_bb);
4761
4762         return ins;
4763 }
4764
4765 static MonoInst*
4766 handle_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4767 {
4768         /* This opcode takes as input an object reference and a class, and returns:
4769         0) if the object is an instance of the class,
4770         1) if the object is not instance of the class,
4771         2) if the object is a proxy whose type cannot be determined */
4772
4773         MonoInst *ins;
4774 #ifndef DISABLE_REMOTING
4775         MonoBasicBlock *true_bb, *false_bb, *false2_bb, *end_bb, *no_proxy_bb, *interface_fail_bb;
4776 #else
4777         MonoBasicBlock *true_bb, *false_bb, *end_bb;
4778 #endif
4779         int obj_reg = src->dreg;
4780         int dreg = alloc_ireg (cfg);
4781         int tmp_reg;
4782 #ifndef DISABLE_REMOTING
4783         int klass_reg = alloc_preg (cfg);
4784 #endif
4785
4786         NEW_BBLOCK (cfg, true_bb);
4787         NEW_BBLOCK (cfg, false_bb);
4788         NEW_BBLOCK (cfg, end_bb);
4789 #ifndef DISABLE_REMOTING
4790         NEW_BBLOCK (cfg, false2_bb);
4791         NEW_BBLOCK (cfg, no_proxy_bb);
4792 #endif
4793
4794         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4795         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
4796
4797         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4798 #ifndef DISABLE_REMOTING
4799                 NEW_BBLOCK (cfg, interface_fail_bb);
4800 #endif
4801
4802                 tmp_reg = alloc_preg (cfg);
4803                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4804 #ifndef DISABLE_REMOTING
4805                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, true_bb);
4806                 MONO_START_BB (cfg, interface_fail_bb);
4807                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4808                 
4809                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, false_bb);
4810
4811                 tmp_reg = alloc_preg (cfg);
4812                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4813                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4814                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false2_bb);                
4815 #else
4816                 mini_emit_iface_cast (cfg, tmp_reg, klass, false_bb, true_bb);
4817 #endif
4818         } else {
4819 #ifndef DISABLE_REMOTING
4820                 tmp_reg = alloc_preg (cfg);
4821                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4822                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4823
4824                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4825                 tmp_reg = alloc_preg (cfg);
4826                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4827                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4828
4829                 tmp_reg = alloc_preg (cfg);             
4830                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4831                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4832                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4833                 
4834                 mini_emit_isninst_cast (cfg, klass_reg, klass, false2_bb, true_bb);
4835                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false2_bb);
4836
4837                 MONO_START_BB (cfg, no_proxy_bb);
4838
4839                 mini_emit_isninst_cast (cfg, klass_reg, klass, false_bb, true_bb);
4840 #else
4841                 g_error ("transparent proxy support is disabled while trying to JIT code that uses it");
4842 #endif
4843         }
4844
4845         MONO_START_BB (cfg, false_bb);
4846
4847         MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4848         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4849
4850 #ifndef DISABLE_REMOTING
4851         MONO_START_BB (cfg, false2_bb);
4852
4853         MONO_EMIT_NEW_ICONST (cfg, dreg, 2);
4854         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4855 #endif
4856
4857         MONO_START_BB (cfg, true_bb);
4858
4859         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4860
4861         MONO_START_BB (cfg, end_bb);
4862
4863         /* FIXME: */
4864         MONO_INST_NEW (cfg, ins, OP_ICONST);
4865         ins->dreg = dreg;
4866         ins->type = STACK_I4;
4867
4868         return ins;
4869 }
4870
4871 static MonoInst*
4872 handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4873 {
4874         /* This opcode takes as input an object reference and a class, and returns:
4875         0) if the object is an instance of the class,
4876         1) if the object is a proxy whose type cannot be determined
4877         an InvalidCastException exception is thrown otherwhise*/
4878         
4879         MonoInst *ins;
4880 #ifndef DISABLE_REMOTING
4881         MonoBasicBlock *end_bb, *ok_result_bb, *no_proxy_bb, *interface_fail_bb, *fail_1_bb;
4882 #else
4883         MonoBasicBlock *ok_result_bb;
4884 #endif
4885         int obj_reg = src->dreg;
4886         int dreg = alloc_ireg (cfg);
4887         int tmp_reg = alloc_preg (cfg);
4888
4889 #ifndef DISABLE_REMOTING
4890         int klass_reg = alloc_preg (cfg);
4891         NEW_BBLOCK (cfg, end_bb);
4892 #endif
4893
4894         NEW_BBLOCK (cfg, ok_result_bb);
4895
4896         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4897         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, ok_result_bb);
4898
4899         save_cast_details (cfg, klass, obj_reg, FALSE);
4900
4901         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4902 #ifndef DISABLE_REMOTING
4903                 NEW_BBLOCK (cfg, interface_fail_bb);
4904         
4905                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4906                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, ok_result_bb);
4907                 MONO_START_BB (cfg, interface_fail_bb);
4908                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4909
4910                 mini_emit_class_check (cfg, klass_reg, mono_defaults.transparent_proxy_class);
4911
4912                 tmp_reg = alloc_preg (cfg);             
4913                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4914                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4915                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
4916                 
4917                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4918                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4919 #else
4920                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4921                 mini_emit_iface_cast (cfg, tmp_reg, klass, NULL, NULL);
4922                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, ok_result_bb);
4923 #endif
4924         } else {
4925 #ifndef DISABLE_REMOTING
4926                 NEW_BBLOCK (cfg, no_proxy_bb);
4927
4928                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4929                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4930                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4931
4932                 tmp_reg = alloc_preg (cfg);
4933                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4934                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4935
4936                 tmp_reg = alloc_preg (cfg);
4937                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4938                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4939                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4940
4941                 NEW_BBLOCK (cfg, fail_1_bb);
4942                 
4943                 mini_emit_isninst_cast (cfg, klass_reg, klass, fail_1_bb, ok_result_bb);
4944
4945                 MONO_START_BB (cfg, fail_1_bb);
4946
4947                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4948                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4949
4950                 MONO_START_BB (cfg, no_proxy_bb);
4951
4952                 mini_emit_castclass (cfg, obj_reg, klass_reg, klass, ok_result_bb);
4953 #else
4954                 g_error ("Transparent proxy support is disabled while trying to JIT code that uses it");
4955 #endif
4956         }
4957
4958         MONO_START_BB (cfg, ok_result_bb);
4959
4960         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4961
4962 #ifndef DISABLE_REMOTING
4963         MONO_START_BB (cfg, end_bb);
4964 #endif
4965
4966         /* FIXME: */
4967         MONO_INST_NEW (cfg, ins, OP_ICONST);
4968         ins->dreg = dreg;
4969         ins->type = STACK_I4;
4970
4971         return ins;
4972 }
4973
4974 static G_GNUC_UNUSED MonoInst*
4975 handle_enum_has_flag (MonoCompile *cfg, MonoClass *klass, MonoInst *enum_this, MonoInst *enum_flag)
4976 {
4977         MonoType *enum_type = mono_type_get_underlying_type (&klass->byval_arg);
4978         guint32 load_opc = mono_type_to_load_membase (cfg, enum_type);
4979         gboolean is_i4;
4980
4981         switch (enum_type->type) {
4982         case MONO_TYPE_I8:
4983         case MONO_TYPE_U8:
4984 #if SIZEOF_REGISTER == 8
4985         case MONO_TYPE_I:
4986         case MONO_TYPE_U:
4987 #endif
4988                 is_i4 = FALSE;
4989                 break;
4990         default:
4991                 is_i4 = TRUE;
4992                 break;
4993         }
4994
4995         {
4996                 MonoInst *load, *and_, *cmp, *ceq;
4997                 int enum_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4998                 int and_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4999                 int dest_reg = alloc_ireg (cfg);
5000
5001                 EMIT_NEW_LOAD_MEMBASE (cfg, load, load_opc, enum_reg, enum_this->dreg, 0);
5002                 EMIT_NEW_BIALU (cfg, and_, is_i4 ? OP_IAND : OP_LAND, and_reg, enum_reg, enum_flag->dreg);
5003                 EMIT_NEW_BIALU (cfg, cmp, is_i4 ? OP_ICOMPARE : OP_LCOMPARE, -1, and_reg, enum_flag->dreg);
5004                 EMIT_NEW_UNALU (cfg, ceq, is_i4 ? OP_ICEQ : OP_LCEQ, dest_reg, -1);
5005
5006                 ceq->type = STACK_I4;
5007
5008                 if (!is_i4) {
5009                         load = mono_decompose_opcode (cfg, load);
5010                         and_ = mono_decompose_opcode (cfg, and_);
5011                         cmp = mono_decompose_opcode (cfg, cmp);
5012                         ceq = mono_decompose_opcode (cfg, ceq);
5013                 }
5014
5015                 return ceq;
5016         }
5017 }
5018
5019 /*
5020  * Returns NULL and set the cfg exception on error.
5021  */
5022 static G_GNUC_UNUSED MonoInst*
5023 handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method, int context_used, gboolean virtual_)
5024 {
5025         MonoInst *ptr;
5026         int dreg;
5027         gpointer trampoline;
5028         MonoInst *obj, *method_ins, *tramp_ins;
5029         MonoDomain *domain;
5030         guint8 **code_slot;
5031
5032         if (virtual_ && !cfg->llvm_only) {
5033                 MonoMethod *invoke = mono_get_delegate_invoke (klass);
5034                 g_assert (invoke);
5035
5036                 if (!mono_get_delegate_virtual_invoke_impl (mono_method_signature (invoke), context_used ? NULL : method))
5037                         return NULL;
5038         }
5039
5040         obj = handle_alloc (cfg, klass, FALSE, mono_class_check_context_used (klass));
5041         if (!obj)
5042                 return NULL;
5043
5044         /* Inline the contents of mono_delegate_ctor */
5045
5046         /* Set target field */
5047         /* Optimize away setting of NULL target */
5048         if (!(target->opcode == OP_PCONST && target->inst_p0 == 0)) {
5049                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
5050                 if (cfg->gen_write_barriers) {
5051                         dreg = alloc_preg (cfg);
5052                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target));
5053                         emit_write_barrier (cfg, ptr, target);
5054                 }
5055         }
5056
5057         /* Set method field */
5058         method_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
5059         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg);
5060
5061         /* 
5062          * To avoid looking up the compiled code belonging to the target method
5063          * in mono_delegate_trampoline (), we allocate a per-domain memory slot to
5064          * store it, and we fill it after the method has been compiled.
5065          */
5066         if (!method->dynamic && !(cfg->opt & MONO_OPT_SHARED)) {
5067                 MonoInst *code_slot_ins;
5068
5069                 if (context_used) {
5070                         code_slot_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD_DELEGATE_CODE);
5071                 } else {
5072                         domain = mono_domain_get ();
5073                         mono_domain_lock (domain);
5074                         if (!domain_jit_info (domain)->method_code_hash)
5075                                 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
5076                         code_slot = (guint8 **)g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, method);
5077                         if (!code_slot) {
5078                                 code_slot = (guint8 **)mono_domain_alloc0 (domain, sizeof (gpointer));
5079                                 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, method, code_slot);
5080                         }
5081                         mono_domain_unlock (domain);
5082
5083                         code_slot_ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHOD_CODE_SLOT, method);
5084                 }
5085                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);                
5086         }
5087
5088         if (cfg->llvm_only) {
5089                 MonoInst *args [16];
5090
5091                 if (virtual_) {
5092                         args [0] = obj;
5093                         args [1] = target;
5094                         args [2] = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
5095                         mono_emit_jit_icall (cfg, mono_llvmonly_init_delegate_virtual, args);
5096                 } else {
5097                         args [0] = obj;
5098                         mono_emit_jit_icall (cfg, mono_llvmonly_init_delegate, args);
5099                 }
5100
5101                 return obj;
5102         }
5103
5104         if (cfg->compile_aot) {
5105                 MonoDelegateClassMethodPair *del_tramp;
5106
5107                 del_tramp = (MonoDelegateClassMethodPair *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoDelegateClassMethodPair));
5108                 del_tramp->klass = klass;
5109                 del_tramp->method = context_used ? NULL : method;
5110                 del_tramp->is_virtual = virtual_;
5111                 EMIT_NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_DELEGATE_TRAMPOLINE, del_tramp);
5112         } else {
5113                 if (virtual_)
5114                         trampoline = mono_create_delegate_virtual_trampoline (cfg->domain, klass, context_used ? NULL : method);
5115                 else
5116                         trampoline = mono_create_delegate_trampoline_info (cfg->domain, klass, context_used ? NULL : method);
5117                 EMIT_NEW_PCONST (cfg, tramp_ins, trampoline);
5118         }
5119
5120         /* Set invoke_impl field */
5121         if (virtual_) {
5122                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), tramp_ins->dreg);
5123         } else {
5124                 dreg = alloc_preg (cfg);
5125                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, invoke_impl));
5126                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), dreg);
5127
5128                 dreg = alloc_preg (cfg);
5129                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, method_ptr));
5130                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr), dreg);
5131         }
5132
5133         dreg = alloc_preg (cfg);
5134         MONO_EMIT_NEW_ICONST (cfg, dreg, virtual_ ? 1 : 0);
5135         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_is_virtual), dreg);
5136
5137         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
5138
5139         return obj;
5140 }
5141
5142 static MonoInst*
5143 handle_array_new (MonoCompile *cfg, int rank, MonoInst **sp, unsigned char *ip)
5144 {
5145         MonoJitICallInfo *info;
5146
5147         /* Need to register the icall so it gets an icall wrapper */
5148         info = mono_get_array_new_va_icall (rank);
5149
5150         cfg->flags |= MONO_CFG_HAS_VARARGS;
5151
5152         /* mono_array_new_va () needs a vararg calling convention */
5153         cfg->exception_message = g_strdup ("array-new");
5154         cfg->disable_llvm = TRUE;
5155
5156         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
5157         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, sp);
5158 }
5159
5160 /*
5161  * handle_constrained_gsharedvt_call:
5162  *
5163  *   Handle constrained calls where the receiver is a gsharedvt type.
5164  * Return the instruction representing the call. Set the cfg exception on failure.
5165  */
5166 static MonoInst*
5167 handle_constrained_gsharedvt_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp, MonoClass *constrained_class,
5168                                                                    gboolean *ref_emit_widen)
5169 {
5170         MonoInst *ins = NULL;
5171         gboolean emit_widen = *ref_emit_widen;
5172
5173         /*
5174          * Constrained calls need to behave differently at runtime dependending on whenever the receiver is instantiated as ref type or as a vtype.
5175          * 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
5176          * pack the arguments into an array, and do the rest of the work in in an icall.
5177          */
5178         if (((cmethod->klass == mono_defaults.object_class) || (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) &&
5179                 (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)) &&
5180                 (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]))))) {
5181                 MonoInst *args [16];
5182
5183                 /*
5184                  * This case handles calls to
5185                  * - object:ToString()/Equals()/GetHashCode(),
5186                  * - System.IComparable<T>:CompareTo()
5187                  * - System.IEquatable<T>:Equals ()
5188                  * plus some simple interface calls enough to support AsyncTaskMethodBuilder.
5189                  */
5190
5191                 args [0] = sp [0];
5192                 if (mono_method_check_context_used (cmethod))
5193                         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cmethod), cmethod, MONO_RGCTX_INFO_METHOD);
5194                 else
5195                         EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
5196                 args [2] = emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_class), constrained_class, MONO_RGCTX_INFO_KLASS);
5197
5198                 /* !fsig->hasthis is for the wrapper for the Object.GetType () icall */
5199                 if (fsig->hasthis && fsig->param_count) {
5200                         /* Pass the arguments using a localloc-ed array using the format expected by runtime_invoke () */
5201                         MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
5202                         ins->dreg = alloc_preg (cfg);
5203                         ins->inst_imm = fsig->param_count * sizeof (mgreg_t);
5204                         MONO_ADD_INS (cfg->cbb, ins);
5205                         args [4] = ins;
5206
5207                         if (mini_is_gsharedvt_type (fsig->params [0])) {
5208                                 int addr_reg, deref_arg_reg;
5209
5210                                 ins = emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type (fsig->params [0]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
5211                                 deref_arg_reg = alloc_preg (cfg);
5212                                 /* deref_arg = BOX_TYPE != MONO_GSHAREDVT_BOX_TYPE_VTYPE */
5213                                 EMIT_NEW_BIALU_IMM (cfg, args [3], OP_ISUB_IMM, deref_arg_reg, ins->dreg, 1);
5214
5215                                 EMIT_NEW_VARLOADA_VREG (cfg, ins, sp [1]->dreg, fsig->params [0]);
5216                                 addr_reg = ins->dreg;
5217                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, addr_reg);
5218                         } else {
5219                                 EMIT_NEW_ICONST (cfg, args [3], 0);
5220                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, sp [1]->dreg);
5221                         }
5222                 } else {
5223                         EMIT_NEW_ICONST (cfg, args [3], 0);
5224                         EMIT_NEW_ICONST (cfg, args [4], 0);
5225                 }
5226                 ins = mono_emit_jit_icall (cfg, mono_gsharedvt_constrained_call, args);
5227                 emit_widen = FALSE;
5228
5229                 if (mini_is_gsharedvt_type (fsig->ret)) {
5230                         ins = handle_unbox_gsharedvt (cfg, mono_class_from_mono_type (fsig->ret), ins);
5231                 } else if (MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret)) {
5232                         MonoInst *add;
5233
5234                         /* Unbox */
5235                         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), ins->dreg, sizeof (MonoObject));
5236                         MONO_ADD_INS (cfg->cbb, add);
5237                         /* Load value */
5238                         NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, add->dreg, 0);
5239                         MONO_ADD_INS (cfg->cbb, ins);
5240                         /* ins represents the call result */
5241                 }
5242         } else {
5243                 GSHAREDVT_FAILURE (CEE_CALLVIRT);
5244         }
5245
5246         *ref_emit_widen = emit_widen;
5247
5248         return ins;
5249
5250  exception_exit:
5251         return NULL;
5252 }
5253
5254 static void
5255 mono_emit_load_got_addr (MonoCompile *cfg)
5256 {
5257         MonoInst *getaddr, *dummy_use;
5258
5259         if (!cfg->got_var || cfg->got_var_allocated)
5260                 return;
5261
5262         MONO_INST_NEW (cfg, getaddr, OP_LOAD_GOTADDR);
5263         getaddr->cil_code = cfg->header->code;
5264         getaddr->dreg = cfg->got_var->dreg;
5265
5266         /* Add it to the start of the first bblock */
5267         if (cfg->bb_entry->code) {
5268                 getaddr->next = cfg->bb_entry->code;
5269                 cfg->bb_entry->code = getaddr;
5270         }
5271         else
5272                 MONO_ADD_INS (cfg->bb_entry, getaddr);
5273
5274         cfg->got_var_allocated = TRUE;
5275
5276         /* 
5277          * Add a dummy use to keep the got_var alive, since real uses might
5278          * only be generated by the back ends.
5279          * Add it to end_bblock, so the variable's lifetime covers the whole
5280          * method.
5281          * It would be better to make the usage of the got var explicit in all
5282          * cases when the backend needs it (i.e. calls, throw etc.), so this
5283          * wouldn't be needed.
5284          */
5285         NEW_DUMMY_USE (cfg, dummy_use, cfg->got_var);
5286         MONO_ADD_INS (cfg->bb_exit, dummy_use);
5287 }
5288
5289 static int inline_limit;
5290 static gboolean inline_limit_inited;
5291
5292 static gboolean
5293 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
5294 {
5295         MonoMethodHeaderSummary header;
5296         MonoVTable *vtable;
5297 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5298         MonoMethodSignature *sig = mono_method_signature (method);
5299         int i;
5300 #endif
5301
5302         if (cfg->disable_inline)
5303                 return FALSE;
5304         if (cfg->gshared)
5305                 return FALSE;
5306
5307         if (cfg->inline_depth > 10)
5308                 return FALSE;
5309
5310         if (!mono_method_get_header_summary (method, &header))
5311                 return FALSE;
5312
5313         /*runtime, icall and pinvoke are checked by summary call*/
5314         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
5315             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
5316             (mono_class_is_marshalbyref (method->klass)) ||
5317             header.has_clauses)
5318                 return FALSE;
5319
5320         /* also consider num_locals? */
5321         /* Do the size check early to avoid creating vtables */
5322         if (!inline_limit_inited) {
5323                 if (g_getenv ("MONO_INLINELIMIT"))
5324                         inline_limit = atoi (g_getenv ("MONO_INLINELIMIT"));
5325                 else
5326                         inline_limit = INLINE_LENGTH_LIMIT;
5327                 inline_limit_inited = TRUE;
5328         }
5329         if (header.code_size >= inline_limit && !(method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
5330                 return FALSE;
5331
5332         /*
5333          * if we can initialize the class of the method right away, we do,
5334          * otherwise we don't allow inlining if the class needs initialization,
5335          * since it would mean inserting a call to mono_runtime_class_init()
5336          * inside the inlined code
5337          */
5338         if (!(cfg->opt & MONO_OPT_SHARED)) {
5339                 /* The AggressiveInlining hint is a good excuse to force that cctor to run. */
5340                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING) {
5341                         vtable = mono_class_vtable (cfg->domain, method->klass);
5342                         if (!vtable)
5343                                 return FALSE;
5344                         if (!cfg->compile_aot) {
5345                                 MonoError error;
5346                                 if (!mono_runtime_class_init_full (vtable, &error)) {
5347                                         mono_error_cleanup (&error);
5348                                         return FALSE;
5349                                 }
5350                         }
5351                 } else if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5352                         if (cfg->run_cctors && method->klass->has_cctor) {
5353                                 /*FIXME it would easier and lazier to just use mono_class_try_get_vtable */
5354                                 if (!method->klass->runtime_info)
5355                                         /* No vtable created yet */
5356                                         return FALSE;
5357                                 vtable = mono_class_vtable (cfg->domain, method->klass);
5358                                 if (!vtable)
5359                                         return FALSE;
5360                                 /* This makes so that inline cannot trigger */
5361                                 /* .cctors: too many apps depend on them */
5362                                 /* running with a specific order... */
5363                                 if (! vtable->initialized)
5364                                         return FALSE;
5365                                 MonoError error;
5366                                 if (!mono_runtime_class_init_full (vtable, &error)) {
5367                                         mono_error_cleanup (&error);
5368                                         return FALSE;
5369                                 }
5370                         }
5371                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
5372                         if (!method->klass->runtime_info)
5373                                 /* No vtable created yet */
5374                                 return FALSE;
5375                         vtable = mono_class_vtable (cfg->domain, method->klass);
5376                         if (!vtable)
5377                                 return FALSE;
5378                         if (!vtable->initialized)
5379                                 return FALSE;
5380                 }
5381         } else {
5382                 /* 
5383                  * If we're compiling for shared code
5384                  * the cctor will need to be run at aot method load time, for example,
5385                  * or at the end of the compilation of the inlining method.
5386                  */
5387                 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
5388                         return FALSE;
5389         }
5390
5391 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5392         if (mono_arch_is_soft_float ()) {
5393                 /* FIXME: */
5394                 if (sig->ret && sig->ret->type == MONO_TYPE_R4)
5395                         return FALSE;
5396                 for (i = 0; i < sig->param_count; ++i)
5397                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4)
5398                                 return FALSE;
5399         }
5400 #endif
5401
5402         if (g_list_find (cfg->dont_inline, method))
5403                 return FALSE;
5404
5405         return TRUE;
5406 }
5407
5408 static gboolean
5409 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoClass *klass, MonoVTable *vtable)
5410 {
5411         if (!cfg->compile_aot) {
5412                 g_assert (vtable);
5413                 if (vtable->initialized)
5414                         return FALSE;
5415         }
5416
5417         if (klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5418                 if (cfg->method == method)
5419                         return FALSE;
5420         }
5421
5422         if (!mono_class_needs_cctor_run (klass, method))
5423                 return FALSE;
5424
5425         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (klass == method->klass))
5426                 /* The initialization is already done before the method is called */
5427                 return FALSE;
5428
5429         return TRUE;
5430 }
5431
5432 static MonoInst*
5433 mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck)
5434 {
5435         MonoInst *ins;
5436         guint32 size;
5437         int mult_reg, add_reg, array_reg, index_reg, index2_reg;
5438         int context_used;
5439
5440         if (mini_is_gsharedvt_variable_klass (klass)) {
5441                 size = -1;
5442         } else {
5443                 mono_class_init (klass);
5444                 size = mono_class_array_element_size (klass);
5445         }
5446
5447         mult_reg = alloc_preg (cfg);
5448         array_reg = arr->dreg;
5449         index_reg = index->dreg;
5450
5451 #if SIZEOF_REGISTER == 8
5452         /* The array reg is 64 bits but the index reg is only 32 */
5453         if (COMPILE_LLVM (cfg)) {
5454                 /* Not needed */
5455                 index2_reg = index_reg;
5456         } else {
5457                 index2_reg = alloc_preg (cfg);
5458                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
5459         }
5460 #else
5461         if (index->type == STACK_I8) {
5462                 index2_reg = alloc_preg (cfg);
5463                 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I4, index2_reg, index_reg);
5464         } else {
5465                 index2_reg = index_reg;
5466         }
5467 #endif
5468
5469         if (bcheck)
5470                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
5471
5472 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5473         if (size == 1 || size == 2 || size == 4 || size == 8) {
5474                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
5475
5476                 EMIT_NEW_X86_LEA (cfg, ins, array_reg, index2_reg, fast_log2 [size], MONO_STRUCT_OFFSET (MonoArray, vector));
5477                 ins->klass = mono_class_get_element_class (klass);
5478                 ins->type = STACK_MP;
5479
5480                 return ins;
5481         }
5482 #endif          
5483
5484         add_reg = alloc_ireg_mp (cfg);
5485
5486         if (size == -1) {
5487                 MonoInst *rgctx_ins;
5488
5489                 /* gsharedvt */
5490                 g_assert (cfg->gshared);
5491                 context_used = mini_class_check_context_used (cfg, klass);
5492                 g_assert (context_used);
5493                 rgctx_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE);
5494                 MONO_EMIT_NEW_BIALU (cfg, OP_IMUL, mult_reg, index2_reg, rgctx_ins->dreg);
5495         } else {
5496                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
5497         }
5498         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg);
5499         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5500         ins->klass = mono_class_get_element_class (klass);
5501         ins->type = STACK_MP;
5502         MONO_ADD_INS (cfg->cbb, ins);
5503
5504         return ins;
5505 }
5506
5507 static MonoInst*
5508 mini_emit_ldelema_2_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index_ins1, MonoInst *index_ins2)
5509 {
5510         int bounds_reg = alloc_preg (cfg);
5511         int add_reg = alloc_ireg_mp (cfg);
5512         int mult_reg = alloc_preg (cfg);
5513         int mult2_reg = alloc_preg (cfg);
5514         int low1_reg = alloc_preg (cfg);
5515         int low2_reg = alloc_preg (cfg);
5516         int high1_reg = alloc_preg (cfg);
5517         int high2_reg = alloc_preg (cfg);
5518         int realidx1_reg = alloc_preg (cfg);
5519         int realidx2_reg = alloc_preg (cfg);
5520         int sum_reg = alloc_preg (cfg);
5521         int index1, index2, tmpreg;
5522         MonoInst *ins;
5523         guint32 size;
5524
5525         mono_class_init (klass);
5526         size = mono_class_array_element_size (klass);
5527
5528         index1 = index_ins1->dreg;
5529         index2 = index_ins2->dreg;
5530
5531 #if SIZEOF_REGISTER == 8
5532         /* The array reg is 64 bits but the index reg is only 32 */
5533         if (COMPILE_LLVM (cfg)) {
5534                 /* Not needed */
5535         } else {
5536                 tmpreg = alloc_preg (cfg);
5537                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index1);
5538                 index1 = tmpreg;
5539                 tmpreg = alloc_preg (cfg);
5540                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index2);
5541                 index2 = tmpreg;
5542         }
5543 #else
5544         // FIXME: Do we need to do something here for i8 indexes, like in ldelema_1_ins ?
5545         tmpreg = -1;
5546 #endif
5547
5548         /* range checking */
5549         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, 
5550                                        arr->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5551
5552         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low1_reg, 
5553                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5554         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx1_reg, index1, low1_reg);
5555         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high1_reg, 
5556                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5557         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high1_reg, realidx1_reg);
5558         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5559
5560         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low2_reg, 
5561                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5562         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx2_reg, index2, low2_reg);
5563         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high2_reg, 
5564                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5565         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high2_reg, realidx2_reg);
5566         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5567
5568         MONO_EMIT_NEW_BIALU (cfg, OP_PMUL, mult_reg, high2_reg, realidx1_reg);
5569         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, mult_reg, realidx2_reg);
5570         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PMUL_IMM, mult2_reg, sum_reg, size);
5571         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult2_reg, arr->dreg);
5572         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5573
5574         ins->type = STACK_MP;
5575         ins->klass = klass;
5576         MONO_ADD_INS (cfg->cbb, ins);
5577
5578         return ins;
5579 }
5580
5581 static MonoInst*
5582 mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
5583 {
5584         int rank;
5585         MonoInst *addr;
5586         MonoMethod *addr_method;
5587         int element_size;
5588         MonoClass *eclass = cmethod->klass->element_class;
5589
5590         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
5591
5592         if (rank == 1)
5593                 return mini_emit_ldelema_1_ins (cfg, eclass, sp [0], sp [1], TRUE);
5594
5595         /* emit_ldelema_2 depends on OP_LMUL */
5596         if (!cfg->backend->emulate_mul_div && rank == 2 && (cfg->opt & MONO_OPT_INTRINS) && !mini_is_gsharedvt_variable_klass (eclass)) {
5597                 return mini_emit_ldelema_2_ins (cfg, eclass, sp [0], sp [1], sp [2]);
5598         }
5599
5600         if (mini_is_gsharedvt_variable_klass (eclass))
5601                 element_size = 0;
5602         else
5603                 element_size = mono_class_array_element_size (eclass);
5604         addr_method = mono_marshal_get_array_address (rank, element_size);
5605         addr = mono_emit_method_call (cfg, addr_method, sp, NULL);
5606
5607         return addr;
5608 }
5609
5610 static MonoBreakPolicy
5611 always_insert_breakpoint (MonoMethod *method)
5612 {
5613         return MONO_BREAK_POLICY_ALWAYS;
5614 }
5615
5616 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
5617
5618 /**
5619  * mono_set_break_policy:
5620  * policy_callback: the new callback function
5621  *
5622  * Allow embedders to decide wherther to actually obey breakpoint instructions
5623  * (both break IL instructions and Debugger.Break () method calls), for example
5624  * to not allow an app to be aborted by a perfectly valid IL opcode when executing
5625  * untrusted or semi-trusted code.
5626  *
5627  * @policy_callback will be called every time a break point instruction needs to
5628  * be inserted with the method argument being the method that calls Debugger.Break()
5629  * or has the IL break instruction. The callback should return #MONO_BREAK_POLICY_NEVER
5630  * if it wants the breakpoint to not be effective in the given method.
5631  * #MONO_BREAK_POLICY_ALWAYS is the default.
5632  */
5633 void
5634 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
5635 {
5636         if (policy_callback)
5637                 break_policy_func = policy_callback;
5638         else
5639                 break_policy_func = always_insert_breakpoint;
5640 }
5641
5642 static gboolean
5643 should_insert_brekpoint (MonoMethod *method) {
5644         switch (break_policy_func (method)) {
5645         case MONO_BREAK_POLICY_ALWAYS:
5646                 return TRUE;
5647         case MONO_BREAK_POLICY_NEVER:
5648                 return FALSE;
5649         case MONO_BREAK_POLICY_ON_DBG:
5650                 g_warning ("mdb no longer supported");
5651                 return FALSE;
5652         default:
5653                 g_warning ("Incorrect value returned from break policy callback");
5654                 return FALSE;
5655         }
5656 }
5657
5658 /* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */
5659 static MonoInst*
5660 emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5661 {
5662         MonoInst *addr, *store, *load;
5663         MonoClass *eklass = mono_class_from_mono_type (fsig->params [2]);
5664
5665         /* the bounds check is already done by the callers */
5666         addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5667         if (is_set) {
5668                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
5669                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
5670                 if (mini_type_is_reference (fsig->params [2]))
5671                         emit_write_barrier (cfg, addr, load);
5672         } else {
5673                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
5674                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
5675         }
5676         return store;
5677 }
5678
5679
5680 static gboolean
5681 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
5682 {
5683         return mini_type_is_reference (&klass->byval_arg);
5684 }
5685
5686 static MonoInst*
5687 emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboolean safety_checks)
5688 {
5689         if (safety_checks && generic_class_is_reference_type (cfg, klass) &&
5690                 !(sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL)) {
5691                 MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
5692                 MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
5693                 MonoInst *iargs [3];
5694
5695                 if (!helper->slot)
5696                         mono_class_setup_vtable (obj_array);
5697                 g_assert (helper->slot);
5698
5699                 if (sp [0]->type != STACK_OBJ)
5700                         return NULL;
5701                 if (sp [2]->type != STACK_OBJ)
5702                         return NULL;
5703
5704                 iargs [2] = sp [2];
5705                 iargs [1] = sp [1];
5706                 iargs [0] = sp [0];
5707
5708                 return mono_emit_method_call (cfg, helper, iargs, sp [0]);
5709         } else {
5710                 MonoInst *ins;
5711
5712                 if (mini_is_gsharedvt_variable_klass (klass)) {
5713                         MonoInst *addr;
5714
5715                         // FIXME-VT: OP_ICONST optimization
5716                         addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
5717                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5718                         ins->opcode = OP_STOREV_MEMBASE;
5719                 } else if (sp [1]->opcode == OP_ICONST) {
5720                         int array_reg = sp [0]->dreg;
5721                         int index_reg = sp [1]->dreg;
5722                         int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
5723
5724                         if (SIZEOF_REGISTER == 8 && COMPILE_LLVM (cfg))
5725                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, index_reg);
5726
5727                         if (safety_checks)
5728                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
5729                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
5730                 } else {
5731                         MonoInst *addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], safety_checks);
5732                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5733                         if (generic_class_is_reference_type (cfg, klass))
5734                                 emit_write_barrier (cfg, addr, sp [2]);
5735                 }
5736                 return ins;
5737         }
5738 }
5739
5740 static MonoInst*
5741 emit_array_unsafe_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5742 {
5743         MonoClass *eklass;
5744         
5745         if (is_set)
5746                 eklass = mono_class_from_mono_type (fsig->params [2]);
5747         else
5748                 eklass = mono_class_from_mono_type (fsig->ret);
5749
5750         if (is_set) {
5751                 return emit_array_store (cfg, eklass, args, FALSE);
5752         } else {
5753                 MonoInst *ins, *addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5754                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &eklass->byval_arg, addr->dreg, 0);
5755                 return ins;
5756         }
5757 }
5758
5759 static gboolean
5760 is_unsafe_mov_compatible (MonoCompile *cfg, MonoClass *param_klass, MonoClass *return_klass)
5761 {
5762         uint32_t align;
5763         int param_size, return_size;
5764
5765         param_klass = mono_class_from_mono_type (mini_get_underlying_type (&param_klass->byval_arg));
5766         return_klass = mono_class_from_mono_type (mini_get_underlying_type (&return_klass->byval_arg));
5767
5768         if (cfg->verbose_level > 3)
5769                 printf ("[UNSAFE-MOV-INTRISIC] %s <- %s\n", return_klass->name, param_klass->name);
5770
5771         //Don't allow mixing reference types with value types
5772         if (param_klass->valuetype != return_klass->valuetype) {
5773                 if (cfg->verbose_level > 3)
5774                         printf ("[UNSAFE-MOV-INTRISIC]\tone of the args is a valuetype and the other is not\n");
5775                 return FALSE;
5776         }
5777
5778         if (!param_klass->valuetype) {
5779                 if (cfg->verbose_level > 3)
5780                         printf ("[UNSAFE-MOV-INTRISIC]\targs are reference types\n");
5781                 return TRUE;
5782         }
5783
5784         //That are blitable
5785         if (param_klass->has_references || return_klass->has_references)
5786                 return FALSE;
5787
5788         /* Avoid mixing structs and primitive types/enums, they need to be handled differently in the JIT */
5789         if ((MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && !MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)) ||
5790                 (!MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && MONO_TYPE_ISSTRUCT (&return_klass->byval_arg))) {
5791                         if (cfg->verbose_level > 3)
5792                                 printf ("[UNSAFE-MOV-INTRISIC]\tmixing structs and scalars\n");
5793                 return FALSE;
5794         }
5795
5796         if (param_klass->byval_arg.type == MONO_TYPE_R4 || param_klass->byval_arg.type == MONO_TYPE_R8 ||
5797                 return_klass->byval_arg.type == MONO_TYPE_R4 || return_klass->byval_arg.type == MONO_TYPE_R8) {
5798                 if (cfg->verbose_level > 3)
5799                         printf ("[UNSAFE-MOV-INTRISIC]\tfloat or double are not supported\n");
5800                 return FALSE;
5801         }
5802
5803         param_size = mono_class_value_size (param_klass, &align);
5804         return_size = mono_class_value_size (return_klass, &align);
5805
5806         //We can do it if sizes match
5807         if (param_size == return_size) {
5808                 if (cfg->verbose_level > 3)
5809                         printf ("[UNSAFE-MOV-INTRISIC]\tsame size\n");
5810                 return TRUE;
5811         }
5812
5813         //No simple way to handle struct if sizes don't match
5814         if (MONO_TYPE_ISSTRUCT (&param_klass->byval_arg)) {
5815                 if (cfg->verbose_level > 3)
5816                         printf ("[UNSAFE-MOV-INTRISIC]\tsize mismatch and type is a struct\n");
5817                 return FALSE;
5818         }
5819
5820         /*
5821          * Same reg size category.
5822          * A quick note on why we don't require widening here.
5823          * The intrinsic is "R Array.UnsafeMov<S,R> (S s)".
5824          *
5825          * Since the source value comes from a function argument, the JIT will already have
5826          * the value in a VREG and performed any widening needed before (say, when loading from a field).
5827          */
5828         if (param_size <= 4 && return_size <= 4) {
5829                 if (cfg->verbose_level > 3)
5830                         printf ("[UNSAFE-MOV-INTRISIC]\tsize mismatch but both are of the same reg class\n");
5831                 return TRUE;
5832         }
5833
5834         return FALSE;
5835 }
5836
5837 static MonoInst*
5838 emit_array_unsafe_mov (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args)
5839 {
5840         MonoClass *param_klass = mono_class_from_mono_type (fsig->params [0]);
5841         MonoClass *return_klass = mono_class_from_mono_type (fsig->ret);
5842
5843         if (mini_is_gsharedvt_variable_type (fsig->ret))
5844                 return NULL;
5845
5846         //Valuetypes that are semantically equivalent or numbers than can be widened to
5847         if (is_unsafe_mov_compatible (cfg, param_klass, return_klass))
5848                 return args [0];
5849
5850         //Arrays of valuetypes that are semantically equivalent
5851         if (param_klass->rank == 1 && return_klass->rank == 1 && is_unsafe_mov_compatible (cfg, param_klass->element_class, return_klass->element_class))
5852                 return args [0];
5853
5854         return NULL;
5855 }
5856
5857 static MonoInst*
5858 mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5859 {
5860 #ifdef MONO_ARCH_SIMD_INTRINSICS
5861         MonoInst *ins = NULL;
5862
5863         if (cfg->opt & MONO_OPT_SIMD) {
5864                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5865                 if (ins)
5866                         return ins;
5867         }
5868 #endif
5869
5870         return mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
5871 }
5872
5873 static MonoInst*
5874 emit_memory_barrier (MonoCompile *cfg, int kind)
5875 {
5876         MonoInst *ins = NULL;
5877         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
5878         MONO_ADD_INS (cfg->cbb, ins);
5879         ins->backend.memory_barrier_kind = kind;
5880
5881         return ins;
5882 }
5883
5884 static MonoInst*
5885 llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5886 {
5887         MonoInst *ins = NULL;
5888         int opcode = 0;
5889
5890         /* The LLVM backend supports these intrinsics */
5891         if (cmethod->klass == mono_defaults.math_class) {
5892                 if (strcmp (cmethod->name, "Sin") == 0) {
5893                         opcode = OP_SIN;
5894                 } else if (strcmp (cmethod->name, "Cos") == 0) {
5895                         opcode = OP_COS;
5896                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
5897                         opcode = OP_SQRT;
5898                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
5899                         opcode = OP_ABS;
5900                 }
5901
5902                 if (opcode && fsig->param_count == 1) {
5903                         MONO_INST_NEW (cfg, ins, opcode);
5904                         ins->type = STACK_R8;
5905                         ins->dreg = mono_alloc_freg (cfg);
5906                         ins->sreg1 = args [0]->dreg;
5907                         MONO_ADD_INS (cfg->cbb, ins);
5908                 }
5909
5910                 opcode = 0;
5911                 if (cfg->opt & MONO_OPT_CMOV) {
5912                         if (strcmp (cmethod->name, "Min") == 0) {
5913                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5914                                         opcode = OP_IMIN;
5915                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5916                                         opcode = OP_IMIN_UN;
5917                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5918                                         opcode = OP_LMIN;
5919                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5920                                         opcode = OP_LMIN_UN;
5921                         } else if (strcmp (cmethod->name, "Max") == 0) {
5922                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5923                                         opcode = OP_IMAX;
5924                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5925                                         opcode = OP_IMAX_UN;
5926                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5927                                         opcode = OP_LMAX;
5928                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5929                                         opcode = OP_LMAX_UN;
5930                         }
5931                 }
5932
5933                 if (opcode && fsig->param_count == 2) {
5934                         MONO_INST_NEW (cfg, ins, opcode);
5935                         ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
5936                         ins->dreg = mono_alloc_ireg (cfg);
5937                         ins->sreg1 = args [0]->dreg;
5938                         ins->sreg2 = args [1]->dreg;
5939                         MONO_ADD_INS (cfg->cbb, ins);
5940                 }
5941         }
5942
5943         return ins;
5944 }
5945
5946 static MonoInst*
5947 mini_emit_inst_for_sharable_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5948 {
5949         if (cmethod->klass == mono_defaults.array_class) {
5950                 if (strcmp (cmethod->name, "UnsafeStore") == 0)
5951                         return emit_array_unsafe_access (cfg, fsig, args, TRUE);
5952                 else if (strcmp (cmethod->name, "UnsafeLoad") == 0)
5953                         return emit_array_unsafe_access (cfg, fsig, args, FALSE);
5954                 else if (strcmp (cmethod->name, "UnsafeMov") == 0)
5955                         return emit_array_unsafe_mov (cfg, fsig, args);
5956         }
5957
5958         return NULL;
5959 }
5960
5961 static MonoInst*
5962 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5963 {
5964         MonoInst *ins = NULL;
5965
5966          MonoClass *runtime_helpers_class = mono_class_get_runtime_helpers_class ();
5967
5968         if (cmethod->klass == mono_defaults.string_class) {
5969                 if (strcmp (cmethod->name, "get_Chars") == 0 && fsig->param_count + fsig->hasthis == 2) {
5970                         int dreg = alloc_ireg (cfg);
5971                         int index_reg = alloc_preg (cfg);
5972                         int add_reg = alloc_preg (cfg);
5973
5974 #if SIZEOF_REGISTER == 8
5975                         if (COMPILE_LLVM (cfg)) {
5976                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, args [1]->dreg);
5977                         } else {
5978                                 /* The array reg is 64 bits but the index reg is only 32 */
5979                                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index_reg, args [1]->dreg);
5980                         }
5981 #else
5982                         index_reg = args [1]->dreg;
5983 #endif  
5984                         MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
5985
5986 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5987                         EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, MONO_STRUCT_OFFSET (MonoString, chars));
5988                         add_reg = ins->dreg;
5989                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5990                                                                    add_reg, 0);
5991 #else
5992                         int mult_reg = alloc_preg (cfg);
5993                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1);
5994                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5995                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5996                                                                    add_reg, MONO_STRUCT_OFFSET (MonoString, chars));
5997 #endif
5998                         type_from_op (cfg, ins, NULL, NULL);
5999                         return ins;
6000                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
6001                         int dreg = alloc_ireg (cfg);
6002                         /* Decompose later to allow more optimizations */
6003                         EMIT_NEW_UNALU (cfg, ins, OP_STRLEN, dreg, args [0]->dreg);
6004                         ins->type = STACK_I4;
6005                         ins->flags |= MONO_INST_FAULT;
6006                         cfg->cbb->has_array_access = TRUE;
6007                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
6008
6009                         return ins;
6010                 } else 
6011                         return NULL;
6012         } else if (cmethod->klass == mono_defaults.object_class) {
6013                 if (strcmp (cmethod->name, "GetType") == 0 && fsig->param_count + fsig->hasthis == 1) {
6014                         int dreg = alloc_ireg_ref (cfg);
6015                         int vt_reg = alloc_preg (cfg);
6016                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
6017                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, MONO_STRUCT_OFFSET (MonoVTable, type));
6018                         type_from_op (cfg, ins, NULL, NULL);
6019
6020                         return ins;
6021                 } else if (!cfg->backend->emulate_mul_div && strcmp (cmethod->name, "InternalGetHashCode") == 0 && fsig->param_count == 1 && !mono_gc_is_moving ()) {
6022                         int dreg = alloc_ireg (cfg);
6023                         int t1 = alloc_ireg (cfg);
6024         
6025                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, t1, args [0]->dreg, 3);
6026                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_MUL_IMM, dreg, t1, 2654435761u);
6027                         ins->type = STACK_I4;
6028
6029                         return ins;
6030                 } else if (strcmp (cmethod->name, ".ctor") == 0 && fsig->param_count == 0) {
6031                         MONO_INST_NEW (cfg, ins, OP_NOP);
6032                         MONO_ADD_INS (cfg->cbb, ins);
6033                         return ins;
6034                 } else
6035                         return NULL;
6036         } else if (cmethod->klass == mono_defaults.array_class) {
6037                 if (strcmp (cmethod->name, "GetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
6038                         return emit_array_generic_access (cfg, fsig, args, FALSE);
6039                 else if (strcmp (cmethod->name, "SetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
6040                         return emit_array_generic_access (cfg, fsig, args, TRUE);
6041
6042 #ifndef MONO_BIG_ARRAYS
6043                 /*
6044                  * This is an inline version of GetLength/GetLowerBound(0) used frequently in
6045                  * Array methods.
6046                  */
6047                 else if (((strcmp (cmethod->name, "GetLength") == 0 && fsig->param_count + fsig->hasthis == 2) ||
6048                          (strcmp (cmethod->name, "GetLowerBound") == 0 && fsig->param_count + fsig->hasthis == 2)) &&
6049                          args [1]->opcode == OP_ICONST && args [1]->inst_c0 == 0) {
6050                         int dreg = alloc_ireg (cfg);
6051                         int bounds_reg = alloc_ireg_mp (cfg);
6052                         MonoBasicBlock *end_bb, *szarray_bb;
6053                         gboolean get_length = strcmp (cmethod->name, "GetLength") == 0;
6054
6055                         NEW_BBLOCK (cfg, end_bb);
6056                         NEW_BBLOCK (cfg, szarray_bb);
6057
6058                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOAD_MEMBASE, bounds_reg,
6059                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
6060                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
6061                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, szarray_bb);
6062                         /* Non-szarray case */
6063                         if (get_length)
6064                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
6065                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
6066                         else
6067                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
6068                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
6069                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
6070                         MONO_START_BB (cfg, szarray_bb);
6071                         /* Szarray case */
6072                         if (get_length)
6073                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
6074                                                                            args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
6075                         else
6076                                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
6077                         MONO_START_BB (cfg, end_bb);
6078
6079                         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, dreg, dreg);
6080                         ins->type = STACK_I4;
6081                         
6082                         return ins;
6083                 }
6084 #endif
6085
6086                 if (cmethod->name [0] != 'g')
6087                         return NULL;
6088
6089                 if (strcmp (cmethod->name, "get_Rank") == 0 && fsig->param_count + fsig->hasthis == 1) {
6090                         int dreg = alloc_ireg (cfg);
6091                         int vtable_reg = alloc_preg (cfg);
6092                         MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, 
6093                                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
6094                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
6095                                                                    vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
6096                         type_from_op (cfg, ins, NULL, NULL);
6097
6098                         return ins;
6099                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
6100                         int dreg = alloc_ireg (cfg);
6101
6102                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
6103                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
6104                         type_from_op (cfg, ins, NULL, NULL);
6105
6106                         return ins;
6107                 } else
6108                         return NULL;
6109         } else if (cmethod->klass == runtime_helpers_class) {
6110                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0 && fsig->param_count == 0) {
6111                         EMIT_NEW_ICONST (cfg, ins, MONO_STRUCT_OFFSET (MonoString, chars));
6112                         return ins;
6113                 } else
6114                         return NULL;
6115         } else if (cmethod->klass == mono_defaults.monitor_class) {
6116                 gboolean is_enter = FALSE;
6117
6118                 if (!strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1)
6119                         is_enter = TRUE;
6120
6121                 if (is_enter) {
6122                         /*
6123                          * To make async stack traces work, icalls which can block should have a wrapper.
6124                          * For Monitor.Enter, emit two calls: a fastpath which doesn't have a wrapper, and a slowpath, which does.
6125                          */
6126                         MonoBasicBlock *end_bb;
6127
6128                         NEW_BBLOCK (cfg, end_bb);
6129
6130                         ins = mono_emit_jit_icall (cfg, (gpointer)mono_monitor_enter_fast, args);
6131                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, ins->dreg, 0);
6132                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, end_bb);
6133                         ins = mono_emit_jit_icall (cfg, (gpointer)mono_monitor_enter, args);
6134                         MONO_START_BB (cfg, end_bb);
6135                         return ins;
6136                 }
6137         } else if (cmethod->klass == mono_defaults.thread_class) {
6138                 if (strcmp (cmethod->name, "SpinWait_nop") == 0 && fsig->param_count == 0) {
6139                         MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
6140                         MONO_ADD_INS (cfg->cbb, ins);
6141                         return ins;
6142                 } else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0) {
6143                         return emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6144                 } else if (!strcmp (cmethod->name, "VolatileRead") && fsig->param_count == 1) {
6145                         guint32 opcode = 0;
6146                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6147
6148                         if (fsig->params [0]->type == MONO_TYPE_I1)
6149                                 opcode = OP_LOADI1_MEMBASE;
6150                         else if (fsig->params [0]->type == MONO_TYPE_U1)
6151                                 opcode = OP_LOADU1_MEMBASE;
6152                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6153                                 opcode = OP_LOADI2_MEMBASE;
6154                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6155                                 opcode = OP_LOADU2_MEMBASE;
6156                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6157                                 opcode = OP_LOADI4_MEMBASE;
6158                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6159                                 opcode = OP_LOADU4_MEMBASE;
6160                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
6161                                 opcode = OP_LOADI8_MEMBASE;
6162                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6163                                 opcode = OP_LOADR4_MEMBASE;
6164                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6165                                 opcode = OP_LOADR8_MEMBASE;
6166                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
6167                                 opcode = OP_LOAD_MEMBASE;
6168
6169                         if (opcode) {
6170                                 MONO_INST_NEW (cfg, ins, opcode);
6171                                 ins->inst_basereg = args [0]->dreg;
6172                                 ins->inst_offset = 0;
6173                                 MONO_ADD_INS (cfg->cbb, ins);
6174
6175                                 switch (fsig->params [0]->type) {
6176                                 case MONO_TYPE_I1:
6177                                 case MONO_TYPE_U1:
6178                                 case MONO_TYPE_I2:
6179                                 case MONO_TYPE_U2:
6180                                 case MONO_TYPE_I4:
6181                                 case MONO_TYPE_U4:
6182                                         ins->dreg = mono_alloc_ireg (cfg);
6183                                         ins->type = STACK_I4;
6184                                         break;
6185                                 case MONO_TYPE_I8:
6186                                 case MONO_TYPE_U8:
6187                                         ins->dreg = mono_alloc_lreg (cfg);
6188                                         ins->type = STACK_I8;
6189                                         break;
6190                                 case MONO_TYPE_I:
6191                                 case MONO_TYPE_U:
6192                                         ins->dreg = mono_alloc_ireg (cfg);
6193 #if SIZEOF_REGISTER == 8
6194                                         ins->type = STACK_I8;
6195 #else
6196                                         ins->type = STACK_I4;
6197 #endif
6198                                         break;
6199                                 case MONO_TYPE_R4:
6200                                 case MONO_TYPE_R8:
6201                                         ins->dreg = mono_alloc_freg (cfg);
6202                                         ins->type = STACK_R8;
6203                                         break;
6204                                 default:
6205                                         g_assert (mini_type_is_reference (fsig->params [0]));
6206                                         ins->dreg = mono_alloc_ireg_ref (cfg);
6207                                         ins->type = STACK_OBJ;
6208                                         break;
6209                                 }
6210
6211                                 if (opcode == OP_LOADI8_MEMBASE)
6212                                         ins = mono_decompose_opcode (cfg, ins);
6213
6214                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6215
6216                                 return ins;
6217                         }
6218                 } else if (!strcmp (cmethod->name, "VolatileWrite") && fsig->param_count == 2) {
6219                         guint32 opcode = 0;
6220                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6221
6222                         if (fsig->params [0]->type == MONO_TYPE_I1 || fsig->params [0]->type == MONO_TYPE_U1)
6223                                 opcode = OP_STOREI1_MEMBASE_REG;
6224                         else if (fsig->params [0]->type == MONO_TYPE_I2 || fsig->params [0]->type == MONO_TYPE_U2)
6225                                 opcode = OP_STOREI2_MEMBASE_REG;
6226                         else if (fsig->params [0]->type == MONO_TYPE_I4 || fsig->params [0]->type == MONO_TYPE_U4)
6227                                 opcode = OP_STOREI4_MEMBASE_REG;
6228                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
6229                                 opcode = OP_STOREI8_MEMBASE_REG;
6230                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6231                                 opcode = OP_STORER4_MEMBASE_REG;
6232                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6233                                 opcode = OP_STORER8_MEMBASE_REG;
6234                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
6235                                 opcode = OP_STORE_MEMBASE_REG;
6236
6237                         if (opcode) {
6238                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6239
6240                                 MONO_INST_NEW (cfg, ins, opcode);
6241                                 ins->sreg1 = args [1]->dreg;
6242                                 ins->inst_destbasereg = args [0]->dreg;
6243                                 ins->inst_offset = 0;
6244                                 MONO_ADD_INS (cfg->cbb, ins);
6245
6246                                 if (opcode == OP_STOREI8_MEMBASE_REG)
6247                                         ins = mono_decompose_opcode (cfg, ins);
6248
6249                                 return ins;
6250                         }
6251                 }
6252         } else if (cmethod->klass->image == mono_defaults.corlib &&
6253                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6254                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
6255                 ins = NULL;
6256
6257 #if SIZEOF_REGISTER == 8
6258                 if (!cfg->llvm_only && strcmp (cmethod->name, "Read") == 0 && fsig->param_count == 1 && (fsig->params [0]->type == MONO_TYPE_I8)) {
6259                         if (!cfg->llvm_only && mono_arch_opcode_supported (OP_ATOMIC_LOAD_I8)) {
6260                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_LOAD_I8);
6261                                 ins->dreg = mono_alloc_preg (cfg);
6262                                 ins->sreg1 = args [0]->dreg;
6263                                 ins->type = STACK_I8;
6264                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_SEQ;
6265                                 MONO_ADD_INS (cfg->cbb, ins);
6266                         } else {
6267                                 MonoInst *load_ins;
6268
6269                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6270
6271                                 /* 64 bit reads are already atomic */
6272                                 MONO_INST_NEW (cfg, load_ins, OP_LOADI8_MEMBASE);
6273                                 load_ins->dreg = mono_alloc_preg (cfg);
6274                                 load_ins->inst_basereg = args [0]->dreg;
6275                                 load_ins->inst_offset = 0;
6276                                 load_ins->type = STACK_I8;
6277                                 MONO_ADD_INS (cfg->cbb, load_ins);
6278
6279                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6280
6281                                 ins = load_ins;
6282                         }
6283                 }
6284 #endif
6285
6286                 if (strcmp (cmethod->name, "Increment") == 0 && fsig->param_count == 1) {
6287                         MonoInst *ins_iconst;
6288                         guint32 opcode = 0;
6289
6290                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6291                                 opcode = OP_ATOMIC_ADD_I4;
6292                                 cfg->has_atomic_add_i4 = TRUE;
6293                         }
6294 #if SIZEOF_REGISTER == 8
6295                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6296                                 opcode = OP_ATOMIC_ADD_I8;
6297 #endif
6298                         if (opcode) {
6299                                 if (!mono_arch_opcode_supported (opcode))
6300                                         return NULL;
6301                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6302                                 ins_iconst->inst_c0 = 1;
6303                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6304                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6305
6306                                 MONO_INST_NEW (cfg, ins, opcode);
6307                                 ins->dreg = mono_alloc_ireg (cfg);
6308                                 ins->inst_basereg = args [0]->dreg;
6309                                 ins->inst_offset = 0;
6310                                 ins->sreg2 = ins_iconst->dreg;
6311                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6312                                 MONO_ADD_INS (cfg->cbb, ins);
6313                         }
6314                 } else if (strcmp (cmethod->name, "Decrement") == 0 && fsig->param_count == 1) {
6315                         MonoInst *ins_iconst;
6316                         guint32 opcode = 0;
6317
6318                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6319                                 opcode = OP_ATOMIC_ADD_I4;
6320                                 cfg->has_atomic_add_i4 = TRUE;
6321                         }
6322 #if SIZEOF_REGISTER == 8
6323                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6324                                 opcode = OP_ATOMIC_ADD_I8;
6325 #endif
6326                         if (opcode) {
6327                                 if (!mono_arch_opcode_supported (opcode))
6328                                         return NULL;
6329                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6330                                 ins_iconst->inst_c0 = -1;
6331                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6332                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6333
6334                                 MONO_INST_NEW (cfg, ins, opcode);
6335                                 ins->dreg = mono_alloc_ireg (cfg);
6336                                 ins->inst_basereg = args [0]->dreg;
6337                                 ins->inst_offset = 0;
6338                                 ins->sreg2 = ins_iconst->dreg;
6339                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6340                                 MONO_ADD_INS (cfg->cbb, ins);
6341                         }
6342                 } else if (strcmp (cmethod->name, "Add") == 0 && fsig->param_count == 2) {
6343                         guint32 opcode = 0;
6344
6345                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6346                                 opcode = OP_ATOMIC_ADD_I4;
6347                                 cfg->has_atomic_add_i4 = TRUE;
6348                         }
6349 #if SIZEOF_REGISTER == 8
6350                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6351                                 opcode = OP_ATOMIC_ADD_I8;
6352 #endif
6353                         if (opcode) {
6354                                 if (!mono_arch_opcode_supported (opcode))
6355                                         return NULL;
6356                                 MONO_INST_NEW (cfg, ins, opcode);
6357                                 ins->dreg = mono_alloc_ireg (cfg);
6358                                 ins->inst_basereg = args [0]->dreg;
6359                                 ins->inst_offset = 0;
6360                                 ins->sreg2 = args [1]->dreg;
6361                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6362                                 MONO_ADD_INS (cfg->cbb, ins);
6363                         }
6364                 }
6365                 else if (strcmp (cmethod->name, "Exchange") == 0 && fsig->param_count == 2) {
6366                         MonoInst *f2i = NULL, *i2f;
6367                         guint32 opcode, f2i_opcode, i2f_opcode;
6368                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6369                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
6370
6371                         if (fsig->params [0]->type == MONO_TYPE_I4 ||
6372                             fsig->params [0]->type == MONO_TYPE_R4) {
6373                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6374                                 f2i_opcode = OP_MOVE_F_TO_I4;
6375                                 i2f_opcode = OP_MOVE_I4_TO_F;
6376                                 cfg->has_atomic_exchange_i4 = TRUE;
6377                         }
6378 #if SIZEOF_REGISTER == 8
6379                         else if (is_ref ||
6380                                  fsig->params [0]->type == MONO_TYPE_I8 ||
6381                                  fsig->params [0]->type == MONO_TYPE_R8 ||
6382                                  fsig->params [0]->type == MONO_TYPE_I) {
6383                                 opcode = OP_ATOMIC_EXCHANGE_I8;
6384                                 f2i_opcode = OP_MOVE_F_TO_I8;
6385                                 i2f_opcode = OP_MOVE_I8_TO_F;
6386                         }
6387 #else
6388                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I) {
6389                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6390                                 cfg->has_atomic_exchange_i4 = TRUE;
6391                         }
6392 #endif
6393                         else
6394                                 return NULL;
6395
6396                         if (!mono_arch_opcode_supported (opcode))
6397                                 return NULL;
6398
6399                         if (is_float) {
6400                                 /* TODO: Decompose these opcodes instead of bailing here. */
6401                                 if (COMPILE_SOFT_FLOAT (cfg))
6402                                         return NULL;
6403
6404                                 MONO_INST_NEW (cfg, f2i, f2i_opcode);
6405                                 f2i->dreg = mono_alloc_ireg (cfg);
6406                                 f2i->sreg1 = args [1]->dreg;
6407                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6408                                         f2i->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6409                                 MONO_ADD_INS (cfg->cbb, f2i);
6410                         }
6411
6412                         MONO_INST_NEW (cfg, ins, opcode);
6413                         ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : mono_alloc_ireg (cfg);
6414                         ins->inst_basereg = args [0]->dreg;
6415                         ins->inst_offset = 0;
6416                         ins->sreg2 = is_float ? f2i->dreg : args [1]->dreg;
6417                         MONO_ADD_INS (cfg->cbb, ins);
6418
6419                         switch (fsig->params [0]->type) {
6420                         case MONO_TYPE_I4:
6421                                 ins->type = STACK_I4;
6422                                 break;
6423                         case MONO_TYPE_I8:
6424                                 ins->type = STACK_I8;
6425                                 break;
6426                         case MONO_TYPE_I:
6427 #if SIZEOF_REGISTER == 8
6428                                 ins->type = STACK_I8;
6429 #else
6430                                 ins->type = STACK_I4;
6431 #endif
6432                                 break;
6433                         case MONO_TYPE_R4:
6434                         case MONO_TYPE_R8:
6435                                 ins->type = STACK_R8;
6436                                 break;
6437                         default:
6438                                 g_assert (mini_type_is_reference (fsig->params [0]));
6439                                 ins->type = STACK_OBJ;
6440                                 break;
6441                         }
6442
6443                         if (is_float) {
6444                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6445                                 i2f->dreg = mono_alloc_freg (cfg);
6446                                 i2f->sreg1 = ins->dreg;
6447                                 i2f->type = STACK_R8;
6448                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6449                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6450                                 MONO_ADD_INS (cfg->cbb, i2f);
6451
6452                                 ins = i2f;
6453                         }
6454
6455                         if (cfg->gen_write_barriers && is_ref)
6456                                 emit_write_barrier (cfg, args [0], args [1]);
6457                 }
6458                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 3) {
6459                         MonoInst *f2i_new = NULL, *f2i_cmp = NULL, *i2f;
6460                         guint32 opcode, f2i_opcode, i2f_opcode;
6461                         gboolean is_ref = mini_type_is_reference (fsig->params [1]);
6462                         gboolean is_float = fsig->params [1]->type == MONO_TYPE_R4 || fsig->params [1]->type == MONO_TYPE_R8;
6463
6464                         if (fsig->params [1]->type == MONO_TYPE_I4 ||
6465                             fsig->params [1]->type == MONO_TYPE_R4) {
6466                                 opcode = OP_ATOMIC_CAS_I4;
6467                                 f2i_opcode = OP_MOVE_F_TO_I4;
6468                                 i2f_opcode = OP_MOVE_I4_TO_F;
6469                                 cfg->has_atomic_cas_i4 = TRUE;
6470                         }
6471 #if SIZEOF_REGISTER == 8
6472                         else if (is_ref ||
6473                                  fsig->params [1]->type == MONO_TYPE_I8 ||
6474                                  fsig->params [1]->type == MONO_TYPE_R8 ||
6475                                  fsig->params [1]->type == MONO_TYPE_I) {
6476                                 opcode = OP_ATOMIC_CAS_I8;
6477                                 f2i_opcode = OP_MOVE_F_TO_I8;
6478                                 i2f_opcode = OP_MOVE_I8_TO_F;
6479                         }
6480 #else
6481                         else if (is_ref || fsig->params [1]->type == MONO_TYPE_I) {
6482                                 opcode = OP_ATOMIC_CAS_I4;
6483                                 cfg->has_atomic_cas_i4 = TRUE;
6484                         }
6485 #endif
6486                         else
6487                                 return NULL;
6488
6489                         if (!mono_arch_opcode_supported (opcode))
6490                                 return NULL;
6491
6492                         if (is_float) {
6493                                 /* TODO: Decompose these opcodes instead of bailing here. */
6494                                 if (COMPILE_SOFT_FLOAT (cfg))
6495                                         return NULL;
6496
6497                                 MONO_INST_NEW (cfg, f2i_new, f2i_opcode);
6498                                 f2i_new->dreg = mono_alloc_ireg (cfg);
6499                                 f2i_new->sreg1 = args [1]->dreg;
6500                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6501                                         f2i_new->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6502                                 MONO_ADD_INS (cfg->cbb, f2i_new);
6503
6504                                 MONO_INST_NEW (cfg, f2i_cmp, f2i_opcode);
6505                                 f2i_cmp->dreg = mono_alloc_ireg (cfg);
6506                                 f2i_cmp->sreg1 = args [2]->dreg;
6507                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6508                                         f2i_cmp->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6509                                 MONO_ADD_INS (cfg->cbb, f2i_cmp);
6510                         }
6511
6512                         MONO_INST_NEW (cfg, ins, opcode);
6513                         ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
6514                         ins->sreg1 = args [0]->dreg;
6515                         ins->sreg2 = is_float ? f2i_new->dreg : args [1]->dreg;
6516                         ins->sreg3 = is_float ? f2i_cmp->dreg : args [2]->dreg;
6517                         MONO_ADD_INS (cfg->cbb, ins);
6518
6519                         switch (fsig->params [1]->type) {
6520                         case MONO_TYPE_I4:
6521                                 ins->type = STACK_I4;
6522                                 break;
6523                         case MONO_TYPE_I8:
6524                                 ins->type = STACK_I8;
6525                                 break;
6526                         case MONO_TYPE_I:
6527 #if SIZEOF_REGISTER == 8
6528                                 ins->type = STACK_I8;
6529 #else
6530                                 ins->type = STACK_I4;
6531 #endif
6532                                 break;
6533                         case MONO_TYPE_R4:
6534                                 ins->type = cfg->r4_stack_type;
6535                                 break;
6536                         case MONO_TYPE_R8:
6537                                 ins->type = STACK_R8;
6538                                 break;
6539                         default:
6540                                 g_assert (mini_type_is_reference (fsig->params [1]));
6541                                 ins->type = STACK_OBJ;
6542                                 break;
6543                         }
6544
6545                         if (is_float) {
6546                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6547                                 i2f->dreg = mono_alloc_freg (cfg);
6548                                 i2f->sreg1 = ins->dreg;
6549                                 i2f->type = STACK_R8;
6550                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6551                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6552                                 MONO_ADD_INS (cfg->cbb, i2f);
6553
6554                                 ins = i2f;
6555                         }
6556
6557                         if (cfg->gen_write_barriers && is_ref)
6558                                 emit_write_barrier (cfg, args [0], args [1]);
6559                 }
6560                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 4 &&
6561                          fsig->params [1]->type == MONO_TYPE_I4) {
6562                         MonoInst *cmp, *ceq;
6563
6564                         if (!mono_arch_opcode_supported (OP_ATOMIC_CAS_I4))
6565                                 return NULL;
6566
6567                         /* int32 r = CAS (location, value, comparand); */
6568                         MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
6569                         ins->dreg = alloc_ireg (cfg);
6570                         ins->sreg1 = args [0]->dreg;
6571                         ins->sreg2 = args [1]->dreg;
6572                         ins->sreg3 = args [2]->dreg;
6573                         ins->type = STACK_I4;
6574                         MONO_ADD_INS (cfg->cbb, ins);
6575
6576                         /* bool result = r == comparand; */
6577                         MONO_INST_NEW (cfg, cmp, OP_ICOMPARE);
6578                         cmp->sreg1 = ins->dreg;
6579                         cmp->sreg2 = args [2]->dreg;
6580                         cmp->type = STACK_I4;
6581                         MONO_ADD_INS (cfg->cbb, cmp);
6582
6583                         MONO_INST_NEW (cfg, ceq, OP_ICEQ);
6584                         ceq->dreg = alloc_ireg (cfg);
6585                         ceq->type = STACK_I4;
6586                         MONO_ADD_INS (cfg->cbb, ceq);
6587
6588                         /* *success = result; */
6589                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, args [3]->dreg, 0, ceq->dreg);
6590
6591                         cfg->has_atomic_cas_i4 = TRUE;
6592                 }
6593                 else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0)
6594                         ins = emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6595
6596                 if (ins)
6597                         return ins;
6598         } else if (cmethod->klass->image == mono_defaults.corlib &&
6599                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6600                            (strcmp (cmethod->klass->name, "Volatile") == 0)) {
6601                 ins = NULL;
6602
6603                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Read") && fsig->param_count == 1) {
6604                         guint32 opcode = 0;
6605                         MonoType *t = fsig->params [0];
6606                         gboolean is_ref;
6607                         gboolean is_float = t->type == MONO_TYPE_R4 || t->type == MONO_TYPE_R8;
6608
6609                         g_assert (t->byref);
6610                         /* t is a byref type, so the reference check is more complicated */
6611                         is_ref = mini_type_is_reference (&mono_class_from_mono_type (t)->byval_arg);
6612                         if (t->type == MONO_TYPE_I1)
6613                                 opcode = OP_ATOMIC_LOAD_I1;
6614                         else if (t->type == MONO_TYPE_U1 || t->type == MONO_TYPE_BOOLEAN)
6615                                 opcode = OP_ATOMIC_LOAD_U1;
6616                         else if (t->type == MONO_TYPE_I2)
6617                                 opcode = OP_ATOMIC_LOAD_I2;
6618                         else if (t->type == MONO_TYPE_U2)
6619                                 opcode = OP_ATOMIC_LOAD_U2;
6620                         else if (t->type == MONO_TYPE_I4)
6621                                 opcode = OP_ATOMIC_LOAD_I4;
6622                         else if (t->type == MONO_TYPE_U4)
6623                                 opcode = OP_ATOMIC_LOAD_U4;
6624                         else if (t->type == MONO_TYPE_R4)
6625                                 opcode = OP_ATOMIC_LOAD_R4;
6626                         else if (t->type == MONO_TYPE_R8)
6627                                 opcode = OP_ATOMIC_LOAD_R8;
6628 #if SIZEOF_REGISTER == 8
6629                         else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_I)
6630                                 opcode = OP_ATOMIC_LOAD_I8;
6631                         else if (is_ref || t->type == MONO_TYPE_U8 || t->type == MONO_TYPE_U)
6632                                 opcode = OP_ATOMIC_LOAD_U8;
6633 #else
6634                         else if (t->type == MONO_TYPE_I)
6635                                 opcode = OP_ATOMIC_LOAD_I4;
6636                         else if (is_ref || t->type == MONO_TYPE_U)
6637                                 opcode = OP_ATOMIC_LOAD_U4;
6638 #endif
6639
6640                         if (opcode) {
6641                                 if (!mono_arch_opcode_supported (opcode))
6642                                         return NULL;
6643
6644                                 MONO_INST_NEW (cfg, ins, opcode);
6645                                 ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : (is_float ? mono_alloc_freg (cfg) : mono_alloc_ireg (cfg));
6646                                 ins->sreg1 = args [0]->dreg;
6647                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_ACQ;
6648                                 MONO_ADD_INS (cfg->cbb, ins);
6649
6650                                 switch (t->type) {
6651                                 case MONO_TYPE_BOOLEAN:
6652                                 case MONO_TYPE_I1:
6653                                 case MONO_TYPE_U1:
6654                                 case MONO_TYPE_I2:
6655                                 case MONO_TYPE_U2:
6656                                 case MONO_TYPE_I4:
6657                                 case MONO_TYPE_U4:
6658                                         ins->type = STACK_I4;
6659                                         break;
6660                                 case MONO_TYPE_I8:
6661                                 case MONO_TYPE_U8:
6662                                         ins->type = STACK_I8;
6663                                         break;
6664                                 case MONO_TYPE_I:
6665                                 case MONO_TYPE_U:
6666 #if SIZEOF_REGISTER == 8
6667                                         ins->type = STACK_I8;
6668 #else
6669                                         ins->type = STACK_I4;
6670 #endif
6671                                         break;
6672                                 case MONO_TYPE_R4:
6673                                         ins->type = cfg->r4_stack_type;
6674                                         break;
6675                                 case MONO_TYPE_R8:
6676                                         ins->type = STACK_R8;
6677                                         break;
6678                                 default:
6679                                         g_assert (is_ref);
6680                                         ins->type = STACK_OBJ;
6681                                         break;
6682                                 }
6683                         }
6684                 }
6685
6686                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Write") && fsig->param_count == 2) {
6687                         guint32 opcode = 0;
6688                         MonoType *t = fsig->params [0];
6689                         gboolean is_ref;
6690
6691                         g_assert (t->byref);
6692                         is_ref = mini_type_is_reference (&mono_class_from_mono_type (t)->byval_arg);
6693                         if (t->type == MONO_TYPE_I1)
6694                                 opcode = OP_ATOMIC_STORE_I1;
6695                         else if (t->type == MONO_TYPE_U1 || t->type == MONO_TYPE_BOOLEAN)
6696                                 opcode = OP_ATOMIC_STORE_U1;
6697                         else if (t->type == MONO_TYPE_I2)
6698                                 opcode = OP_ATOMIC_STORE_I2;
6699                         else if (t->type == MONO_TYPE_U2)
6700                                 opcode = OP_ATOMIC_STORE_U2;
6701                         else if (t->type == MONO_TYPE_I4)
6702                                 opcode = OP_ATOMIC_STORE_I4;
6703                         else if (t->type == MONO_TYPE_U4)
6704                                 opcode = OP_ATOMIC_STORE_U4;
6705                         else if (t->type == MONO_TYPE_R4)
6706                                 opcode = OP_ATOMIC_STORE_R4;
6707                         else if (t->type == MONO_TYPE_R8)
6708                                 opcode = OP_ATOMIC_STORE_R8;
6709 #if SIZEOF_REGISTER == 8
6710                         else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_I)
6711                                 opcode = OP_ATOMIC_STORE_I8;
6712                         else if (is_ref || t->type == MONO_TYPE_U8 || t->type == MONO_TYPE_U)
6713                                 opcode = OP_ATOMIC_STORE_U8;
6714 #else
6715                         else if (t->type == MONO_TYPE_I)
6716                                 opcode = OP_ATOMIC_STORE_I4;
6717                         else if (is_ref || t->type == MONO_TYPE_U)
6718                                 opcode = OP_ATOMIC_STORE_U4;
6719 #endif
6720
6721                         if (opcode) {
6722                                 if (!mono_arch_opcode_supported (opcode))
6723                                         return NULL;
6724
6725                                 MONO_INST_NEW (cfg, ins, opcode);
6726                                 ins->dreg = args [0]->dreg;
6727                                 ins->sreg1 = args [1]->dreg;
6728                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_REL;
6729                                 MONO_ADD_INS (cfg->cbb, ins);
6730
6731                                 if (cfg->gen_write_barriers && is_ref)
6732                                         emit_write_barrier (cfg, args [0], args [1]);
6733                         }
6734                 }
6735
6736                 if (ins)
6737                         return ins;
6738         } else if (cmethod->klass->image == mono_defaults.corlib &&
6739                            (strcmp (cmethod->klass->name_space, "System.Diagnostics") == 0) &&
6740                            (strcmp (cmethod->klass->name, "Debugger") == 0)) {
6741                 if (!strcmp (cmethod->name, "Break") && fsig->param_count == 0) {
6742                         if (should_insert_brekpoint (cfg->method)) {
6743                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
6744                         } else {
6745                                 MONO_INST_NEW (cfg, ins, OP_NOP);
6746                                 MONO_ADD_INS (cfg->cbb, ins);
6747                         }
6748                         return ins;
6749                 }
6750         } else if (cmethod->klass->image == mono_defaults.corlib &&
6751                    (strcmp (cmethod->klass->name_space, "System") == 0) &&
6752                    (strcmp (cmethod->klass->name, "Environment") == 0)) {
6753                 if (!strcmp (cmethod->name, "get_IsRunningOnWindows") && fsig->param_count == 0) {
6754 #ifdef TARGET_WIN32
6755                         EMIT_NEW_ICONST (cfg, ins, 1);
6756 #else
6757                         EMIT_NEW_ICONST (cfg, ins, 0);
6758 #endif
6759                 }
6760         } else if (cmethod->klass->image == mono_defaults.corlib &&
6761                            (strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
6762                            (strcmp (cmethod->klass->name, "Assembly") == 0)) {
6763                 if (cfg->llvm_only && !strcmp (cmethod->name, "GetExecutingAssembly")) {
6764                         /* No stack walks are currently available, so implement this as an intrinsic */
6765                         MonoInst *assembly_ins;
6766
6767                         EMIT_NEW_AOTCONST (cfg, assembly_ins, MONO_PATCH_INFO_IMAGE, cfg->method->klass->image);
6768                         ins = mono_emit_jit_icall (cfg, mono_get_assembly_object, &assembly_ins);
6769                         return ins;
6770                 }
6771         } else if (cmethod->klass->image == mono_defaults.corlib &&
6772                            (strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
6773                            (strcmp (cmethod->klass->name, "MethodBase") == 0)) {
6774                 if (cfg->llvm_only && !strcmp (cmethod->name, "GetCurrentMethod")) {
6775                         /* No stack walks are currently available, so implement this as an intrinsic */
6776                         MonoInst *method_ins;
6777                         MonoMethod *declaring = cfg->method;
6778
6779                         /* This returns the declaring generic method */
6780                         if (declaring->is_inflated)
6781                                 declaring = ((MonoMethodInflated*)cfg->method)->declaring;
6782                         EMIT_NEW_AOTCONST (cfg, method_ins, MONO_PATCH_INFO_METHODCONST, declaring);
6783                         ins = mono_emit_jit_icall (cfg, mono_get_method_object, &method_ins);
6784                         cfg->no_inline = TRUE;
6785                         if (cfg->method != cfg->current_method)
6786                                 inline_failure (cfg, "MethodBase:GetCurrentMethod ()");
6787                         return ins;
6788                 }
6789         } else if (cmethod->klass == mono_defaults.math_class) {
6790                 /* 
6791                  * There is general branchless code for Min/Max, but it does not work for 
6792                  * all inputs:
6793                  * http://everything2.com/?node_id=1051618
6794                  */
6795         } else if (((!strcmp (cmethod->klass->image->assembly->aname.name, "MonoMac") ||
6796                     !strcmp (cmethod->klass->image->assembly->aname.name, "monotouch")) &&
6797                                 !strcmp (cmethod->klass->name_space, "XamCore.ObjCRuntime") &&
6798                                 !strcmp (cmethod->klass->name, "Selector")) ||
6799                            (!strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.iOS") &&
6800                                 !strcmp (cmethod->klass->name_space, "ObjCRuntime") &&
6801                                 !strcmp (cmethod->klass->name, "Selector"))
6802                            ) {
6803                 if (cfg->backend->have_objc_get_selector &&
6804                         !strcmp (cmethod->name, "GetHandle") && fsig->param_count == 1 &&
6805                     (args [0]->opcode == OP_GOT_ENTRY || args [0]->opcode == OP_AOTCONST) &&
6806                     cfg->compile_aot && !cfg->llvm_only) {
6807                         MonoInst *pi;
6808                         MonoJumpInfoToken *ji;
6809                         MonoString *s;
6810
6811                         // FIXME: llvmonly
6812
6813                         cfg->exception_message = g_strdup ("GetHandle");
6814                         cfg->disable_llvm = TRUE;
6815
6816                         if (args [0]->opcode == OP_GOT_ENTRY) {
6817                                 pi = (MonoInst *)args [0]->inst_p1;
6818                                 g_assert (pi->opcode == OP_PATCH_INFO);
6819                                 g_assert (GPOINTER_TO_INT (pi->inst_p1) == MONO_PATCH_INFO_LDSTR);
6820                                 ji = (MonoJumpInfoToken *)pi->inst_p0;
6821                         } else {
6822                                 g_assert (GPOINTER_TO_INT (args [0]->inst_p1) == MONO_PATCH_INFO_LDSTR);
6823                                 ji = (MonoJumpInfoToken *)args [0]->inst_p0;
6824                         }
6825
6826                         NULLIFY_INS (args [0]);
6827
6828                         // FIXME: Ugly
6829                         s = mono_ldstr_checked (cfg->domain, ji->image, mono_metadata_token_index (ji->token), &cfg->error);
6830                         return_val_if_nok (&cfg->error, NULL);
6831                         MONO_INST_NEW (cfg, ins, OP_OBJC_GET_SELECTOR);
6832                         ins->dreg = mono_alloc_ireg (cfg);
6833                         // FIXME: Leaks
6834                         ins->inst_p0 = mono_string_to_utf8_checked (s, &cfg->error);
6835                         return_val_if_nok (&cfg->error, NULL);
6836                         MONO_ADD_INS (cfg->cbb, ins);
6837                         return ins;
6838                 }
6839         }
6840
6841 #ifdef MONO_ARCH_SIMD_INTRINSICS
6842         if (cfg->opt & MONO_OPT_SIMD) {
6843                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
6844                 if (ins)
6845                         return ins;
6846         }
6847 #endif
6848
6849         ins = mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
6850         if (ins)
6851                 return ins;
6852
6853         if (COMPILE_LLVM (cfg)) {
6854                 ins = llvm_emit_inst_for_method (cfg, cmethod, fsig, args);
6855                 if (ins)
6856                         return ins;
6857         }
6858
6859         return mono_arch_emit_inst_for_method (cfg, cmethod, fsig, args);
6860 }
6861
6862 /*
6863  * This entry point could be used later for arbitrary method
6864  * redirection.
6865  */
6866 inline static MonoInst*
6867 mini_redirect_call (MonoCompile *cfg, MonoMethod *method,  
6868                                         MonoMethodSignature *signature, MonoInst **args, MonoInst *this_ins)
6869 {
6870         if (method->klass == mono_defaults.string_class) {
6871                 /* managed string allocation support */
6872                 if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && !(cfg->opt & MONO_OPT_SHARED)) {
6873                         MonoInst *iargs [2];
6874                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
6875                         MonoMethod *managed_alloc = NULL;
6876
6877                         g_assert (vtable); /*Should not fail since it System.String*/
6878 #ifndef MONO_CROSS_COMPILE
6879                         managed_alloc = mono_gc_get_managed_allocator (method->klass, FALSE, FALSE);
6880 #endif
6881                         if (!managed_alloc)
6882                                 return NULL;
6883                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
6884                         iargs [1] = args [0];
6885                         return mono_emit_method_call (cfg, managed_alloc, iargs, this_ins);
6886                 }
6887         }
6888         return NULL;
6889 }
6890
6891 static void
6892 mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp)
6893 {
6894         MonoInst *store, *temp;
6895         int i;
6896
6897         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
6898                 MonoType *argtype = (sig->hasthis && (i == 0)) ? type_from_stack_type (*sp) : sig->params [i - sig->hasthis];
6899
6900                 /*
6901                  * FIXME: We should use *args++ = sp [0], but that would mean the arg
6902                  * would be different than the MonoInst's used to represent arguments, and
6903                  * the ldelema implementation can't deal with that.
6904                  * Solution: When ldelema is used on an inline argument, create a var for 
6905                  * it, emit ldelema on that var, and emit the saving code below in
6906                  * inline_method () if needed.
6907                  */
6908                 temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
6909                 cfg->args [i] = temp;
6910                 /* This uses cfg->args [i] which is set by the preceeding line */
6911                 EMIT_NEW_ARGSTORE (cfg, store, i, *sp);
6912                 store->cil_code = sp [0]->cil_code;
6913                 sp++;
6914         }
6915 }
6916
6917 #define MONO_INLINE_CALLED_LIMITED_METHODS 1
6918 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
6919
6920 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6921 static gboolean
6922 check_inline_called_method_name_limit (MonoMethod *called_method)
6923 {
6924         int strncmp_result;
6925         static const char *limit = NULL;
6926         
6927         if (limit == NULL) {
6928                 const char *limit_string = g_getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
6929
6930                 if (limit_string != NULL)
6931                         limit = limit_string;
6932                 else
6933                         limit = "";
6934         }
6935
6936         if (limit [0] != '\0') {
6937                 char *called_method_name = mono_method_full_name (called_method, TRUE);
6938
6939                 strncmp_result = strncmp (called_method_name, limit, strlen (limit));
6940                 g_free (called_method_name);
6941         
6942                 //return (strncmp_result <= 0);
6943                 return (strncmp_result == 0);
6944         } else {
6945                 return TRUE;
6946         }
6947 }
6948 #endif
6949
6950 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6951 static gboolean
6952 check_inline_caller_method_name_limit (MonoMethod *caller_method)
6953 {
6954         int strncmp_result;
6955         static const char *limit = NULL;
6956         
6957         if (limit == NULL) {
6958                 const char *limit_string = g_getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
6959                 if (limit_string != NULL) {
6960                         limit = limit_string;
6961                 } else {
6962                         limit = "";
6963                 }
6964         }
6965
6966         if (limit [0] != '\0') {
6967                 char *caller_method_name = mono_method_full_name (caller_method, TRUE);
6968
6969                 strncmp_result = strncmp (caller_method_name, limit, strlen (limit));
6970                 g_free (caller_method_name);
6971         
6972                 //return (strncmp_result <= 0);
6973                 return (strncmp_result == 0);
6974         } else {
6975                 return TRUE;
6976         }
6977 }
6978 #endif
6979
6980 static void
6981 emit_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6982 {
6983         static double r8_0 = 0.0;
6984         static float r4_0 = 0.0;
6985         MonoInst *ins;
6986         int t;
6987
6988         rtype = mini_get_underlying_type (rtype);
6989         t = rtype->type;
6990
6991         if (rtype->byref) {
6992                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6993         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6994                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
6995         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6996                 MONO_EMIT_NEW_I8CONST (cfg, dreg, 0);
6997         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6998                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
6999                 ins->type = STACK_R4;
7000                 ins->inst_p0 = (void*)&r4_0;
7001                 ins->dreg = dreg;
7002                 MONO_ADD_INS (cfg->cbb, ins);
7003         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
7004                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
7005                 ins->type = STACK_R8;
7006                 ins->inst_p0 = (void*)&r8_0;
7007                 ins->dreg = dreg;
7008                 MONO_ADD_INS (cfg->cbb, ins);
7009         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
7010                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
7011                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
7012         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
7013                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
7014         } else {
7015                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
7016         }
7017 }
7018
7019 static void
7020 emit_dummy_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
7021 {
7022         int t;
7023
7024         rtype = mini_get_underlying_type (rtype);
7025         t = rtype->type;
7026
7027         if (rtype->byref) {
7028                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_PCONST);
7029         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
7030                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_ICONST);
7031         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
7032                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_I8CONST);
7033         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
7034                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R4CONST);
7035         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
7036                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R8CONST);
7037         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
7038                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
7039                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
7040         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
7041                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
7042         } else {
7043                 emit_init_rvar (cfg, dreg, rtype);
7044         }
7045 }
7046
7047 /* If INIT is FALSE, emit dummy initialization statements to keep the IR valid */
7048 static void
7049 emit_init_local (MonoCompile *cfg, int local, MonoType *type, gboolean init)
7050 {
7051         MonoInst *var = cfg->locals [local];
7052         if (COMPILE_SOFT_FLOAT (cfg)) {
7053                 MonoInst *store;
7054                 int reg = alloc_dreg (cfg, (MonoStackType)var->type);
7055                 emit_init_rvar (cfg, reg, type);
7056                 EMIT_NEW_LOCSTORE (cfg, store, local, cfg->cbb->last_ins);
7057         } else {
7058                 if (init)
7059                         emit_init_rvar (cfg, var->dreg, type);
7060                 else
7061                         emit_dummy_init_rvar (cfg, var->dreg, type);
7062         }
7063 }
7064
7065 /*
7066  * inline_method:
7067  *
7068  *   Return the cost of inlining CMETHOD.
7069  */
7070 static int
7071 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
7072                            guchar *ip, guint real_offset, gboolean inline_always)
7073 {
7074         MonoError error;
7075         MonoInst *ins, *rvar = NULL;
7076         MonoMethodHeader *cheader;
7077         MonoBasicBlock *ebblock, *sbblock;
7078         int i, costs;
7079         MonoMethod *prev_inlined_method;
7080         MonoInst **prev_locals, **prev_args;
7081         MonoType **prev_arg_types;
7082         guint prev_real_offset;
7083         GHashTable *prev_cbb_hash;
7084         MonoBasicBlock **prev_cil_offset_to_bb;
7085         MonoBasicBlock *prev_cbb;
7086         unsigned char* prev_cil_start;
7087         guint32 prev_cil_offset_to_bb_len;
7088         MonoMethod *prev_current_method;
7089         MonoGenericContext *prev_generic_context;
7090         gboolean ret_var_set, prev_ret_var_set, prev_disable_inline, virtual_ = FALSE;
7091
7092         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
7093
7094 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
7095         if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod))
7096                 return 0;
7097 #endif
7098 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
7099         if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method))
7100                 return 0;
7101 #endif
7102
7103         if (!fsig)
7104                 fsig = mono_method_signature (cmethod);
7105
7106         if (cfg->verbose_level > 2)
7107                 printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
7108
7109         if (!cmethod->inline_info) {
7110                 cfg->stat_inlineable_methods++;
7111                 cmethod->inline_info = 1;
7112         }
7113
7114         /* allocate local variables */
7115         cheader = mono_method_get_header_checked (cmethod, &error);
7116         if (!cheader) {
7117                 if (inline_always) {
7118                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
7119                         mono_error_move (&cfg->error, &error);
7120                 } else {
7121                         mono_error_cleanup (&error);
7122                 }
7123                 return 0;
7124         }
7125
7126         /*Must verify before creating locals as it can cause the JIT to assert.*/
7127         if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
7128                 mono_metadata_free_mh (cheader);
7129                 return 0;
7130         }
7131
7132         /* allocate space to store the return value */
7133         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
7134                 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
7135         }
7136
7137         prev_locals = cfg->locals;
7138         cfg->locals = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));
7139         for (i = 0; i < cheader->num_locals; ++i)
7140                 cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
7141
7142         /* allocate start and end blocks */
7143         /* This is needed so if the inline is aborted, we can clean up */
7144         NEW_BBLOCK (cfg, sbblock);
7145         sbblock->real_offset = real_offset;
7146
7147         NEW_BBLOCK (cfg, ebblock);
7148         ebblock->block_num = cfg->num_bblocks++;
7149         ebblock->real_offset = real_offset;
7150
7151         prev_args = cfg->args;
7152         prev_arg_types = cfg->arg_types;
7153         prev_inlined_method = cfg->inlined_method;
7154         cfg->inlined_method = cmethod;
7155         cfg->ret_var_set = FALSE;
7156         cfg->inline_depth ++;
7157         prev_real_offset = cfg->real_offset;
7158         prev_cbb_hash = cfg->cbb_hash;
7159         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
7160         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
7161         prev_cil_start = cfg->cil_start;
7162         prev_cbb = cfg->cbb;
7163         prev_current_method = cfg->current_method;
7164         prev_generic_context = cfg->generic_context;
7165         prev_ret_var_set = cfg->ret_var_set;
7166         prev_disable_inline = cfg->disable_inline;
7167
7168         if (ip && *ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
7169                 virtual_ = TRUE;
7170
7171         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, sp, real_offset, virtual_);
7172
7173         ret_var_set = cfg->ret_var_set;
7174
7175         cfg->inlined_method = prev_inlined_method;
7176         cfg->real_offset = prev_real_offset;
7177         cfg->cbb_hash = prev_cbb_hash;
7178         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
7179         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
7180         cfg->cil_start = prev_cil_start;
7181         cfg->locals = prev_locals;
7182         cfg->args = prev_args;
7183         cfg->arg_types = prev_arg_types;
7184         cfg->current_method = prev_current_method;
7185         cfg->generic_context = prev_generic_context;
7186         cfg->ret_var_set = prev_ret_var_set;
7187         cfg->disable_inline = prev_disable_inline;
7188         cfg->inline_depth --;
7189
7190         if ((costs >= 0 && costs < 60) || inline_always || (costs >= 0 && (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))) {
7191                 if (cfg->verbose_level > 2)
7192                         printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
7193                 
7194                 cfg->stat_inlined_methods++;
7195
7196                 /* always add some code to avoid block split failures */
7197                 MONO_INST_NEW (cfg, ins, OP_NOP);
7198                 MONO_ADD_INS (prev_cbb, ins);
7199
7200                 prev_cbb->next_bb = sbblock;
7201                 link_bblock (cfg, prev_cbb, sbblock);
7202
7203                 /* 
7204                  * Get rid of the begin and end bblocks if possible to aid local
7205                  * optimizations.
7206                  */
7207                 mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
7208
7209                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
7210                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
7211
7212                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
7213                         MonoBasicBlock *prev = ebblock->in_bb [0];
7214
7215                         if (prev->next_bb == ebblock) {
7216                                 mono_merge_basic_blocks (cfg, prev, ebblock);
7217                                 cfg->cbb = prev;
7218                                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
7219                                         mono_merge_basic_blocks (cfg, prev_cbb, prev);
7220                                         cfg->cbb = prev_cbb;
7221                                 }
7222                         } else {
7223                                 /* There could be a bblock after 'prev', and making 'prev' the current bb could cause problems */
7224                                 cfg->cbb = ebblock;
7225                         }
7226                 } else {
7227                         /* 
7228                          * Its possible that the rvar is set in some prev bblock, but not in others.
7229                          * (#1835).
7230                          */
7231                         if (rvar) {
7232                                 MonoBasicBlock *bb;
7233
7234                                 for (i = 0; i < ebblock->in_count; ++i) {
7235                                         bb = ebblock->in_bb [i];
7236
7237                                         if (bb->last_ins && bb->last_ins->opcode == OP_NOT_REACHED) {
7238                                                 cfg->cbb = bb;
7239
7240                                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
7241                                         }
7242                                 }
7243                         }
7244
7245                         cfg->cbb = ebblock;
7246                 }
7247
7248                 if (rvar) {
7249                         /*
7250                          * If the inlined method contains only a throw, then the ret var is not 
7251                          * set, so set it to a dummy value.
7252                          */
7253                         if (!ret_var_set)
7254                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
7255
7256                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
7257                         *sp++ = ins;
7258                 }
7259                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
7260                 return costs + 1;
7261         } else {
7262                 if (cfg->verbose_level > 2)
7263                         printf ("INLINE ABORTED %s (cost %d)\n", mono_method_full_name (cmethod, TRUE), costs);
7264                 cfg->exception_type = MONO_EXCEPTION_NONE;
7265
7266                 /* This gets rid of the newly added bblocks */
7267                 cfg->cbb = prev_cbb;
7268         }
7269         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
7270         return 0;
7271 }
7272
7273 /*
7274  * Some of these comments may well be out-of-date.
7275  * Design decisions: we do a single pass over the IL code (and we do bblock 
7276  * splitting/merging in the few cases when it's required: a back jump to an IL
7277  * address that was not already seen as bblock starting point).
7278  * Code is validated as we go (full verification is still better left to metadata/verify.c).
7279  * Complex operations are decomposed in simpler ones right away. We need to let the 
7280  * arch-specific code peek and poke inside this process somehow (except when the 
7281  * optimizations can take advantage of the full semantic info of coarse opcodes).
7282  * All the opcodes of the form opcode.s are 'normalized' to opcode.
7283  * MonoInst->opcode initially is the IL opcode or some simplification of that 
7284  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
7285  * opcode with value bigger than OP_LAST.
7286  * At this point the IR can be handed over to an interpreter, a dumb code generator
7287  * or to the optimizing code generator that will translate it to SSA form.
7288  *
7289  * Profiling directed optimizations.
7290  * We may compile by default with few or no optimizations and instrument the code
7291  * or the user may indicate what methods to optimize the most either in a config file
7292  * or through repeated runs where the compiler applies offline the optimizations to 
7293  * each method and then decides if it was worth it.
7294  */
7295
7296 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
7297 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
7298 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
7299 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
7300 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
7301 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
7302 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
7303 #define CHECK_TYPELOAD(klass) if (!(klass) || mono_class_has_failure (klass)) TYPE_LOAD_ERROR ((klass))
7304
7305 /* offset from br.s -> br like opcodes */
7306 #define BIG_BRANCH_OFFSET 13
7307
7308 static gboolean
7309 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
7310 {
7311         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
7312
7313         return b == NULL || b == bb;
7314 }
7315
7316 static int
7317 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
7318 {
7319         unsigned char *ip = start;
7320         unsigned char *target;
7321         int i;
7322         guint cli_addr;
7323         MonoBasicBlock *bblock;
7324         const MonoOpcode *opcode;
7325
7326         while (ip < end) {
7327                 cli_addr = ip - start;
7328                 i = mono_opcode_value ((const guint8 **)&ip, end);
7329                 if (i < 0)
7330                         UNVERIFIED;
7331                 opcode = &mono_opcodes [i];
7332                 switch (opcode->argument) {
7333                 case MonoInlineNone:
7334                         ip++; 
7335                         break;
7336                 case MonoInlineString:
7337                 case MonoInlineType:
7338                 case MonoInlineField:
7339                 case MonoInlineMethod:
7340                 case MonoInlineTok:
7341                 case MonoInlineSig:
7342                 case MonoShortInlineR:
7343                 case MonoInlineI:
7344                         ip += 5;
7345                         break;
7346                 case MonoInlineVar:
7347                         ip += 3;
7348                         break;
7349                 case MonoShortInlineVar:
7350                 case MonoShortInlineI:
7351                         ip += 2;
7352                         break;
7353                 case MonoShortInlineBrTarget:
7354                         target = start + cli_addr + 2 + (signed char)ip [1];
7355                         GET_BBLOCK (cfg, bblock, target);
7356                         ip += 2;
7357                         if (ip < end)
7358                                 GET_BBLOCK (cfg, bblock, ip);
7359                         break;
7360                 case MonoInlineBrTarget:
7361                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
7362                         GET_BBLOCK (cfg, bblock, target);
7363                         ip += 5;
7364                         if (ip < end)
7365                                 GET_BBLOCK (cfg, bblock, ip);
7366                         break;
7367                 case MonoInlineSwitch: {
7368                         guint32 n = read32 (ip + 1);
7369                         guint32 j;
7370                         ip += 5;
7371                         cli_addr += 5 + 4 * n;
7372                         target = start + cli_addr;
7373                         GET_BBLOCK (cfg, bblock, target);
7374                         
7375                         for (j = 0; j < n; ++j) {
7376                                 target = start + cli_addr + (gint32)read32 (ip);
7377                                 GET_BBLOCK (cfg, bblock, target);
7378                                 ip += 4;
7379                         }
7380                         break;
7381                 }
7382                 case MonoInlineR:
7383                 case MonoInlineI8:
7384                         ip += 9;
7385                         break;
7386                 default:
7387                         g_assert_not_reached ();
7388                 }
7389
7390                 if (i == CEE_THROW) {
7391                         unsigned char *bb_start = ip - 1;
7392                         
7393                         /* Find the start of the bblock containing the throw */
7394                         bblock = NULL;
7395                         while ((bb_start >= start) && !bblock) {
7396                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
7397                                 bb_start --;
7398                         }
7399                         if (bblock)
7400                                 bblock->out_of_line = 1;
7401                 }
7402         }
7403         return 0;
7404 unverified:
7405 exception_exit:
7406         *pos = ip;
7407         return 1;
7408 }
7409
7410 static inline MonoMethod *
7411 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context, MonoError *error)
7412 {
7413         MonoMethod *method;
7414
7415         mono_error_init (error);
7416
7417         if (m->wrapper_type != MONO_WRAPPER_NONE) {
7418                 method = (MonoMethod *)mono_method_get_wrapper_data (m, token);
7419                 if (context) {
7420                         method = mono_class_inflate_generic_method_checked (method, context, error);
7421                 }
7422         } else {
7423                 method = mono_get_method_checked (m->klass->image, token, klass, context, error);
7424         }
7425
7426         return method;
7427 }
7428
7429 static inline MonoMethod *
7430 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
7431 {
7432         MonoError error;
7433         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context, cfg ? &cfg->error : &error);
7434
7435         if (method && cfg && !cfg->gshared && mono_class_is_open_constructed_type (&method->klass->byval_arg)) {
7436                 mono_error_set_bad_image (&cfg->error, cfg->method->klass->image, "Method with open type while not compiling gshared");
7437                 method = NULL;
7438         }
7439
7440         if (!method && !cfg)
7441                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
7442
7443         return method;
7444 }
7445
7446 static inline MonoClass*
7447 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
7448 {
7449         MonoError error;
7450         MonoClass *klass;
7451
7452         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7453                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
7454                 if (context) {
7455                         klass = mono_class_inflate_generic_class_checked (klass, context, &error);
7456                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7457                 }
7458         } else {
7459                 klass = mono_class_get_and_inflate_typespec_checked (method->klass->image, token, context, &error);
7460                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
7461         }
7462         if (klass)
7463                 mono_class_init (klass);
7464         return klass;
7465 }
7466
7467 static inline MonoMethodSignature*
7468 mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context, MonoError *error)
7469 {
7470         MonoMethodSignature *fsig;
7471
7472         mono_error_init (error);
7473         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7474                 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
7475         } else {
7476                 fsig = mono_metadata_parse_signature_checked (method->klass->image, token, error);
7477                 return_val_if_nok (error, NULL);
7478         }
7479         if (context) {
7480                 fsig = mono_inflate_generic_signature(fsig, context, error);
7481         }
7482         return fsig;
7483 }
7484
7485 static MonoMethod*
7486 throw_exception (void)
7487 {
7488         static MonoMethod *method = NULL;
7489
7490         if (!method) {
7491                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
7492                 method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
7493         }
7494         g_assert (method);
7495         return method;
7496 }
7497
7498 static void
7499 emit_throw_exception (MonoCompile *cfg, MonoException *ex)
7500 {
7501         MonoMethod *thrower = throw_exception ();
7502         MonoInst *args [1];
7503
7504         EMIT_NEW_PCONST (cfg, args [0], ex);
7505         mono_emit_method_call (cfg, thrower, args, NULL);
7506 }
7507
7508 /*
7509  * Return the original method is a wrapper is specified. We can only access 
7510  * the custom attributes from the original method.
7511  */
7512 static MonoMethod*
7513 get_original_method (MonoMethod *method)
7514 {
7515         if (method->wrapper_type == MONO_WRAPPER_NONE)
7516                 return method;
7517
7518         /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
7519         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
7520                 return NULL;
7521
7522         /* in other cases we need to find the original method */
7523         return mono_marshal_method_from_wrapper (method);
7524 }
7525
7526 static void
7527 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field)
7528 {
7529         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7530         MonoException *ex = mono_security_core_clr_is_field_access_allowed (get_original_method (caller), field);
7531         if (ex)
7532                 emit_throw_exception (cfg, ex);
7533 }
7534
7535 static void
7536 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
7537 {
7538         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7539         MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
7540         if (ex)
7541                 emit_throw_exception (cfg, ex);
7542 }
7543
7544 /*
7545  * Check that the IL instructions at ip are the array initialization
7546  * sequence and return the pointer to the data and the size.
7547  */
7548 static const char*
7549 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
7550 {
7551         /*
7552          * newarr[System.Int32]
7553          * dup
7554          * ldtoken field valuetype ...
7555          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
7556          */
7557         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
7558                 MonoError error;
7559                 guint32 token = read32 (ip + 7);
7560                 guint32 field_token = read32 (ip + 2);
7561                 guint32 field_index = field_token & 0xffffff;
7562                 guint32 rva;
7563                 const char *data_ptr;
7564                 int size = 0;
7565                 MonoMethod *cmethod;
7566                 MonoClass *dummy_class;
7567                 MonoClassField *field = mono_field_from_token_checked (method->klass->image, field_token, &dummy_class, NULL, &error);
7568                 int dummy_align;
7569
7570                 if (!field) {
7571                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7572                         return NULL;
7573                 }
7574
7575                 *out_field_token = field_token;
7576
7577                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
7578                 if (!cmethod)
7579                         return NULL;
7580                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
7581                         return NULL;
7582                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
7583                 case MONO_TYPE_BOOLEAN:
7584                 case MONO_TYPE_I1:
7585                 case MONO_TYPE_U1:
7586                         size = 1; break;
7587                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
7588 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
7589                 case MONO_TYPE_CHAR:
7590                 case MONO_TYPE_I2:
7591                 case MONO_TYPE_U2:
7592                         size = 2; break;
7593                 case MONO_TYPE_I4:
7594                 case MONO_TYPE_U4:
7595                 case MONO_TYPE_R4:
7596                         size = 4; break;
7597                 case MONO_TYPE_R8:
7598                 case MONO_TYPE_I8:
7599                 case MONO_TYPE_U8:
7600                         size = 8; break;
7601 #endif
7602                 default:
7603                         return NULL;
7604                 }
7605                 size *= len;
7606                 if (size > mono_type_size (field->type, &dummy_align))
7607                     return NULL;
7608                 *out_size = size;
7609                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
7610                 if (!image_is_dynamic (method->klass->image)) {
7611                         field_index = read32 (ip + 2) & 0xffffff;
7612                         mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
7613                         data_ptr = mono_image_rva_map (method->klass->image, rva);
7614                         /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
7615                         /* for aot code we do the lookup on load */
7616                         if (aot && data_ptr)
7617                                 return (const char *)GUINT_TO_POINTER (rva);
7618                 } else {
7619                         /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
7620                         g_assert (!aot);
7621                         data_ptr = mono_field_get_data (field);
7622                 }
7623                 return data_ptr;
7624         }
7625         return NULL;
7626 }
7627
7628 static void
7629 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
7630 {
7631         MonoError error;
7632         char *method_fname = mono_method_full_name (method, TRUE);
7633         char *method_code;
7634         MonoMethodHeader *header = mono_method_get_header_checked (method, &error);
7635
7636         if (!header) {
7637                 method_code = g_strdup_printf ("could not parse method body due to %s", mono_error_get_message (&error));
7638                 mono_error_cleanup (&error);
7639         } else if (header->code_size == 0)
7640                 method_code = g_strdup ("method body is empty.");
7641         else
7642                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
7643         mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code));
7644         g_free (method_fname);
7645         g_free (method_code);
7646         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
7647 }
7648
7649 static void
7650 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
7651 {
7652         MonoInst *ins;
7653         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
7654         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
7655                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
7656                 /* Optimize reg-reg moves away */
7657                 /* 
7658                  * Can't optimize other opcodes, since sp[0] might point to
7659                  * the last ins of a decomposed opcode.
7660                  */
7661                 sp [0]->dreg = (cfg)->locals [n]->dreg;
7662         } else {
7663                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
7664         }
7665 }
7666
7667 /*
7668  * ldloca inhibits many optimizations so try to get rid of it in common
7669  * cases.
7670  */
7671 static inline unsigned char *
7672 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
7673 {
7674         int local, token;
7675         MonoClass *klass;
7676         MonoType *type;
7677
7678         if (size == 1) {
7679                 local = ip [1];
7680                 ip += 2;
7681         } else {
7682                 local = read16 (ip + 2);
7683                 ip += 4;
7684         }
7685         
7686         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
7687                 /* From the INITOBJ case */
7688                 token = read32 (ip + 2);
7689                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
7690                 CHECK_TYPELOAD (klass);
7691                 type = mini_get_underlying_type (&klass->byval_arg);
7692                 emit_init_local (cfg, local, type, TRUE);
7693                 return ip + 6;
7694         }
7695  exception_exit:
7696         return NULL;
7697 }
7698
7699 static MonoInst*
7700 emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used, MonoInst **sp)
7701 {
7702         MonoInst *icall_args [16];
7703         MonoInst *call_target, *ins, *vtable_ins;
7704         int arg_reg, this_reg, vtable_reg;
7705         gboolean is_iface = cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE;
7706         gboolean is_gsharedvt = cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig);
7707         gboolean variant_iface = FALSE;
7708         guint32 slot;
7709         int offset;
7710
7711         /*
7712          * In llvm-only mode, vtables contain function descriptors instead of
7713          * method addresses/trampolines.
7714          */
7715         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
7716
7717         if (is_iface)
7718                 slot = mono_method_get_imt_slot (cmethod);
7719         else
7720                 slot = mono_method_get_vtable_index (cmethod);
7721
7722         this_reg = sp [0]->dreg;
7723
7724         if (is_iface && mono_class_has_variant_generic_params (cmethod->klass))
7725                 variant_iface = TRUE;
7726
7727         if (!fsig->generic_param_count && !is_iface && !is_gsharedvt) {
7728                 /*
7729                  * The simplest case, a normal virtual call.
7730                  */
7731                 int slot_reg = alloc_preg (cfg);
7732                 int addr_reg = alloc_preg (cfg);
7733                 int arg_reg = alloc_preg (cfg);
7734                 MonoBasicBlock *non_null_bb;
7735
7736                 vtable_reg = alloc_preg (cfg);
7737                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7738                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) + (slot * SIZEOF_VOID_P);
7739
7740                 /* Load the vtable slot, which contains a function descriptor. */
7741                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7742
7743                 NEW_BBLOCK (cfg, non_null_bb);
7744
7745                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, slot_reg, 0);
7746                 cfg->cbb->last_ins->flags |= MONO_INST_LIKELY;
7747                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, non_null_bb);
7748
7749                 /* Slow path */
7750                 // FIXME: Make the wrapper use the preserveall cconv
7751                 // FIXME: Use one icall per slot for small slot numbers ?
7752                 icall_args [0] = vtable_ins;
7753                 EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7754                 /* Make the icall return the vtable slot value to save some code space */
7755                 ins = mono_emit_jit_icall (cfg, mono_init_vtable_slot, icall_args);
7756                 ins->dreg = slot_reg;
7757                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, non_null_bb);
7758
7759                 /* Fastpath */
7760                 MONO_START_BB (cfg, non_null_bb);
7761                 /* Load the address + arg from the vtable slot */
7762                 EMIT_NEW_LOAD_MEMBASE (cfg, call_target, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7763                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, arg_reg, slot_reg, SIZEOF_VOID_P);
7764
7765                 return emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
7766         }
7767
7768         if (!fsig->generic_param_count && is_iface && !variant_iface && !is_gsharedvt) {
7769                 /*
7770                  * A simple interface call
7771                  *
7772                  * We make a call through an imt slot to obtain the function descriptor we need to call.
7773                  * The imt slot contains a function descriptor for a runtime function + arg.
7774                  */
7775                 int slot_reg = alloc_preg (cfg);
7776                 int addr_reg = alloc_preg (cfg);
7777                 int arg_reg = alloc_preg (cfg);
7778                 MonoInst *thunk_addr_ins, *thunk_arg_ins, *ftndesc_ins;
7779
7780                 vtable_reg = alloc_preg (cfg);
7781                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7782                 offset = ((gint32)slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
7783
7784                 /*
7785                  * The slot is already initialized when the vtable is created so there is no need
7786                  * to check it here.
7787                  */
7788
7789                 /* Load the imt slot, which contains a function descriptor. */
7790                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7791
7792                 /* Load the address + arg of the imt thunk from the imt slot */
7793                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_addr_ins, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7794                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_arg_ins, OP_LOAD_MEMBASE, arg_reg, slot_reg, SIZEOF_VOID_P);
7795                 /*
7796                  * IMT thunks in llvm-only mode are C functions which take an info argument
7797                  * plus the imt method and return the ftndesc to call.
7798                  */
7799                 icall_args [0] = thunk_arg_ins;
7800                 icall_args [1] = emit_get_rgctx_method (cfg, context_used,
7801                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7802                 ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_thunk, icall_args, thunk_addr_ins, NULL, NULL);
7803
7804                 return emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
7805         }
7806
7807         if ((fsig->generic_param_count || variant_iface) && !is_gsharedvt) {
7808                 /*
7809                  * This is similar to the interface case, the vtable slot points to an imt thunk which is
7810                  * dynamically extended as more instantiations are discovered.
7811                  * This handles generic virtual methods both on classes and interfaces.
7812                  */
7813                 int slot_reg = alloc_preg (cfg);
7814                 int addr_reg = alloc_preg (cfg);
7815                 int arg_reg = alloc_preg (cfg);
7816                 int ftndesc_reg = alloc_preg (cfg);
7817                 MonoInst *thunk_addr_ins, *thunk_arg_ins, *ftndesc_ins;
7818                 MonoBasicBlock *slowpath_bb, *end_bb;
7819
7820                 NEW_BBLOCK (cfg, slowpath_bb);
7821                 NEW_BBLOCK (cfg, end_bb);
7822
7823                 vtable_reg = alloc_preg (cfg);
7824                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7825                 if (is_iface)
7826                         offset = ((gint32)slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
7827                 else
7828                         offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) + (slot * SIZEOF_VOID_P);
7829
7830                 /* Load the slot, which contains a function descriptor. */
7831                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7832
7833                 /* These slots are not initialized, so fall back to the slow path until they are initialized */
7834                 /* That happens when mono_method_add_generic_virtual_invocation () creates an IMT thunk */
7835                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, slot_reg, 0);
7836                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, slowpath_bb);
7837
7838                 /* Fastpath */
7839                 /* Same as with iface calls */
7840                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_addr_ins, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7841                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_arg_ins, OP_LOAD_MEMBASE, arg_reg, slot_reg, SIZEOF_VOID_P);
7842                 icall_args [0] = thunk_arg_ins;
7843                 icall_args [1] = emit_get_rgctx_method (cfg, context_used,
7844                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7845                 ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_thunk, icall_args, thunk_addr_ins, NULL, NULL);
7846                 ftndesc_ins->dreg = ftndesc_reg;
7847                 /*
7848                  * Unlike normal iface calls, these imt thunks can return NULL, i.e. when they are passed an instantiation
7849                  * they don't know about yet. Fall back to the slowpath in that case.
7850                  */
7851                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ftndesc_reg, 0);
7852                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, slowpath_bb);
7853
7854                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
7855
7856                 /* Slowpath */
7857                 MONO_START_BB (cfg, slowpath_bb);
7858                 icall_args [0] = vtable_ins;
7859                 EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7860                 icall_args [2] = emit_get_rgctx_method (cfg, context_used,
7861                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7862                 if (is_iface)
7863                         ftndesc_ins = mono_emit_jit_icall (cfg, mono_resolve_generic_virtual_iface_call, icall_args);
7864                 else
7865                         ftndesc_ins = mono_emit_jit_icall (cfg, mono_resolve_generic_virtual_call, icall_args);
7866                 ftndesc_ins->dreg = ftndesc_reg;
7867                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
7868
7869                 /* Common case */
7870                 MONO_START_BB (cfg, end_bb);
7871                 return emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
7872         }
7873
7874         /*
7875          * Non-optimized cases
7876          */
7877         icall_args [0] = sp [0];
7878         EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7879
7880         icall_args [2] = emit_get_rgctx_method (cfg, context_used,
7881                                                                                         cmethod, MONO_RGCTX_INFO_METHOD);
7882
7883         arg_reg = alloc_preg (cfg);
7884         MONO_EMIT_NEW_PCONST (cfg, arg_reg, NULL);
7885         EMIT_NEW_VARLOADA_VREG (cfg, icall_args [3], arg_reg, &mono_defaults.int_class->byval_arg);
7886
7887         g_assert (is_gsharedvt);
7888         if (is_iface)
7889                 call_target = mono_emit_jit_icall (cfg, mono_resolve_iface_call_gsharedvt, icall_args);
7890         else
7891                 call_target = mono_emit_jit_icall (cfg, mono_resolve_vcall_gsharedvt, icall_args);
7892
7893         /*
7894          * Pass the extra argument even if the callee doesn't receive it, most
7895          * calling conventions allow this.
7896          */
7897         return emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
7898 }
7899
7900 static gboolean
7901 is_exception_class (MonoClass *klass)
7902 {
7903         while (klass) {
7904                 if (klass == mono_defaults.exception_class)
7905                         return TRUE;
7906                 klass = klass->parent;
7907         }
7908         return FALSE;
7909 }
7910
7911 /*
7912  * is_jit_optimizer_disabled:
7913  *
7914  *   Determine whenever M's assembly has a DebuggableAttribute with the
7915  * IsJITOptimizerDisabled flag set.
7916  */
7917 static gboolean
7918 is_jit_optimizer_disabled (MonoMethod *m)
7919 {
7920         MonoError error;
7921         MonoAssembly *ass = m->klass->image->assembly;
7922         MonoCustomAttrInfo* attrs;
7923         MonoClass *klass;
7924         int i;
7925         gboolean val = FALSE;
7926
7927         g_assert (ass);
7928         if (ass->jit_optimizer_disabled_inited)
7929                 return ass->jit_optimizer_disabled;
7930
7931         klass = mono_class_try_get_debuggable_attribute_class ();
7932
7933         if (!klass) {
7934                 /* Linked away */
7935                 ass->jit_optimizer_disabled = FALSE;
7936                 mono_memory_barrier ();
7937                 ass->jit_optimizer_disabled_inited = TRUE;
7938                 return FALSE;
7939         }
7940
7941         attrs = mono_custom_attrs_from_assembly_checked (ass, &error);
7942         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7943         if (attrs) {
7944                 for (i = 0; i < attrs->num_attrs; ++i) {
7945                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
7946                         const gchar *p;
7947                         MonoMethodSignature *sig;
7948
7949                         if (!attr->ctor || attr->ctor->klass != klass)
7950                                 continue;
7951                         /* Decode the attribute. See reflection.c */
7952                         p = (const char*)attr->data;
7953                         g_assert (read16 (p) == 0x0001);
7954                         p += 2;
7955
7956                         // FIXME: Support named parameters
7957                         sig = mono_method_signature (attr->ctor);
7958                         if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
7959                                 continue;
7960                         /* Two boolean arguments */
7961                         p ++;
7962                         val = *p;
7963                 }
7964                 mono_custom_attrs_free (attrs);
7965         }
7966
7967         ass->jit_optimizer_disabled = val;
7968         mono_memory_barrier ();
7969         ass->jit_optimizer_disabled_inited = TRUE;
7970
7971         return val;
7972 }
7973
7974 static gboolean
7975 is_supported_tail_call (MonoCompile *cfg, MonoMethod *method, MonoMethod *cmethod, MonoMethodSignature *fsig, int call_opcode)
7976 {
7977         gboolean supported_tail_call;
7978         int i;
7979
7980         supported_tail_call = mono_arch_tail_call_supported (cfg, mono_method_signature (method), mono_method_signature (cmethod));
7981
7982         for (i = 0; i < fsig->param_count; ++i) {
7983                 if (fsig->params [i]->byref || fsig->params [i]->type == MONO_TYPE_PTR || fsig->params [i]->type == MONO_TYPE_FNPTR)
7984                         /* These can point to the current method's stack */
7985                         supported_tail_call = FALSE;
7986         }
7987         if (fsig->hasthis && cmethod->klass->valuetype)
7988                 /* this might point to the current method's stack */
7989                 supported_tail_call = FALSE;
7990         if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
7991                 supported_tail_call = FALSE;
7992         if (cfg->method->save_lmf)
7993                 supported_tail_call = FALSE;
7994         if (cmethod->wrapper_type && cmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
7995                 supported_tail_call = FALSE;
7996         if (call_opcode != CEE_CALL)
7997                 supported_tail_call = FALSE;
7998
7999         /* Debugging support */
8000 #if 0
8001         if (supported_tail_call) {
8002                 if (!mono_debug_count ())
8003                         supported_tail_call = FALSE;
8004         }
8005 #endif
8006
8007         return supported_tail_call;
8008 }
8009
8010 /*
8011  * handle_ctor_call:
8012  *
8013  *   Handle calls made to ctors from NEWOBJ opcodes.
8014  */
8015 static void
8016 handle_ctor_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used,
8017                                   MonoInst **sp, guint8 *ip, int *inline_costs)
8018 {
8019         MonoInst *vtable_arg = NULL, *callvirt_this_arg = NULL, *ins;
8020
8021         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
8022                                         mono_method_is_generic_sharable (cmethod, TRUE)) {
8023                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
8024                         mono_class_vtable (cfg->domain, cmethod->klass);
8025                         CHECK_TYPELOAD (cmethod->klass);
8026
8027                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
8028                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
8029                 } else {
8030                         if (context_used) {
8031                                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
8032                                                                                                    cmethod->klass, MONO_RGCTX_INFO_VTABLE);
8033                         } else {
8034                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
8035
8036                                 CHECK_TYPELOAD (cmethod->klass);
8037                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
8038                         }
8039                 }
8040         }
8041
8042         /* Avoid virtual calls to ctors if possible */
8043         if (mono_class_is_marshalbyref (cmethod->klass))
8044                 callvirt_this_arg = sp [0];
8045
8046         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
8047                 g_assert (MONO_TYPE_IS_VOID (fsig->ret));
8048                 CHECK_CFG_EXCEPTION;
8049         } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
8050                            mono_method_check_inlining (cfg, cmethod) &&
8051                            !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE)) {
8052                 int costs;
8053
8054                 if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, FALSE))) {
8055                         cfg->real_offset += 5;
8056
8057                         *inline_costs += costs - 5;
8058                 } else {
8059                         INLINE_FAILURE ("inline failure");
8060                         // FIXME-VT: Clean this up
8061                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
8062                                 GSHAREDVT_FAILURE(*ip);
8063                         mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, callvirt_this_arg, NULL, NULL);
8064                 }
8065         } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
8066                 MonoInst *addr;
8067
8068                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
8069
8070                 if (cfg->llvm_only) {
8071                         // FIXME: Avoid initializing vtable_arg
8072                         emit_llvmonly_calli (cfg, fsig, sp, addr);
8073                 } else {
8074                         mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
8075                 }
8076         } else if (context_used &&
8077                            ((!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
8078                                  !mono_class_generic_sharing_enabled (cmethod->klass)) || cfg->gsharedvt)) {
8079                 MonoInst *cmethod_addr;
8080
8081                 /* Generic calls made out of gsharedvt methods cannot be patched, so use an indirect call */
8082
8083                 if (cfg->llvm_only) {
8084                         MonoInst *addr = emit_get_rgctx_method (cfg, context_used, cmethod,
8085                                                                                                         MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
8086                         emit_llvmonly_calli (cfg, fsig, sp, addr);
8087                 } else {
8088                         cmethod_addr = emit_get_rgctx_method (cfg, context_used,
8089                                                                                                   cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
8090
8091                         mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
8092                 }
8093         } else {
8094                 INLINE_FAILURE ("ctor call");
8095                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
8096                                                                                   callvirt_this_arg, NULL, vtable_arg);
8097         }
8098  exception_exit:
8099         return;
8100 }
8101
8102 static void
8103 emit_setret (MonoCompile *cfg, MonoInst *val)
8104 {
8105         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (cfg->method)->ret);
8106         MonoInst *ins;
8107
8108         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
8109                 MonoInst *ret_addr;
8110
8111                 if (!cfg->vret_addr) {
8112                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, val);
8113                 } else {
8114                         EMIT_NEW_RETLOADA (cfg, ret_addr);
8115
8116                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, val->dreg);
8117                         ins->klass = mono_class_from_mono_type (ret_type);
8118                 }
8119         } else {
8120 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
8121                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
8122                         MonoInst *iargs [1];
8123                         MonoInst *conv;
8124
8125                         iargs [0] = val;
8126                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
8127                         mono_arch_emit_setret (cfg, cfg->method, conv);
8128                 } else {
8129                         mono_arch_emit_setret (cfg, cfg->method, val);
8130                 }
8131 #else
8132                 mono_arch_emit_setret (cfg, cfg->method, val);
8133 #endif
8134         }
8135 }
8136
8137 /*
8138  * mono_method_to_ir:
8139  *
8140  *   Translate the .net IL into linear IR.
8141  */
8142 int
8143 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
8144                    MonoInst *return_var, MonoInst **inline_args, 
8145                    guint inline_offset, gboolean is_virtual_call)
8146 {
8147         MonoError error;
8148         MonoInst *ins, **sp, **stack_start;
8149         MonoBasicBlock *tblock = NULL, *init_localsbb = NULL;
8150         MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
8151         MonoMethod *cmethod, *method_definition;
8152         MonoInst **arg_array;
8153         MonoMethodHeader *header;
8154         MonoImage *image;
8155         guint32 token, ins_flag;
8156         MonoClass *klass;
8157         MonoClass *constrained_class = NULL;
8158         unsigned char *ip, *end, *target, *err_pos;
8159         MonoMethodSignature *sig;
8160         MonoGenericContext *generic_context = NULL;
8161         MonoGenericContainer *generic_container = NULL;
8162         MonoType **param_types;
8163         int i, n, start_new_bblock, dreg;
8164         int num_calls = 0, inline_costs = 0;
8165         int breakpoint_id = 0;
8166         guint num_args;
8167         GSList *class_inits = NULL;
8168         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
8169         int context_used;
8170         gboolean init_locals, seq_points, skip_dead_blocks;
8171         gboolean sym_seq_points = FALSE;
8172         MonoDebugMethodInfo *minfo;
8173         MonoBitSet *seq_point_locs = NULL;
8174         MonoBitSet *seq_point_set_locs = NULL;
8175
8176         cfg->disable_inline = is_jit_optimizer_disabled (method);
8177
8178         /* serialization and xdomain stuff may need access to private fields and methods */
8179         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
8180         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
8181         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
8182         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
8183         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
8184         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
8185
8186         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
8187         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
8188         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
8189         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
8190         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF;
8191
8192         image = method->klass->image;
8193         header = mono_method_get_header_checked (method, &cfg->error);
8194         if (!header) {
8195                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
8196                 goto exception_exit;
8197         }
8198         generic_container = mono_method_get_generic_container (method);
8199         sig = mono_method_signature (method);
8200         num_args = sig->hasthis + sig->param_count;
8201         ip = (unsigned char*)header->code;
8202         cfg->cil_start = ip;
8203         end = ip + header->code_size;
8204         cfg->stat_cil_code_size += header->code_size;
8205
8206         seq_points = cfg->gen_seq_points && cfg->method == method;
8207
8208         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
8209                 /* We could hit a seq point before attaching to the JIT (#8338) */
8210                 seq_points = FALSE;
8211         }
8212
8213         if (cfg->gen_sdb_seq_points && cfg->method == method) {
8214                 minfo = mono_debug_lookup_method (method);
8215                 if (minfo) {
8216                         MonoSymSeqPoint *sps;
8217                         int i, n_il_offsets;
8218
8219                         mono_debug_get_seq_points (minfo, NULL, NULL, NULL, &sps, &n_il_offsets);
8220                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
8221                         seq_point_set_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
8222                         sym_seq_points = TRUE;
8223                         for (i = 0; i < n_il_offsets; ++i) {
8224                                 if (sps [i].il_offset < header->code_size)
8225                                         mono_bitset_set_fast (seq_point_locs, sps [i].il_offset);
8226                         }
8227                         g_free (sps);
8228                 } else if (!method->wrapper_type && !method->dynamic && mono_debug_image_has_debug_info (method->klass->image)) {
8229                         /* Methods without line number info like auto-generated property accessors */
8230                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
8231                         seq_point_set_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
8232                         sym_seq_points = TRUE;
8233                 }
8234         }
8235
8236         /* 
8237          * Methods without init_locals set could cause asserts in various passes
8238          * (#497220). To work around this, we emit dummy initialization opcodes
8239          * (OP_DUMMY_ICONST etc.) which generate no code. These are only supported
8240          * on some platforms.
8241          */
8242         if ((cfg->opt & MONO_OPT_UNSAFE) && cfg->backend->have_dummy_init)
8243                 init_locals = header->init_locals;
8244         else
8245                 init_locals = TRUE;
8246
8247         method_definition = method;
8248         while (method_definition->is_inflated) {
8249                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
8250                 method_definition = imethod->declaring;
8251         }
8252
8253         /* SkipVerification is not allowed if core-clr is enabled */
8254         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
8255                 dont_verify = TRUE;
8256                 dont_verify_stloc = TRUE;
8257         }
8258
8259         if (sig->is_inflated)
8260                 generic_context = mono_method_get_context (method);
8261         else if (generic_container)
8262                 generic_context = &generic_container->context;
8263         cfg->generic_context = generic_context;
8264
8265         if (!cfg->gshared)
8266                 g_assert (!sig->has_type_parameters);
8267
8268         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
8269                 g_assert (method->is_inflated);
8270                 g_assert (mono_method_get_context (method)->method_inst);
8271         }
8272         if (method->is_inflated && mono_method_get_context (method)->method_inst)
8273                 g_assert (sig->generic_param_count);
8274
8275         if (cfg->method == method) {
8276                 cfg->real_offset = 0;
8277         } else {
8278                 cfg->real_offset = inline_offset;
8279         }
8280
8281         cfg->cil_offset_to_bb = (MonoBasicBlock **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
8282         cfg->cil_offset_to_bb_len = header->code_size;
8283
8284         cfg->current_method = method;
8285
8286         if (cfg->verbose_level > 2)
8287                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
8288
8289         param_types = (MonoType **)mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
8290         if (sig->hasthis)
8291                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
8292         for (n = 0; n < sig->param_count; ++n)
8293                 param_types [n + sig->hasthis] = sig->params [n];
8294         cfg->arg_types = param_types;
8295
8296         cfg->dont_inline = g_list_prepend (cfg->dont_inline, method);
8297         if (cfg->method == method) {
8298
8299                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
8300                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
8301
8302                 /* ENTRY BLOCK */
8303                 NEW_BBLOCK (cfg, start_bblock);
8304                 cfg->bb_entry = start_bblock;
8305                 start_bblock->cil_code = NULL;
8306                 start_bblock->cil_length = 0;
8307
8308                 /* EXIT BLOCK */
8309                 NEW_BBLOCK (cfg, end_bblock);
8310                 cfg->bb_exit = end_bblock;
8311                 end_bblock->cil_code = NULL;
8312                 end_bblock->cil_length = 0;
8313                 end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
8314                 g_assert (cfg->num_bblocks == 2);
8315
8316                 arg_array = cfg->args;
8317
8318                 if (header->num_clauses) {
8319                         cfg->spvars = g_hash_table_new (NULL, NULL);
8320                         cfg->exvars = g_hash_table_new (NULL, NULL);
8321                 }
8322                 /* handle exception clauses */
8323                 for (i = 0; i < header->num_clauses; ++i) {
8324                         MonoBasicBlock *try_bb;
8325                         MonoExceptionClause *clause = &header->clauses [i];
8326                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
8327
8328                         try_bb->real_offset = clause->try_offset;
8329                         try_bb->try_start = TRUE;
8330                         try_bb->region = ((i + 1) << 8) | clause->flags;
8331                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
8332                         tblock->real_offset = clause->handler_offset;
8333                         tblock->flags |= BB_EXCEPTION_HANDLER;
8334
8335                         /*
8336                          * Linking the try block with the EH block hinders inlining as we won't be able to 
8337                          * merge the bblocks from inlining and produce an artificial hole for no good reason.
8338                          */
8339                         if (COMPILE_LLVM (cfg))
8340                                 link_bblock (cfg, try_bb, tblock);
8341
8342                         if (*(ip + clause->handler_offset) == CEE_POP)
8343                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
8344
8345                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
8346                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
8347                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
8348                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
8349                                 MONO_ADD_INS (tblock, ins);
8350
8351                                 if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FILTER) {
8352                                         /* finally clauses already have a seq point */
8353                                         /* seq points for filter clauses are emitted below */
8354                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
8355                                         MONO_ADD_INS (tblock, ins);
8356                                 }
8357
8358                                 /* todo: is a fault block unsafe to optimize? */
8359                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
8360                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
8361                         }
8362
8363                         /*printf ("clause try IL_%04x to IL_%04x handler %d at IL_%04x to IL_%04x\n", clause->try_offset, clause->try_offset + clause->try_len, clause->flags, clause->handler_offset, clause->handler_offset + clause->handler_len);
8364                           while (p < end) {
8365                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
8366                           }*/
8367                         /* catch and filter blocks get the exception object on the stack */
8368                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
8369                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8370
8371                                 /* mostly like handle_stack_args (), but just sets the input args */
8372                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
8373                                 tblock->in_scount = 1;
8374                                 tblock->in_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
8375                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
8376
8377                                 cfg->cbb = tblock;
8378
8379 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
8380                                 /* The EH code passes in the exception in a register to both JITted and LLVM compiled code */
8381                                 if (!cfg->compile_llvm) {
8382                                         MONO_INST_NEW (cfg, ins, OP_GET_EX_OBJ);
8383                                         ins->dreg = tblock->in_stack [0]->dreg;
8384                                         MONO_ADD_INS (tblock, ins);
8385                                 }
8386 #else
8387                                 MonoInst *dummy_use;
8388
8389                                 /* 
8390                                  * Add a dummy use for the exvar so its liveness info will be
8391                                  * correct.
8392                                  */
8393                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
8394 #endif
8395
8396                                 if (seq_points && clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8397                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
8398                                         MONO_ADD_INS (tblock, ins);
8399                                 }
8400                                 
8401                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8402                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
8403                                         tblock->flags |= BB_EXCEPTION_HANDLER;
8404                                         tblock->real_offset = clause->data.filter_offset;
8405                                         tblock->in_scount = 1;
8406                                         tblock->in_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
8407                                         /* The filter block shares the exvar with the handler block */
8408                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
8409                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
8410                                         MONO_ADD_INS (tblock, ins);
8411                                 }
8412                         }
8413
8414                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
8415                                         clause->data.catch_class &&
8416                                         cfg->gshared &&
8417                                         mono_class_check_context_used (clause->data.catch_class)) {
8418                                 /*
8419                                  * In shared generic code with catch
8420                                  * clauses containing type variables
8421                                  * the exception handling code has to
8422                                  * be able to get to the rgctx.
8423                                  * Therefore we have to make sure that
8424                                  * the vtable/mrgctx argument (for
8425                                  * static or generic methods) or the
8426                                  * "this" argument (for non-static
8427                                  * methods) are live.
8428                                  */
8429                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8430                                                 mini_method_get_context (method)->method_inst ||
8431                                                 method->klass->valuetype) {
8432                                         mono_get_vtable_var (cfg);
8433                                 } else {
8434                                         MonoInst *dummy_use;
8435
8436                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
8437                                 }
8438                         }
8439                 }
8440         } else {
8441                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
8442                 cfg->cbb = start_bblock;
8443                 cfg->args = arg_array;
8444                 mono_save_args (cfg, sig, inline_args);
8445         }
8446
8447         /* FIRST CODE BLOCK */
8448         NEW_BBLOCK (cfg, tblock);
8449         tblock->cil_code = ip;
8450         cfg->cbb = tblock;
8451         cfg->ip = ip;
8452
8453         ADD_BBLOCK (cfg, tblock);
8454
8455         if (cfg->method == method) {
8456                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
8457                 if (breakpoint_id) {
8458                         MONO_INST_NEW (cfg, ins, OP_BREAK);
8459                         MONO_ADD_INS (cfg->cbb, ins);
8460                 }
8461         }
8462
8463         /* we use a separate basic block for the initialization code */
8464         NEW_BBLOCK (cfg, init_localsbb);
8465         cfg->bb_init = init_localsbb;
8466         init_localsbb->real_offset = cfg->real_offset;
8467         start_bblock->next_bb = init_localsbb;
8468         init_localsbb->next_bb = cfg->cbb;
8469         link_bblock (cfg, start_bblock, init_localsbb);
8470         link_bblock (cfg, init_localsbb, cfg->cbb);
8471                 
8472         cfg->cbb = init_localsbb;
8473
8474         if (cfg->gsharedvt && cfg->method == method) {
8475                 MonoGSharedVtMethodInfo *info;
8476                 MonoInst *var, *locals_var;
8477                 int dreg;
8478
8479                 info = (MonoGSharedVtMethodInfo *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoGSharedVtMethodInfo));
8480                 info->method = cfg->method;
8481                 info->count_entries = 16;
8482                 info->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
8483                 cfg->gsharedvt_info = info;
8484
8485                 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8486                 /* prevent it from being register allocated */
8487                 //var->flags |= MONO_INST_VOLATILE;
8488                 cfg->gsharedvt_info_var = var;
8489
8490                 ins = emit_get_rgctx_gsharedvt_method (cfg, mini_method_check_context_used (cfg, method), method, info);
8491                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, var->dreg, ins->dreg);
8492
8493                 /* Allocate locals */
8494                 locals_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8495                 /* prevent it from being register allocated */
8496                 //locals_var->flags |= MONO_INST_VOLATILE;
8497                 cfg->gsharedvt_locals_var = locals_var;
8498
8499                 dreg = alloc_ireg (cfg);
8500                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, dreg, var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, locals_size));
8501
8502                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
8503                 ins->dreg = locals_var->dreg;
8504                 ins->sreg1 = dreg;
8505                 MONO_ADD_INS (cfg->cbb, ins);
8506                 cfg->gsharedvt_locals_var_ins = ins;
8507                 
8508                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
8509                 /*
8510                 if (init_locals)
8511                         ins->flags |= MONO_INST_INIT;
8512                 */
8513         }
8514
8515         if (mono_security_core_clr_enabled ()) {
8516                 /* check if this is native code, e.g. an icall or a p/invoke */
8517                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
8518                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
8519                         if (wrapped) {
8520                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
8521                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
8522
8523                                 /* if this ia a native call then it can only be JITted from platform code */
8524                                 if ((icall || pinvk) && method->klass && method->klass->image) {
8525                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
8526                                                 MonoException *ex = icall ? mono_get_exception_security () : 
8527                                                         mono_get_exception_method_access ();
8528                                                 emit_throw_exception (cfg, ex);
8529                                         }
8530                                 }
8531                         }
8532                 }
8533         }
8534
8535         CHECK_CFG_EXCEPTION;
8536
8537         if (header->code_size == 0)
8538                 UNVERIFIED;
8539
8540         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
8541                 ip = err_pos;
8542                 UNVERIFIED;
8543         }
8544
8545         if (cfg->method == method)
8546                 mono_debug_init_method (cfg, cfg->cbb, breakpoint_id);
8547
8548         for (n = 0; n < header->num_locals; ++n) {
8549                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
8550                         UNVERIFIED;
8551         }
8552         class_inits = NULL;
8553
8554         /* We force the vtable variable here for all shared methods
8555            for the possibility that they might show up in a stack
8556            trace where their exact instantiation is needed. */
8557         if (cfg->gshared && method == cfg->method) {
8558                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8559                                 mini_method_get_context (method)->method_inst ||
8560                                 method->klass->valuetype) {
8561                         mono_get_vtable_var (cfg);
8562                 } else {
8563                         /* FIXME: Is there a better way to do this?
8564                            We need the variable live for the duration
8565                            of the whole method. */
8566                         cfg->args [0]->flags |= MONO_INST_VOLATILE;
8567                 }
8568         }
8569
8570         /* add a check for this != NULL to inlined methods */
8571         if (is_virtual_call) {
8572                 MonoInst *arg_ins;
8573
8574                 NEW_ARGLOAD (cfg, arg_ins, 0);
8575                 MONO_ADD_INS (cfg->cbb, arg_ins);
8576                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
8577         }
8578
8579         skip_dead_blocks = !dont_verify;
8580         if (skip_dead_blocks) {
8581                 original_bb = bb = mono_basic_block_split (method, &cfg->error, header);
8582                 CHECK_CFG_ERROR;
8583                 g_assert (bb);
8584         }
8585
8586         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
8587         stack_start = sp = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
8588
8589         ins_flag = 0;
8590         start_new_bblock = 0;
8591         while (ip < end) {
8592                 if (cfg->method == method)
8593                         cfg->real_offset = ip - header->code;
8594                 else
8595                         cfg->real_offset = inline_offset;
8596                 cfg->ip = ip;
8597
8598                 context_used = 0;
8599
8600                 if (start_new_bblock) {
8601                         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
8602                         if (start_new_bblock == 2) {
8603                                 g_assert (ip == tblock->cil_code);
8604                         } else {
8605                                 GET_BBLOCK (cfg, tblock, ip);
8606                         }
8607                         cfg->cbb->next_bb = tblock;
8608                         cfg->cbb = tblock;
8609                         start_new_bblock = 0;
8610                         for (i = 0; i < cfg->cbb->in_scount; ++i) {
8611                                 if (cfg->verbose_level > 3)
8612                                         printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8613                                 EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8614                                 *sp++ = ins;
8615                         }
8616                         if (class_inits)
8617                                 g_slist_free (class_inits);
8618                         class_inits = NULL;
8619                 } else {
8620                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != cfg->cbb)) {
8621                                 link_bblock (cfg, cfg->cbb, tblock);
8622                                 if (sp != stack_start) {
8623                                         handle_stack_args (cfg, stack_start, sp - stack_start);
8624                                         sp = stack_start;
8625                                         CHECK_UNVERIFIABLE (cfg);
8626                                 }
8627                                 cfg->cbb->next_bb = tblock;
8628                                 cfg->cbb = tblock;
8629                                 for (i = 0; i < cfg->cbb->in_scount; ++i) {
8630                                         if (cfg->verbose_level > 3)
8631                                                 printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8632                                         EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8633                                         *sp++ = ins;
8634                                 }
8635                                 g_slist_free (class_inits);
8636                                 class_inits = NULL;
8637                         }
8638                 }
8639
8640                 if (skip_dead_blocks) {
8641                         int ip_offset = ip - header->code;
8642
8643                         if (ip_offset == bb->end)
8644                                 bb = bb->next;
8645
8646                         if (bb->dead) {
8647                                 int op_size = mono_opcode_size (ip, end);
8648                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
8649
8650                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
8651
8652                                 if (ip_offset + op_size == bb->end) {
8653                                         MONO_INST_NEW (cfg, ins, OP_NOP);
8654                                         MONO_ADD_INS (cfg->cbb, ins);
8655                                         start_new_bblock = 1;
8656                                 }
8657
8658                                 ip += op_size;
8659                                 continue;
8660                         }
8661                 }
8662                 /*
8663                  * Sequence points are points where the debugger can place a breakpoint.
8664                  * Currently, we generate these automatically at points where the IL
8665                  * stack is empty.
8666                  */
8667                 if (seq_points && ((!sym_seq_points && (sp == stack_start)) || (sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code)))) {
8668                         /*
8669                          * Make methods interruptable at the beginning, and at the targets of
8670                          * backward branches.
8671                          * Also, do this at the start of every bblock in methods with clauses too,
8672                          * to be able to handle instructions with inprecise control flow like
8673                          * throw/endfinally.
8674                          * Backward branches are handled at the end of method-to-ir ().
8675                          */
8676                         gboolean intr_loc = ip == header->code || (!cfg->cbb->last_ins && cfg->header->num_clauses);
8677                         gboolean sym_seq_point = sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code);
8678
8679                         /* Avoid sequence points on empty IL like .volatile */
8680                         // FIXME: Enable this
8681                         //if (!(cfg->cbb->last_ins && cfg->cbb->last_ins->opcode == OP_SEQ_POINT)) {
8682                         NEW_SEQ_POINT (cfg, ins, ip - header->code, intr_loc);
8683                         if ((sp != stack_start) && !sym_seq_point)
8684                                 ins->flags |= MONO_INST_NONEMPTY_STACK;
8685                         MONO_ADD_INS (cfg->cbb, ins);
8686
8687                         if (sym_seq_points)
8688                                 mono_bitset_set_fast (seq_point_set_locs, ip - header->code);
8689                 }
8690
8691                 cfg->cbb->real_offset = cfg->real_offset;
8692
8693                 if ((cfg->method == method) && cfg->coverage_info) {
8694                         guint32 cil_offset = ip - header->code;
8695                         cfg->coverage_info->data [cil_offset].cil_code = ip;
8696
8697                         /* TODO: Use an increment here */
8698 #if defined(TARGET_X86)
8699                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
8700                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
8701                         ins->inst_imm = 1;
8702                         MONO_ADD_INS (cfg->cbb, ins);
8703 #else
8704                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
8705                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
8706 #endif
8707                 }
8708
8709                 if (cfg->verbose_level > 3)
8710                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
8711
8712                 switch (*ip) {
8713                 case CEE_NOP:
8714                         if (seq_points && !sym_seq_points && sp != stack_start) {
8715                                 /*
8716                                  * The C# compiler uses these nops to notify the JIT that it should
8717                                  * insert seq points.
8718                                  */
8719                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, FALSE);
8720                                 MONO_ADD_INS (cfg->cbb, ins);
8721                         }
8722                         if (cfg->keep_cil_nops)
8723                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
8724                         else
8725                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8726                         ip++;
8727                         MONO_ADD_INS (cfg->cbb, ins);
8728                         break;
8729                 case CEE_BREAK:
8730                         if (should_insert_brekpoint (cfg->method)) {
8731                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
8732                         } else {
8733                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8734                         }
8735                         ip++;
8736                         MONO_ADD_INS (cfg->cbb, ins);
8737                         break;
8738                 case CEE_LDARG_0:
8739                 case CEE_LDARG_1:
8740                 case CEE_LDARG_2:
8741                 case CEE_LDARG_3:
8742                         CHECK_STACK_OVF (1);
8743                         n = (*ip)-CEE_LDARG_0;
8744                         CHECK_ARG (n);
8745                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8746                         ip++;
8747                         *sp++ = ins;
8748                         break;
8749                 case CEE_LDLOC_0:
8750                 case CEE_LDLOC_1:
8751                 case CEE_LDLOC_2:
8752                 case CEE_LDLOC_3:
8753                         CHECK_STACK_OVF (1);
8754                         n = (*ip)-CEE_LDLOC_0;
8755                         CHECK_LOCAL (n);
8756                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8757                         ip++;
8758                         *sp++ = ins;
8759                         break;
8760                 case CEE_STLOC_0:
8761                 case CEE_STLOC_1:
8762                 case CEE_STLOC_2:
8763                 case CEE_STLOC_3: {
8764                         CHECK_STACK (1);
8765                         n = (*ip)-CEE_STLOC_0;
8766                         CHECK_LOCAL (n);
8767                         --sp;
8768                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
8769                                 UNVERIFIED;
8770                         emit_stloc_ir (cfg, sp, header, n);
8771                         ++ip;
8772                         inline_costs += 1;
8773                         break;
8774                         }
8775                 case CEE_LDARG_S:
8776                         CHECK_OPSIZE (2);
8777                         CHECK_STACK_OVF (1);
8778                         n = ip [1];
8779                         CHECK_ARG (n);
8780                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8781                         *sp++ = ins;
8782                         ip += 2;
8783                         break;
8784                 case CEE_LDARGA_S:
8785                         CHECK_OPSIZE (2);
8786                         CHECK_STACK_OVF (1);
8787                         n = ip [1];
8788                         CHECK_ARG (n);
8789                         NEW_ARGLOADA (cfg, ins, n);
8790                         MONO_ADD_INS (cfg->cbb, ins);
8791                         *sp++ = ins;
8792                         ip += 2;
8793                         break;
8794                 case CEE_STARG_S:
8795                         CHECK_OPSIZE (2);
8796                         CHECK_STACK (1);
8797                         --sp;
8798                         n = ip [1];
8799                         CHECK_ARG (n);
8800                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
8801                                 UNVERIFIED;
8802                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
8803                         ip += 2;
8804                         break;
8805                 case CEE_LDLOC_S:
8806                         CHECK_OPSIZE (2);
8807                         CHECK_STACK_OVF (1);
8808                         n = ip [1];
8809                         CHECK_LOCAL (n);
8810                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8811                         *sp++ = ins;
8812                         ip += 2;
8813                         break;
8814                 case CEE_LDLOCA_S: {
8815                         unsigned char *tmp_ip;
8816                         CHECK_OPSIZE (2);
8817                         CHECK_STACK_OVF (1);
8818                         CHECK_LOCAL (ip [1]);
8819
8820                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
8821                                 ip = tmp_ip;
8822                                 inline_costs += 1;
8823                                 break;
8824                         }
8825
8826                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
8827                         *sp++ = ins;
8828                         ip += 2;
8829                         break;
8830                 }
8831                 case CEE_STLOC_S:
8832                         CHECK_OPSIZE (2);
8833                         CHECK_STACK (1);
8834                         --sp;
8835                         CHECK_LOCAL (ip [1]);
8836                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
8837                                 UNVERIFIED;
8838                         emit_stloc_ir (cfg, sp, header, ip [1]);
8839                         ip += 2;
8840                         inline_costs += 1;
8841                         break;
8842                 case CEE_LDNULL:
8843                         CHECK_STACK_OVF (1);
8844                         EMIT_NEW_PCONST (cfg, ins, NULL);
8845                         ins->type = STACK_OBJ;
8846                         ++ip;
8847                         *sp++ = ins;
8848                         break;
8849                 case CEE_LDC_I4_M1:
8850                         CHECK_STACK_OVF (1);
8851                         EMIT_NEW_ICONST (cfg, ins, -1);
8852                         ++ip;
8853                         *sp++ = ins;
8854                         break;
8855                 case CEE_LDC_I4_0:
8856                 case CEE_LDC_I4_1:
8857                 case CEE_LDC_I4_2:
8858                 case CEE_LDC_I4_3:
8859                 case CEE_LDC_I4_4:
8860                 case CEE_LDC_I4_5:
8861                 case CEE_LDC_I4_6:
8862                 case CEE_LDC_I4_7:
8863                 case CEE_LDC_I4_8:
8864                         CHECK_STACK_OVF (1);
8865                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
8866                         ++ip;
8867                         *sp++ = ins;
8868                         break;
8869                 case CEE_LDC_I4_S:
8870                         CHECK_OPSIZE (2);
8871                         CHECK_STACK_OVF (1);
8872                         ++ip;
8873                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
8874                         ++ip;
8875                         *sp++ = ins;
8876                         break;
8877                 case CEE_LDC_I4:
8878                         CHECK_OPSIZE (5);
8879                         CHECK_STACK_OVF (1);
8880                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
8881                         ip += 5;
8882                         *sp++ = ins;
8883                         break;
8884                 case CEE_LDC_I8:
8885                         CHECK_OPSIZE (9);
8886                         CHECK_STACK_OVF (1);
8887                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
8888                         ins->type = STACK_I8;
8889                         ins->dreg = alloc_dreg (cfg, STACK_I8);
8890                         ++ip;
8891                         ins->inst_l = (gint64)read64 (ip);
8892                         MONO_ADD_INS (cfg->cbb, ins);
8893                         ip += 8;
8894                         *sp++ = ins;
8895                         break;
8896                 case CEE_LDC_R4: {
8897                         float *f;
8898                         gboolean use_aotconst = FALSE;
8899
8900 #ifdef TARGET_POWERPC
8901                         /* FIXME: Clean this up */
8902                         if (cfg->compile_aot)
8903                                 use_aotconst = TRUE;
8904 #endif
8905
8906                         /* FIXME: we should really allocate this only late in the compilation process */
8907                         f = (float *)mono_domain_alloc (cfg->domain, sizeof (float));
8908                         CHECK_OPSIZE (5);
8909                         CHECK_STACK_OVF (1);
8910
8911                         if (use_aotconst) {
8912                                 MonoInst *cons;
8913                                 int dreg;
8914
8915                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
8916
8917                                 dreg = alloc_freg (cfg);
8918                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
8919                                 ins->type = cfg->r4_stack_type;
8920                         } else {
8921                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
8922                                 ins->type = cfg->r4_stack_type;
8923                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8924                                 ins->inst_p0 = f;
8925                                 MONO_ADD_INS (cfg->cbb, ins);
8926                         }
8927                         ++ip;
8928                         readr4 (ip, f);
8929                         ip += 4;
8930                         *sp++ = ins;                    
8931                         break;
8932                 }
8933                 case CEE_LDC_R8: {
8934                         double *d;
8935                         gboolean use_aotconst = FALSE;
8936
8937 #ifdef TARGET_POWERPC
8938                         /* FIXME: Clean this up */
8939                         if (cfg->compile_aot)
8940                                 use_aotconst = TRUE;
8941 #endif
8942
8943                         /* FIXME: we should really allocate this only late in the compilation process */
8944                         d = (double *)mono_domain_alloc (cfg->domain, sizeof (double));
8945                         CHECK_OPSIZE (9);
8946                         CHECK_STACK_OVF (1);
8947
8948                         if (use_aotconst) {
8949                                 MonoInst *cons;
8950                                 int dreg;
8951
8952                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
8953
8954                                 dreg = alloc_freg (cfg);
8955                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
8956                                 ins->type = STACK_R8;
8957                         } else {
8958                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
8959                                 ins->type = STACK_R8;
8960                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8961                                 ins->inst_p0 = d;
8962                                 MONO_ADD_INS (cfg->cbb, ins);
8963                         }
8964                         ++ip;
8965                         readr8 (ip, d);
8966                         ip += 8;
8967                         *sp++ = ins;
8968                         break;
8969                 }
8970                 case CEE_DUP: {
8971                         MonoInst *temp, *store;
8972                         CHECK_STACK (1);
8973                         CHECK_STACK_OVF (1);
8974                         sp--;
8975                         ins = *sp;
8976
8977                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
8978                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
8979
8980                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8981                         *sp++ = ins;
8982
8983                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8984                         *sp++ = ins;
8985
8986                         ++ip;
8987                         inline_costs += 2;
8988                         break;
8989                 }
8990                 case CEE_POP:
8991                         CHECK_STACK (1);
8992                         ip++;
8993                         --sp;
8994
8995 #ifdef TARGET_X86
8996                         if (sp [0]->type == STACK_R8)
8997                                 /* we need to pop the value from the x86 FP stack */
8998                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
8999 #endif
9000                         break;
9001                 case CEE_JMP: {
9002                         MonoCallInst *call;
9003                         MonoMethodSignature *fsig;
9004                         int i, n;
9005
9006                         INLINE_FAILURE ("jmp");
9007                         GSHAREDVT_FAILURE (*ip);
9008
9009                         CHECK_OPSIZE (5);
9010                         if (stack_start != sp)
9011                                 UNVERIFIED;
9012                         token = read32 (ip + 1);
9013                         /* FIXME: check the signature matches */
9014                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
9015                         CHECK_CFG_ERROR;
9016  
9017                         if (cfg->gshared && mono_method_check_context_used (cmethod))
9018                                 GENERIC_SHARING_FAILURE (CEE_JMP);
9019
9020                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
9021
9022                         fsig = mono_method_signature (cmethod);
9023                         n = fsig->param_count + fsig->hasthis;
9024                         if (cfg->llvm_only) {
9025                                 MonoInst **args;
9026
9027                                 args = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
9028                                 for (i = 0; i < n; ++i)
9029                                         EMIT_NEW_ARGLOAD (cfg, args [i], i);
9030                                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, TRUE, args, NULL, NULL, NULL);
9031                                 /*
9032                                  * The code in mono-basic-block.c treats the rest of the code as dead, but we
9033                                  * have to emit a normal return since llvm expects it.
9034                                  */
9035                                 if (cfg->ret)
9036                                         emit_setret (cfg, ins);
9037                                 MONO_INST_NEW (cfg, ins, OP_BR);
9038                                 ins->inst_target_bb = end_bblock;
9039                                 MONO_ADD_INS (cfg->cbb, ins);
9040                                 link_bblock (cfg, cfg->cbb, end_bblock);
9041                                 ip += 5;
9042                                 break;
9043                         } else if (cfg->backend->have_op_tail_call) {
9044                                 /* Handle tail calls similarly to calls */
9045                                 DISABLE_AOT (cfg);
9046
9047                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
9048                                 call->method = cmethod;
9049                                 call->tail_call = TRUE;
9050                                 call->signature = mono_method_signature (cmethod);
9051                                 call->args = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
9052                                 call->inst.inst_p0 = cmethod;
9053                                 for (i = 0; i < n; ++i)
9054                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
9055
9056                                 mono_arch_emit_call (cfg, call);
9057                                 cfg->param_area = MAX(cfg->param_area, call->stack_usage);
9058                                 MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
9059                         } else {
9060                                 for (i = 0; i < num_args; ++i)
9061                                         /* Prevent arguments from being optimized away */
9062                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
9063
9064                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9065                                 ins = (MonoInst*)call;
9066                                 ins->inst_p0 = cmethod;
9067                                 MONO_ADD_INS (cfg->cbb, ins);
9068                         }
9069
9070                         ip += 5;
9071                         start_new_bblock = 1;
9072                         break;
9073                 }
9074                 case CEE_CALLI: {
9075                         MonoInst *addr;
9076                         MonoMethodSignature *fsig;
9077
9078                         CHECK_OPSIZE (5);
9079                         token = read32 (ip + 1);
9080
9081                         ins = NULL;
9082
9083                         //GSHAREDVT_FAILURE (*ip);
9084                         cmethod = NULL;
9085                         CHECK_STACK (1);
9086                         --sp;
9087                         addr = *sp;
9088                         fsig = mini_get_signature (method, token, generic_context, &cfg->error);
9089                         CHECK_CFG_ERROR;
9090
9091                         if (method->dynamic && fsig->pinvoke) {
9092                                 MonoInst *args [3];
9093
9094                                 /*
9095                                  * This is a call through a function pointer using a pinvoke
9096                                  * signature. Have to create a wrapper and call that instead.
9097                                  * FIXME: This is very slow, need to create a wrapper at JIT time
9098                                  * instead based on the signature.
9099                                  */
9100                                 EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
9101                                 EMIT_NEW_PCONST (cfg, args [1], fsig);
9102                                 args [2] = addr;
9103                                 addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
9104                         }
9105
9106                         n = fsig->param_count + fsig->hasthis;
9107
9108                         CHECK_STACK (n);
9109
9110                         //g_assert (!virtual_ || fsig->hasthis);
9111
9112                         sp -= n;
9113
9114                         inline_costs += 10 * num_calls++;
9115
9116                         /*
9117                          * Making generic calls out of gsharedvt methods.
9118                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9119                          * patching gshared method addresses into a gsharedvt method.
9120                          */
9121                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
9122                                 /*
9123                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
9124                                  */
9125                                 MonoInst *callee = addr;
9126
9127                                 if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
9128                                         /* Not tested */
9129                                         GSHAREDVT_FAILURE (*ip);
9130
9131                                 if (cfg->llvm_only)
9132                                         // FIXME:
9133                                         GSHAREDVT_FAILURE (*ip);
9134
9135                                 addr = emit_get_rgctx_sig (cfg, context_used,
9136                                                                                           fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
9137                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
9138                                 goto calli_end;
9139                         }
9140
9141                         /* Prevent inlining of methods with indirect calls */
9142                         INLINE_FAILURE ("indirect call");
9143
9144                         if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
9145                                 MonoJumpInfoType info_type;
9146                                 gpointer info_data;
9147
9148                                 /*
9149                                  * Instead of emitting an indirect call, emit a direct call
9150                                  * with the contents of the aotconst as the patch info.
9151                                  */
9152                                 if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
9153                                         info_type = (MonoJumpInfoType)addr->inst_c1;
9154                                         info_data = addr->inst_p0;
9155                                 } else {
9156                                         info_type = (MonoJumpInfoType)addr->inst_right->inst_c1;
9157                                         info_data = addr->inst_right->inst_left;
9158                                 }
9159
9160                                 if (info_type == MONO_PATCH_INFO_ICALL_ADDR) {
9161                                         ins = (MonoInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_ICALL_ADDR_CALL, info_data, fsig, sp);
9162                                         NULLIFY_INS (addr);
9163                                         goto calli_end;
9164                                 } else if (info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
9165                                         ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
9166                                         NULLIFY_INS (addr);
9167                                         goto calli_end;
9168                                 }
9169                         }
9170                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9171
9172                         calli_end:
9173
9174                         /* End of call, INS should contain the result of the call, if any */
9175
9176                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9177                                 g_assert (ins);
9178                                 *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
9179                         }
9180
9181                         CHECK_CFG_EXCEPTION;
9182
9183                         ip += 5;
9184                         ins_flag = 0;
9185                         constrained_class = NULL;
9186                         break;
9187                 }
9188                 case CEE_CALL:
9189                 case CEE_CALLVIRT: {
9190                         MonoInst *addr = NULL;
9191                         MonoMethodSignature *fsig = NULL;
9192                         int array_rank = 0;
9193                         int virtual_ = *ip == CEE_CALLVIRT;
9194                         gboolean pass_imt_from_rgctx = FALSE;
9195                         MonoInst *imt_arg = NULL;
9196                         MonoInst *keep_this_alive = NULL;
9197                         gboolean pass_vtable = FALSE;
9198                         gboolean pass_mrgctx = FALSE;
9199                         MonoInst *vtable_arg = NULL;
9200                         gboolean check_this = FALSE;
9201                         gboolean supported_tail_call = FALSE;
9202                         gboolean tail_call = FALSE;
9203                         gboolean need_seq_point = FALSE;
9204                         guint32 call_opcode = *ip;
9205                         gboolean emit_widen = TRUE;
9206                         gboolean push_res = TRUE;
9207                         gboolean skip_ret = FALSE;
9208                         gboolean delegate_invoke = FALSE;
9209                         gboolean direct_icall = FALSE;
9210                         gboolean constrained_partial_call = FALSE;
9211                         MonoMethod *cil_method;
9212
9213                         CHECK_OPSIZE (5);
9214                         token = read32 (ip + 1);
9215
9216                         ins = NULL;
9217
9218                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
9219                         CHECK_CFG_ERROR;
9220
9221                         cil_method = cmethod;
9222                                 
9223                         if (constrained_class) {
9224                                 if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
9225                                         if (!mini_is_gsharedvt_klass (constrained_class)) {
9226                                                 g_assert (!cmethod->klass->valuetype);
9227                                                 if (!mini_type_is_reference (&constrained_class->byval_arg))
9228                                                         constrained_partial_call = TRUE;
9229                                         }
9230                                 }
9231
9232                                 if (method->wrapper_type != MONO_WRAPPER_NONE) {
9233                                         if (cfg->verbose_level > 2)
9234                                                 printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_class));
9235                                         if (!((constrained_class->byval_arg.type == MONO_TYPE_VAR ||
9236                                                    constrained_class->byval_arg.type == MONO_TYPE_MVAR) &&
9237                                                   cfg->gshared)) {
9238                                                 cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_class, generic_context, &cfg->error);
9239                                                 CHECK_CFG_ERROR;
9240                                         }
9241                                 } else {
9242                                         if (cfg->verbose_level > 2)
9243                                                 printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_class));
9244
9245                                         if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
9246                                                 /* 
9247                                                  * This is needed since get_method_constrained can't find 
9248                                                  * the method in klass representing a type var.
9249                                                  * The type var is guaranteed to be a reference type in this
9250                                                  * case.
9251                                                  */
9252                                                 if (!mini_is_gsharedvt_klass (constrained_class))
9253                                                         g_assert (!cmethod->klass->valuetype);
9254                                         } else {
9255                                                 cmethod = mono_get_method_constrained_checked (image, token, constrained_class, generic_context, &cil_method, &cfg->error);
9256                                                 CHECK_CFG_ERROR;
9257                                         }
9258                                 }
9259                         }
9260                                         
9261                         if (!dont_verify && !cfg->skip_visibility) {
9262                                 MonoMethod *target_method = cil_method;
9263                                 if (method->is_inflated) {
9264                                         target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context), &cfg->error);
9265                                         CHECK_CFG_ERROR;
9266                                 }
9267                                 if (!mono_method_can_access_method (method_definition, target_method) &&
9268                                         !mono_method_can_access_method (method, cil_method))
9269                                         emit_method_access_failure (cfg, method, cil_method);
9270                         }
9271
9272                         if (mono_security_core_clr_enabled ())
9273                                 ensure_method_is_allowed_to_call_method (cfg, method, cil_method);
9274
9275                         if (!virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
9276                                 /* MS.NET seems to silently convert this to a callvirt */
9277                                 virtual_ = 1;
9278
9279                         {
9280                                 /*
9281                                  * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
9282                                  * converts to a callvirt.
9283                                  *
9284                                  * tests/bug-515884.il is an example of this behavior
9285                                  */
9286                                 const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
9287                                 const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
9288                                 if (!virtual_ && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
9289                                         virtual_ = 1;
9290                         }
9291
9292                         if (!cmethod->klass->inited)
9293                                 if (!mono_class_init (cmethod->klass))
9294                                         TYPE_LOAD_ERROR (cmethod->klass);
9295
9296                         fsig = mono_method_signature (cmethod);
9297                         if (!fsig)
9298                                 LOAD_ERROR;
9299                         if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
9300                                 mini_class_is_system_array (cmethod->klass)) {
9301                                 array_rank = cmethod->klass->rank;
9302                         } else if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && icall_is_direct_callable (cfg, cmethod)) {
9303                                 direct_icall = TRUE;
9304                         } else if (fsig->pinvoke) {
9305                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
9306                                 fsig = mono_method_signature (wrapper);
9307                         } else if (constrained_class) {
9308                         } else {
9309                                 fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
9310                                 CHECK_CFG_ERROR;
9311                         }
9312
9313                         if (cfg->llvm_only && !cfg->method->wrapper_type && (!cmethod || cmethod->is_inflated))
9314                                 cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, fsig);
9315
9316                         /* See code below */
9317                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
9318                                 MonoBasicBlock *tbb;
9319
9320                                 GET_BBLOCK (cfg, tbb, ip + 5);
9321                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
9322                                         /*
9323                                          * We want to extend the try block to cover the call, but we can't do it if the
9324                                          * call is made directly since its followed by an exception check.
9325                                          */
9326                                         direct_icall = FALSE;
9327                                 }
9328                         }
9329
9330                         mono_save_token_info (cfg, image, token, cil_method);
9331
9332                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip + 5 - header->code)))
9333                                 need_seq_point = TRUE;
9334
9335                         /* Don't support calls made using type arguments for now */
9336                         /*
9337                           if (cfg->gsharedvt) {
9338                           if (mini_is_gsharedvt_signature (fsig))
9339                           GSHAREDVT_FAILURE (*ip);
9340                           }
9341                         */
9342
9343                         if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
9344                                 g_assert_not_reached ();
9345
9346                         n = fsig->param_count + fsig->hasthis;
9347
9348                         if (!cfg->gshared && cmethod->klass->generic_container)
9349                                 UNVERIFIED;
9350
9351                         if (!cfg->gshared)
9352                                 g_assert (!mono_method_check_context_used (cmethod));
9353
9354                         CHECK_STACK (n);
9355
9356                         //g_assert (!virtual_ || fsig->hasthis);
9357
9358                         sp -= n;
9359
9360                         /*
9361                          * We have the `constrained.' prefix opcode.
9362                          */
9363                         if (constrained_class) {
9364                                 if (mini_is_gsharedvt_klass (constrained_class)) {
9365                                         if ((cmethod->klass != mono_defaults.object_class) && constrained_class->valuetype && cmethod->klass->valuetype) {
9366                                                 /* The 'Own method' case below */
9367                                         } else if (cmethod->klass->image != mono_defaults.corlib && !(cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !cmethod->klass->valuetype) {
9368                                                 /* 'The type parameter is instantiated as a reference type' case below. */
9369                                         } else {
9370                                                 ins = handle_constrained_gsharedvt_call (cfg, cmethod, fsig, sp, constrained_class, &emit_widen);
9371                                                 CHECK_CFG_EXCEPTION;
9372                                                 g_assert (ins);
9373                                                 goto call_end;
9374                                         }
9375                                 }
9376
9377                                 if (constrained_partial_call) {
9378                                         gboolean need_box = TRUE;
9379
9380                                         /*
9381                                          * The receiver is a valuetype, but the exact type is not known at compile time. This means the
9382                                          * called method is not known at compile time either. The called method could end up being
9383                                          * one of the methods on the parent classes (object/valuetype/enum), in which case we need
9384                                          * to box the receiver.
9385                                          * A simple solution would be to box always and make a normal virtual call, but that would
9386                                          * be bad performance wise.
9387                                          */
9388                                         if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE && cmethod->klass->generic_class) {
9389                                                 /*
9390                                                  * The parent classes implement no generic interfaces, so the called method will be a vtype method, so no boxing neccessary.
9391                                                  */
9392                                                 need_box = FALSE;
9393                                         }
9394
9395                                         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)) {
9396                                                 /* The called method is not virtual, i.e. Object:GetType (), the receiver is a vtype, has to box */
9397                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9398                                                 ins->klass = constrained_class;
9399                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9400                                                 CHECK_CFG_EXCEPTION;
9401                                         } else if (need_box) {
9402                                                 MonoInst *box_type;
9403                                                 MonoBasicBlock *is_ref_bb, *end_bb;
9404                                                 MonoInst *nonbox_call;
9405
9406                                                 /*
9407                                                  * Determine at runtime whenever the called method is defined on object/valuetype/enum, and emit a boxing call
9408                                                  * if needed.
9409                                                  * FIXME: It is possible to inline the called method in a lot of cases, i.e. for T_INT,
9410                                                  * the no-box case goes to a method in Int32, while the box case goes to a method in Enum.
9411                                                  */
9412                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
9413
9414                                                 NEW_BBLOCK (cfg, is_ref_bb);
9415                                                 NEW_BBLOCK (cfg, end_bb);
9416
9417                                                 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);
9418                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, box_type->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
9419                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
9420
9421                                                 /* Non-ref case */
9422                                                 nonbox_call = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9423
9424                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9425
9426                                                 /* Ref case */
9427                                                 MONO_START_BB (cfg, is_ref_bb);
9428                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9429                                                 ins->klass = constrained_class;
9430                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9431                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9432
9433                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9434
9435                                                 MONO_START_BB (cfg, end_bb);
9436                                                 cfg->cbb = end_bb;
9437
9438                                                 nonbox_call->dreg = ins->dreg;
9439                                                 goto call_end;
9440                                         } else {
9441                                                 g_assert (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
9442                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
9443                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9444                                                 goto call_end;
9445                                         }
9446                                 } else if (constrained_class->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
9447                                         /*
9448                                          * The type parameter is instantiated as a valuetype,
9449                                          * but that type doesn't override the method we're
9450                                          * calling, so we need to box `this'.
9451                                          */
9452                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9453                                         ins->klass = constrained_class;
9454                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9455                                         CHECK_CFG_EXCEPTION;
9456                                 } else if (!constrained_class->valuetype) {
9457                                         int dreg = alloc_ireg_ref (cfg);
9458
9459                                         /*
9460                                          * The type parameter is instantiated as a reference
9461                                          * type.  We have a managed pointer on the stack, so
9462                                          * we need to dereference it here.
9463                                          */
9464                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
9465                                         ins->type = STACK_OBJ;
9466                                         sp [0] = ins;
9467                                 } else {
9468                                         if (cmethod->klass->valuetype) {
9469                                                 /* Own method */
9470                                         } else {
9471                                                 /* Interface method */
9472                                                 int ioffset, slot;
9473
9474                                                 mono_class_setup_vtable (constrained_class);
9475                                                 CHECK_TYPELOAD (constrained_class);
9476                                                 ioffset = mono_class_interface_offset (constrained_class, cmethod->klass);
9477                                                 if (ioffset == -1)
9478                                                         TYPE_LOAD_ERROR (constrained_class);
9479                                                 slot = mono_method_get_vtable_slot (cmethod);
9480                                                 if (slot == -1)
9481                                                         TYPE_LOAD_ERROR (cmethod->klass);
9482                                                 cmethod = constrained_class->vtable [ioffset + slot];
9483
9484                                                 if (cmethod->klass == mono_defaults.enum_class) {
9485                                                         /* Enum implements some interfaces, so treat this as the first case */
9486                                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9487                                                         ins->klass = constrained_class;
9488                                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9489                                                         CHECK_CFG_EXCEPTION;
9490                                                 }
9491                                         }
9492                                         virtual_ = 0;
9493                                 }
9494                                 constrained_class = NULL;
9495                         }
9496
9497                         if (check_call_signature (cfg, fsig, sp))
9498                                 UNVERIFIED;
9499
9500                         if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
9501                                 delegate_invoke = TRUE;
9502
9503                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
9504                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9505                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9506                                         emit_widen = FALSE;
9507                                 }
9508
9509                                 goto call_end;
9510                         }
9511
9512                         /* 
9513                          * If the callee is a shared method, then its static cctor
9514                          * might not get called after the call was patched.
9515                          */
9516                         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)) {
9517                                 emit_class_init (cfg, cmethod->klass);
9518                                 CHECK_TYPELOAD (cmethod->klass);
9519                         }
9520
9521                         check_method_sharing (cfg, cmethod, &pass_vtable, &pass_mrgctx);
9522
9523                         if (cfg->gshared) {
9524                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
9525
9526                                 context_used = mini_method_check_context_used (cfg, cmethod);
9527
9528                                 if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9529                                         /* Generic method interface
9530                                            calls are resolved via a
9531                                            helper function and don't
9532                                            need an imt. */
9533                                         if (!cmethod_context || !cmethod_context->method_inst)
9534                                                 pass_imt_from_rgctx = TRUE;
9535                                 }
9536
9537                                 /*
9538                                  * If a shared method calls another
9539                                  * shared method then the caller must
9540                                  * have a generic sharing context
9541                                  * because the magic trampoline
9542                                  * requires it.  FIXME: We shouldn't
9543                                  * have to force the vtable/mrgctx
9544                                  * variable here.  Instead there
9545                                  * should be a flag in the cfg to
9546                                  * request a generic sharing context.
9547                                  */
9548                                 if (context_used &&
9549                                                 ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
9550                                         mono_get_vtable_var (cfg);
9551                         }
9552
9553                         if (pass_vtable) {
9554                                 if (context_used) {
9555                                         vtable_arg = emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
9556                                 } else {
9557                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
9558
9559                                         CHECK_TYPELOAD (cmethod->klass);
9560                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
9561                                 }
9562                         }
9563
9564                         if (pass_mrgctx) {
9565                                 g_assert (!vtable_arg);
9566
9567                                 if (!cfg->compile_aot) {
9568                                         /* 
9569                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
9570                                          * for type load errors before.
9571                                          */
9572                                         mono_class_setup_vtable (cmethod->klass);
9573                                         CHECK_TYPELOAD (cmethod->klass);
9574                                 }
9575
9576                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
9577
9578                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
9579                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
9580                                          MONO_METHOD_IS_FINAL (cmethod)) &&
9581                                         !mono_class_is_marshalbyref (cmethod->klass)) {
9582                                         if (virtual_)
9583                                                 check_this = TRUE;
9584                                         virtual_ = 0;
9585                                 }
9586                         }
9587
9588                         if (pass_imt_from_rgctx) {
9589                                 g_assert (!pass_vtable);
9590
9591                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9592                                         cmethod, MONO_RGCTX_INFO_METHOD);
9593                         }
9594
9595                         if (check_this)
9596                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9597
9598                         /* Calling virtual generic methods */
9599                         if (virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) &&
9600                             !(MONO_METHOD_IS_FINAL (cmethod) && 
9601                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
9602                             fsig->generic_param_count && 
9603                                 !(cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) &&
9604                                 !cfg->llvm_only) {
9605                                 MonoInst *this_temp, *this_arg_temp, *store;
9606                                 MonoInst *iargs [4];
9607
9608                                 g_assert (fsig->is_inflated);
9609
9610                                 /* Prevent inlining of methods that contain indirect calls */
9611                                 INLINE_FAILURE ("virtual generic call");
9612
9613                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
9614                                         GSHAREDVT_FAILURE (*ip);
9615
9616                                 if (cfg->backend->have_generalized_imt_thunk && cfg->backend->gshared_supported && cmethod->wrapper_type == MONO_WRAPPER_NONE) {
9617                                         g_assert (!imt_arg);
9618                                         if (!context_used)
9619                                                 g_assert (cmethod->is_inflated);
9620                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
9621                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
9622                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, sp [0], imt_arg, NULL);
9623                                 } else {
9624                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
9625                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
9626                                         MONO_ADD_INS (cfg->cbb, store);
9627
9628                                         /* FIXME: This should be a managed pointer */
9629                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
9630
9631                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
9632                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
9633                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
9634                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
9635                                         addr = mono_emit_jit_icall (cfg,
9636                                                                                                 mono_helper_compile_generic_method, iargs);
9637
9638                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
9639
9640                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9641                                 }
9642
9643                                 goto call_end;
9644                         }
9645
9646                         /*
9647                          * Implement a workaround for the inherent races involved in locking:
9648                          * Monitor.Enter ()
9649                          * try {
9650                          * } finally {
9651                          *    Monitor.Exit ()
9652                          * }
9653                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
9654                          * try block, the Exit () won't be executed, see:
9655                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
9656                          * To work around this, we extend such try blocks to include the last x bytes
9657                          * of the Monitor.Enter () call.
9658                          */
9659                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
9660                                 MonoBasicBlock *tbb;
9661
9662                                 GET_BBLOCK (cfg, tbb, ip + 5);
9663                                 /* 
9664                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
9665                                  * from Monitor.Enter like ArgumentNullException.
9666                                  */
9667                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
9668                                         /* Mark this bblock as needing to be extended */
9669                                         tbb->extend_try_block = TRUE;
9670                                 }
9671                         }
9672
9673                         /* Conversion to a JIT intrinsic */
9674                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
9675                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9676                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9677                                         emit_widen = FALSE;
9678                                 }
9679                                 goto call_end;
9680                         }
9681                         CHECK_CFG_ERROR;
9682                         
9683                         /* Inlining */
9684                         if ((cfg->opt & MONO_OPT_INLINE) &&
9685                                 (!virtual_ || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
9686                             mono_method_check_inlining (cfg, cmethod)) {
9687                                 int costs;
9688                                 gboolean always = FALSE;
9689
9690                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
9691                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
9692                                         /* Prevent inlining of methods that call wrappers */
9693                                         INLINE_FAILURE ("wrapper call");
9694                                         cmethod = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
9695                                         always = TRUE;
9696                                 }
9697
9698                                 costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, always);
9699                                 if (costs) {
9700                                         cfg->real_offset += 5;
9701
9702                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9703                                                 /* *sp is already set by inline_method */
9704                                                 sp++;
9705                                                 push_res = FALSE;
9706                                         }
9707
9708                                         inline_costs += costs;
9709
9710                                         goto call_end;
9711                                 }
9712                         }
9713
9714                         /* Tail recursion elimination */
9715                         if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
9716                                 gboolean has_vtargs = FALSE;
9717                                 int i;
9718
9719                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9720                                 INLINE_FAILURE ("tail call");
9721
9722                                 /* keep it simple */
9723                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
9724                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
9725                                                 has_vtargs = TRUE;
9726                                 }
9727
9728                                 if (!has_vtargs) {
9729                                         for (i = 0; i < n; ++i)
9730                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9731                                         MONO_INST_NEW (cfg, ins, OP_BR);
9732                                         MONO_ADD_INS (cfg->cbb, ins);
9733                                         tblock = start_bblock->out_bb [0];
9734                                         link_bblock (cfg, cfg->cbb, tblock);
9735                                         ins->inst_target_bb = tblock;
9736                                         start_new_bblock = 1;
9737
9738                                         /* skip the CEE_RET, too */
9739                                         if (ip_in_bb (cfg, cfg->cbb, ip + 5))
9740                                                 skip_ret = TRUE;
9741                                         push_res = FALSE;
9742                                         goto call_end;
9743                                 }
9744                         }
9745
9746                         inline_costs += 10 * num_calls++;
9747
9748                         /*
9749                          * Making generic calls out of gsharedvt methods.
9750                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9751                          * patching gshared method addresses into a gsharedvt method.
9752                          */
9753                         if (cfg->gsharedvt && (mini_is_gsharedvt_signature (fsig) || cmethod->is_inflated || cmethod->klass->generic_class) &&
9754                                 !(cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY) &&
9755                                 (!(cfg->llvm_only && virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)))) {
9756                                 MonoRgctxInfoType info_type;
9757
9758                                 if (virtual_) {
9759                                         //if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
9760                                                 //GSHAREDVT_FAILURE (*ip);
9761                                         // disable for possible remoting calls
9762                                         if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
9763                                                 GSHAREDVT_FAILURE (*ip);
9764                                         if (fsig->generic_param_count) {
9765                                                 /* virtual generic call */
9766                                                 g_assert (!imt_arg);
9767                                                 /* Same as the virtual generic case above */
9768                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9769                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9770                                                 /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
9771                                                 vtable_arg = NULL;
9772                                         } else if ((cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !imt_arg) {
9773                                                 /* This can happen when we call a fully instantiated iface method */
9774                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9775                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9776                                                 vtable_arg = NULL;
9777                                         }
9778                                 }
9779
9780                                 if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
9781                                         keep_this_alive = sp [0];
9782
9783                                 if (virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
9784                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
9785                                 else
9786                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
9787                                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
9788
9789                                 if (cfg->llvm_only) {
9790                                         // FIXME: Avoid initializing vtable_arg
9791                                         ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
9792                                 } else {
9793                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9794                                 }
9795                                 goto call_end;
9796                         }
9797
9798                         /* Generic sharing */
9799
9800                         /*
9801                          * Use this if the callee is gsharedvt sharable too, since
9802                          * at runtime we might find an instantiation so the call cannot
9803                          * be patched (the 'no_patch' code path in mini-trampolines.c).
9804                          */
9805                         if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
9806                                 (!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
9807                                  !mono_class_generic_sharing_enabled (cmethod->klass)) &&
9808                                 (!virtual_ || MONO_METHOD_IS_FINAL (cmethod) ||
9809                                  !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
9810                                 INLINE_FAILURE ("gshared");
9811
9812                                 g_assert (cfg->gshared && cmethod);
9813                                 g_assert (!addr);
9814
9815                                 /*
9816                                  * We are compiling a call to a
9817                                  * generic method from shared code,
9818                                  * which means that we have to look up
9819                                  * the method in the rgctx and do an
9820                                  * indirect call.
9821                                  */
9822                                 if (fsig->hasthis)
9823                                         MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9824
9825                                 if (cfg->llvm_only) {
9826                                         if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig))
9827                                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER);
9828                                         else
9829                                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9830                                         // FIXME: Avoid initializing imt_arg/vtable_arg
9831                                         ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
9832                                 } else {
9833                                         addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9834                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9835                                 }
9836                                 goto call_end;
9837                         }
9838
9839                         /* Direct calls to icalls */
9840                         if (direct_icall) {
9841                                 MonoMethod *wrapper;
9842                                 int costs;
9843
9844                                 /* Inline the wrapper */
9845                                 wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
9846
9847                                 costs = inline_method (cfg, wrapper, fsig, sp, ip, cfg->real_offset, TRUE);
9848                                 g_assert (costs > 0);
9849                                 cfg->real_offset += 5;
9850
9851                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9852                                         /* *sp is already set by inline_method */
9853                                         sp++;
9854                                         push_res = FALSE;
9855                                 }
9856
9857                                 inline_costs += costs;
9858
9859                                 goto call_end;
9860                         }
9861                                         
9862                         /* Array methods */
9863                         if (array_rank) {
9864                                 MonoInst *addr;
9865
9866                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
9867                                         MonoInst *val = sp [fsig->param_count];
9868
9869                                         if (val->type == STACK_OBJ) {
9870                                                 MonoInst *iargs [2];
9871
9872                                                 iargs [0] = sp [0];
9873                                                 iargs [1] = val;
9874                                                 
9875                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
9876                                         }
9877                                         
9878                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
9879                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
9880                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !(val->opcode == OP_PCONST && val->inst_c0 == 0))
9881                                                 emit_write_barrier (cfg, addr, val);
9882                                         if (cfg->gen_write_barriers && mini_is_gsharedvt_klass (cmethod->klass))
9883                                                 GSHAREDVT_FAILURE (*ip);
9884                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
9885                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9886
9887                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
9888                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
9889                                         if (!cmethod->klass->element_class->valuetype && !readonly)
9890                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
9891                                         CHECK_TYPELOAD (cmethod->klass);
9892                                         
9893                                         readonly = FALSE;
9894                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9895                                         ins = addr;
9896                                 } else {
9897                                         g_assert_not_reached ();
9898                                 }
9899
9900                                 emit_widen = FALSE;
9901                                 goto call_end;
9902                         }
9903
9904                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual_ ? sp [0] : NULL);
9905                         if (ins)
9906                                 goto call_end;
9907
9908                         /* Tail prefix / tail call optimization */
9909
9910                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
9911                         /* FIXME: runtime generic context pointer for jumps? */
9912                         /* FIXME: handle this for generic sharing eventually */
9913                         if ((ins_flag & MONO_INST_TAILCALL) &&
9914                                 !vtable_arg && !cfg->gshared && is_supported_tail_call (cfg, method, cmethod, fsig, call_opcode))
9915                                 supported_tail_call = TRUE;
9916
9917                         if (supported_tail_call) {
9918                                 MonoCallInst *call;
9919
9920                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9921                                 INLINE_FAILURE ("tail call");
9922
9923                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
9924
9925                                 if (cfg->backend->have_op_tail_call) {
9926                                         /* Handle tail calls similarly to normal calls */
9927                                         tail_call = TRUE;
9928                                 } else {
9929                                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
9930
9931                                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9932                                         call->tail_call = TRUE;
9933                                         call->method = cmethod;
9934                                         call->signature = mono_method_signature (cmethod);
9935
9936                                         /*
9937                                          * We implement tail calls by storing the actual arguments into the 
9938                                          * argument variables, then emitting a CEE_JMP.
9939                                          */
9940                                         for (i = 0; i < n; ++i) {
9941                                                 /* Prevent argument from being register allocated */
9942                                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
9943                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9944                                         }
9945                                         ins = (MonoInst*)call;
9946                                         ins->inst_p0 = cmethod;
9947                                         ins->inst_p1 = arg_array [0];
9948                                         MONO_ADD_INS (cfg->cbb, ins);
9949                                         link_bblock (cfg, cfg->cbb, end_bblock);
9950                                         start_new_bblock = 1;
9951
9952                                         // FIXME: Eliminate unreachable epilogs
9953
9954                                         /*
9955                                          * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9956                                          * only reachable from this call.
9957                                          */
9958                                         GET_BBLOCK (cfg, tblock, ip + 5);
9959                                         if (tblock == cfg->cbb || tblock->in_count == 0)
9960                                                 skip_ret = TRUE;
9961                                         push_res = FALSE;
9962
9963                                         goto call_end;
9964                                 }
9965                         }
9966
9967                         /* 
9968                          * Synchronized wrappers.
9969                          * Its hard to determine where to replace a method with its synchronized
9970                          * wrapper without causing an infinite recursion. The current solution is
9971                          * to add the synchronized wrapper in the trampolines, and to
9972                          * change the called method to a dummy wrapper, and resolve that wrapper
9973                          * to the real method in mono_jit_compile_method ().
9974                          */
9975                         if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
9976                                 MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
9977                                 if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
9978                                         cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
9979                         }
9980
9981                         /*
9982                          * Virtual calls in llvm-only mode.
9983                          */
9984                         if (cfg->llvm_only && virtual_ && cmethod && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
9985                                 ins = emit_llvmonly_virtual_call (cfg, cmethod, fsig, context_used, sp);
9986                                 goto call_end;
9987                         }
9988
9989                         /* Common call */
9990                         INLINE_FAILURE ("call");
9991                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual_ ? sp [0] : NULL,
9992                                                                                           imt_arg, vtable_arg);
9993
9994                         if (tail_call && !cfg->llvm_only) {
9995                                 link_bblock (cfg, cfg->cbb, end_bblock);
9996                                 start_new_bblock = 1;
9997
9998                                 // FIXME: Eliminate unreachable epilogs
9999
10000                                 /*
10001                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
10002                                  * only reachable from this call.
10003                                  */
10004                                 GET_BBLOCK (cfg, tblock, ip + 5);
10005                                 if (tblock == cfg->cbb || tblock->in_count == 0)
10006                                         skip_ret = TRUE;
10007                                 push_res = FALSE;
10008                         }
10009
10010                         call_end:
10011
10012                         /* End of call, INS should contain the result of the call, if any */
10013
10014                         if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
10015                                 g_assert (ins);
10016                                 if (emit_widen)
10017                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
10018                                 else
10019                                         *sp++ = ins;
10020                         }
10021
10022                         if (keep_this_alive) {
10023                                 MonoInst *dummy_use;
10024
10025                                 /* See mono_emit_method_call_full () */
10026                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
10027                         }
10028
10029                         CHECK_CFG_EXCEPTION;
10030
10031                         ip += 5;
10032                         if (skip_ret) {
10033                                 g_assert (*ip == CEE_RET);
10034                                 ip += 1;
10035                         }
10036                         ins_flag = 0;
10037                         constrained_class = NULL;
10038                         if (need_seq_point)
10039                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10040                         break;
10041                 }
10042                 case CEE_RET:
10043                         if (cfg->method != method) {
10044                                 /* return from inlined method */
10045                                 /* 
10046                                  * If in_count == 0, that means the ret is unreachable due to
10047                                  * being preceeded by a throw. In that case, inline_method () will
10048                                  * handle setting the return value 
10049                                  * (test case: test_0_inline_throw ()).
10050                                  */
10051                                 if (return_var && cfg->cbb->in_count) {
10052                                         MonoType *ret_type = mono_method_signature (method)->ret;
10053
10054                                         MonoInst *store;
10055                                         CHECK_STACK (1);
10056                                         --sp;
10057
10058                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
10059                                                 UNVERIFIED;
10060
10061                                         //g_assert (returnvar != -1);
10062                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
10063                                         cfg->ret_var_set = TRUE;
10064                                 } 
10065                         } else {
10066                                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
10067
10068                                 if (cfg->lmf_var && cfg->cbb->in_count && !cfg->llvm_only)
10069                                         emit_pop_lmf (cfg);
10070
10071                                 if (cfg->ret) {
10072                                         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (method)->ret);
10073
10074                                         if (seq_points && !sym_seq_points) {
10075                                                 /* 
10076                                                  * Place a seq point here too even through the IL stack is not
10077                                                  * empty, so a step over on
10078                                                  * call <FOO>
10079                                                  * ret
10080                                                  * will work correctly.
10081                                                  */
10082                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
10083                                                 MONO_ADD_INS (cfg->cbb, ins);
10084                                         }
10085
10086                                         g_assert (!return_var);
10087                                         CHECK_STACK (1);
10088                                         --sp;
10089
10090                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
10091                                                 UNVERIFIED;
10092
10093                                         emit_setret (cfg, *sp);
10094                                 }
10095                         }
10096                         if (sp != stack_start)
10097                                 UNVERIFIED;
10098                         MONO_INST_NEW (cfg, ins, OP_BR);
10099                         ip++;
10100                         ins->inst_target_bb = end_bblock;
10101                         MONO_ADD_INS (cfg->cbb, ins);
10102                         link_bblock (cfg, cfg->cbb, end_bblock);
10103                         start_new_bblock = 1;
10104                         break;
10105                 case CEE_BR_S:
10106                         CHECK_OPSIZE (2);
10107                         MONO_INST_NEW (cfg, ins, OP_BR);
10108                         ip++;
10109                         target = ip + 1 + (signed char)(*ip);
10110                         ++ip;
10111                         GET_BBLOCK (cfg, tblock, target);
10112                         link_bblock (cfg, cfg->cbb, tblock);
10113                         ins->inst_target_bb = tblock;
10114                         if (sp != stack_start) {
10115                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10116                                 sp = stack_start;
10117                                 CHECK_UNVERIFIABLE (cfg);
10118                         }
10119                         MONO_ADD_INS (cfg->cbb, ins);
10120                         start_new_bblock = 1;
10121                         inline_costs += BRANCH_COST;
10122                         break;
10123                 case CEE_BEQ_S:
10124                 case CEE_BGE_S:
10125                 case CEE_BGT_S:
10126                 case CEE_BLE_S:
10127                 case CEE_BLT_S:
10128                 case CEE_BNE_UN_S:
10129                 case CEE_BGE_UN_S:
10130                 case CEE_BGT_UN_S:
10131                 case CEE_BLE_UN_S:
10132                 case CEE_BLT_UN_S:
10133                         CHECK_OPSIZE (2);
10134                         CHECK_STACK (2);
10135                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
10136                         ip++;
10137                         target = ip + 1 + *(signed char*)ip;
10138                         ip++;
10139
10140                         ADD_BINCOND (NULL);
10141
10142                         sp = stack_start;
10143                         inline_costs += BRANCH_COST;
10144                         break;
10145                 case CEE_BR:
10146                         CHECK_OPSIZE (5);
10147                         MONO_INST_NEW (cfg, ins, OP_BR);
10148                         ip++;
10149
10150                         target = ip + 4 + (gint32)read32(ip);
10151                         ip += 4;
10152                         GET_BBLOCK (cfg, tblock, target);
10153                         link_bblock (cfg, cfg->cbb, tblock);
10154                         ins->inst_target_bb = tblock;
10155                         if (sp != stack_start) {
10156                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10157                                 sp = stack_start;
10158                                 CHECK_UNVERIFIABLE (cfg);
10159                         }
10160
10161                         MONO_ADD_INS (cfg->cbb, ins);
10162
10163                         start_new_bblock = 1;
10164                         inline_costs += BRANCH_COST;
10165                         break;
10166                 case CEE_BRFALSE_S:
10167                 case CEE_BRTRUE_S:
10168                 case CEE_BRFALSE:
10169                 case CEE_BRTRUE: {
10170                         MonoInst *cmp;
10171                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
10172                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
10173                         guint32 opsize = is_short ? 1 : 4;
10174
10175                         CHECK_OPSIZE (opsize);
10176                         CHECK_STACK (1);
10177                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
10178                                 UNVERIFIED;
10179                         ip ++;
10180                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
10181                         ip += opsize;
10182
10183                         sp--;
10184
10185                         GET_BBLOCK (cfg, tblock, target);
10186                         link_bblock (cfg, cfg->cbb, tblock);
10187                         GET_BBLOCK (cfg, tblock, ip);
10188                         link_bblock (cfg, cfg->cbb, tblock);
10189
10190                         if (sp != stack_start) {
10191                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10192                                 CHECK_UNVERIFIABLE (cfg);
10193                         }
10194
10195                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
10196                         cmp->sreg1 = sp [0]->dreg;
10197                         type_from_op (cfg, cmp, sp [0], NULL);
10198                         CHECK_TYPE (cmp);
10199
10200 #if SIZEOF_REGISTER == 4
10201                         if (cmp->opcode == OP_LCOMPARE_IMM) {
10202                                 /* Convert it to OP_LCOMPARE */
10203                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
10204                                 ins->type = STACK_I8;
10205                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
10206                                 ins->inst_l = 0;
10207                                 MONO_ADD_INS (cfg->cbb, ins);
10208                                 cmp->opcode = OP_LCOMPARE;
10209                                 cmp->sreg2 = ins->dreg;
10210                         }
10211 #endif
10212                         MONO_ADD_INS (cfg->cbb, cmp);
10213
10214                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
10215                         type_from_op (cfg, ins, sp [0], NULL);
10216                         MONO_ADD_INS (cfg->cbb, ins);
10217                         ins->inst_many_bb = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
10218                         GET_BBLOCK (cfg, tblock, target);
10219                         ins->inst_true_bb = tblock;
10220                         GET_BBLOCK (cfg, tblock, ip);
10221                         ins->inst_false_bb = tblock;
10222                         start_new_bblock = 2;
10223
10224                         sp = stack_start;
10225                         inline_costs += BRANCH_COST;
10226                         break;
10227                 }
10228                 case CEE_BEQ:
10229                 case CEE_BGE:
10230                 case CEE_BGT:
10231                 case CEE_BLE:
10232                 case CEE_BLT:
10233                 case CEE_BNE_UN:
10234                 case CEE_BGE_UN:
10235                 case CEE_BGT_UN:
10236                 case CEE_BLE_UN:
10237                 case CEE_BLT_UN:
10238                         CHECK_OPSIZE (5);
10239                         CHECK_STACK (2);
10240                         MONO_INST_NEW (cfg, ins, *ip);
10241                         ip++;
10242                         target = ip + 4 + (gint32)read32(ip);
10243                         ip += 4;
10244
10245                         ADD_BINCOND (NULL);
10246
10247                         sp = stack_start;
10248                         inline_costs += BRANCH_COST;
10249                         break;
10250                 case CEE_SWITCH: {
10251                         MonoInst *src1;
10252                         MonoBasicBlock **targets;
10253                         MonoBasicBlock *default_bblock;
10254                         MonoJumpInfoBBTable *table;
10255                         int offset_reg = alloc_preg (cfg);
10256                         int target_reg = alloc_preg (cfg);
10257                         int table_reg = alloc_preg (cfg);
10258                         int sum_reg = alloc_preg (cfg);
10259                         gboolean use_op_switch;
10260
10261                         CHECK_OPSIZE (5);
10262                         CHECK_STACK (1);
10263                         n = read32 (ip + 1);
10264                         --sp;
10265                         src1 = sp [0];
10266                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
10267                                 UNVERIFIED;
10268
10269                         ip += 5;
10270                         CHECK_OPSIZE (n * sizeof (guint32));
10271                         target = ip + n * sizeof (guint32);
10272
10273                         GET_BBLOCK (cfg, default_bblock, target);
10274                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
10275
10276                         targets = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
10277                         for (i = 0; i < n; ++i) {
10278                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
10279                                 targets [i] = tblock;
10280                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
10281                                 ip += 4;
10282                         }
10283
10284                         if (sp != stack_start) {
10285                                 /* 
10286                                  * Link the current bb with the targets as well, so handle_stack_args
10287                                  * will set their in_stack correctly.
10288                                  */
10289                                 link_bblock (cfg, cfg->cbb, default_bblock);
10290                                 for (i = 0; i < n; ++i)
10291                                         link_bblock (cfg, cfg->cbb, targets [i]);
10292
10293                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10294                                 sp = stack_start;
10295                                 CHECK_UNVERIFIABLE (cfg);
10296
10297                                 /* Undo the links */
10298                                 mono_unlink_bblock (cfg, cfg->cbb, default_bblock);
10299                                 for (i = 0; i < n; ++i)
10300                                         mono_unlink_bblock (cfg, cfg->cbb, targets [i]);
10301                         }
10302
10303                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
10304                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
10305
10306                         for (i = 0; i < n; ++i)
10307                                 link_bblock (cfg, cfg->cbb, targets [i]);
10308
10309                         table = (MonoJumpInfoBBTable *)mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
10310                         table->table = targets;
10311                         table->table_size = n;
10312
10313                         use_op_switch = FALSE;
10314 #ifdef TARGET_ARM
10315                         /* ARM implements SWITCH statements differently */
10316                         /* FIXME: Make it use the generic implementation */
10317                         if (!cfg->compile_aot)
10318                                 use_op_switch = TRUE;
10319 #endif
10320
10321                         if (COMPILE_LLVM (cfg))
10322                                 use_op_switch = TRUE;
10323
10324                         cfg->cbb->has_jump_table = 1;
10325
10326                         if (use_op_switch) {
10327                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
10328                                 ins->sreg1 = src1->dreg;
10329                                 ins->inst_p0 = table;
10330                                 ins->inst_many_bb = targets;
10331                                 ins->klass = (MonoClass *)GUINT_TO_POINTER (n);
10332                                 MONO_ADD_INS (cfg->cbb, ins);
10333                         } else {
10334                                 if (sizeof (gpointer) == 8)
10335                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
10336                                 else
10337                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
10338
10339 #if SIZEOF_REGISTER == 8
10340                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
10341                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
10342 #endif
10343
10344                                 if (cfg->compile_aot) {
10345                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
10346                                 } else {
10347                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
10348                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
10349                                         ins->inst_p0 = table;
10350                                         ins->dreg = table_reg;
10351                                         MONO_ADD_INS (cfg->cbb, ins);
10352                                 }
10353
10354                                 /* FIXME: Use load_memindex */
10355                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
10356                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
10357                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
10358                         }
10359                         start_new_bblock = 1;
10360                         inline_costs += (BRANCH_COST * 2);
10361                         break;
10362                 }
10363                 case CEE_LDIND_I1:
10364                 case CEE_LDIND_U1:
10365                 case CEE_LDIND_I2:
10366                 case CEE_LDIND_U2:
10367                 case CEE_LDIND_I4:
10368                 case CEE_LDIND_U4:
10369                 case CEE_LDIND_I8:
10370                 case CEE_LDIND_I:
10371                 case CEE_LDIND_R4:
10372                 case CEE_LDIND_R8:
10373                 case CEE_LDIND_REF:
10374                         CHECK_STACK (1);
10375                         --sp;
10376
10377                         switch (*ip) {
10378                         case CEE_LDIND_R4:
10379                         case CEE_LDIND_R8:
10380                                 dreg = alloc_freg (cfg);
10381                                 break;
10382                         case CEE_LDIND_I8:
10383                                 dreg = alloc_lreg (cfg);
10384                                 break;
10385                         case CEE_LDIND_REF:
10386                                 dreg = alloc_ireg_ref (cfg);
10387                                 break;
10388                         default:
10389                                 dreg = alloc_preg (cfg);
10390                         }
10391
10392                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
10393                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
10394                         if (*ip == CEE_LDIND_R4)
10395                                 ins->type = cfg->r4_stack_type;
10396                         ins->flags |= ins_flag;
10397                         MONO_ADD_INS (cfg->cbb, ins);
10398                         *sp++ = ins;
10399                         if (ins_flag & MONO_INST_VOLATILE) {
10400                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10401                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10402                         }
10403                         ins_flag = 0;
10404                         ++ip;
10405                         break;
10406                 case CEE_STIND_REF:
10407                 case CEE_STIND_I1:
10408                 case CEE_STIND_I2:
10409                 case CEE_STIND_I4:
10410                 case CEE_STIND_I8:
10411                 case CEE_STIND_R4:
10412                 case CEE_STIND_R8:
10413                 case CEE_STIND_I:
10414                         CHECK_STACK (2);
10415                         sp -= 2;
10416
10417                         if (ins_flag & MONO_INST_VOLATILE) {
10418                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
10419                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
10420                         }
10421
10422                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
10423                         ins->flags |= ins_flag;
10424                         ins_flag = 0;
10425
10426                         MONO_ADD_INS (cfg->cbb, ins);
10427
10428                         if (cfg->gen_write_barriers && *ip == CEE_STIND_REF && method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER && !((sp [1]->opcode == OP_PCONST) && (sp [1]->inst_p0 == 0)))
10429                                 emit_write_barrier (cfg, sp [0], sp [1]);
10430
10431                         inline_costs += 1;
10432                         ++ip;
10433                         break;
10434
10435                 case CEE_MUL:
10436                         CHECK_STACK (2);
10437
10438                         MONO_INST_NEW (cfg, ins, (*ip));
10439                         sp -= 2;
10440                         ins->sreg1 = sp [0]->dreg;
10441                         ins->sreg2 = sp [1]->dreg;
10442                         type_from_op (cfg, ins, sp [0], sp [1]);
10443                         CHECK_TYPE (ins);
10444                         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type);
10445
10446                         /* Use the immediate opcodes if possible */
10447                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
10448                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
10449                                 if (imm_opcode != -1) {
10450                                         ins->opcode = imm_opcode;
10451                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
10452                                         ins->sreg2 = -1;
10453
10454                                         NULLIFY_INS (sp [1]);
10455                                 }
10456                         }
10457
10458                         MONO_ADD_INS ((cfg)->cbb, (ins));
10459
10460                         *sp++ = mono_decompose_opcode (cfg, ins);
10461                         ip++;
10462                         break;
10463                 case CEE_ADD:
10464                 case CEE_SUB:
10465                 case CEE_DIV:
10466                 case CEE_DIV_UN:
10467                 case CEE_REM:
10468                 case CEE_REM_UN:
10469                 case CEE_AND:
10470                 case CEE_OR:
10471                 case CEE_XOR:
10472                 case CEE_SHL:
10473                 case CEE_SHR:
10474                 case CEE_SHR_UN:
10475                         CHECK_STACK (2);
10476
10477                         MONO_INST_NEW (cfg, ins, (*ip));
10478                         sp -= 2;
10479                         ins->sreg1 = sp [0]->dreg;
10480                         ins->sreg2 = sp [1]->dreg;
10481                         type_from_op (cfg, ins, sp [0], sp [1]);
10482                         CHECK_TYPE (ins);
10483                         add_widen_op (cfg, ins, &sp [0], &sp [1]);
10484                         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type);
10485
10486                         /* FIXME: Pass opcode to is_inst_imm */
10487
10488                         /* Use the immediate opcodes if possible */
10489                         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)) {
10490                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
10491                                 if (imm_opcode != -1) {
10492                                         ins->opcode = imm_opcode;
10493                                         if (sp [1]->opcode == OP_I8CONST) {
10494 #if SIZEOF_REGISTER == 8
10495                                                 ins->inst_imm = sp [1]->inst_l;
10496 #else
10497                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
10498                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
10499 #endif
10500                                         }
10501                                         else
10502                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
10503                                         ins->sreg2 = -1;
10504
10505                                         /* Might be followed by an instruction added by add_widen_op */
10506                                         if (sp [1]->next == NULL)
10507                                                 NULLIFY_INS (sp [1]);
10508                                 }
10509                         }
10510                         MONO_ADD_INS ((cfg)->cbb, (ins));
10511
10512                         *sp++ = mono_decompose_opcode (cfg, ins);
10513                         ip++;
10514                         break;
10515                 case CEE_NEG:
10516                 case CEE_NOT:
10517                 case CEE_CONV_I1:
10518                 case CEE_CONV_I2:
10519                 case CEE_CONV_I4:
10520                 case CEE_CONV_R4:
10521                 case CEE_CONV_R8:
10522                 case CEE_CONV_U4:
10523                 case CEE_CONV_I8:
10524                 case CEE_CONV_U8:
10525                 case CEE_CONV_OVF_I8:
10526                 case CEE_CONV_OVF_U8:
10527                 case CEE_CONV_R_UN:
10528                         CHECK_STACK (1);
10529
10530                         /* Special case this earlier so we have long constants in the IR */
10531                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
10532                                 int data = sp [-1]->inst_c0;
10533                                 sp [-1]->opcode = OP_I8CONST;
10534                                 sp [-1]->type = STACK_I8;
10535 #if SIZEOF_REGISTER == 8
10536                                 if ((*ip) == CEE_CONV_U8)
10537                                         sp [-1]->inst_c0 = (guint32)data;
10538                                 else
10539                                         sp [-1]->inst_c0 = data;
10540 #else
10541                                 sp [-1]->inst_ls_word = data;
10542                                 if ((*ip) == CEE_CONV_U8)
10543                                         sp [-1]->inst_ms_word = 0;
10544                                 else
10545                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
10546 #endif
10547                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
10548                         }
10549                         else {
10550                                 ADD_UNOP (*ip);
10551                         }
10552                         ip++;
10553                         break;
10554                 case CEE_CONV_OVF_I4:
10555                 case CEE_CONV_OVF_I1:
10556                 case CEE_CONV_OVF_I2:
10557                 case CEE_CONV_OVF_I:
10558                 case CEE_CONV_OVF_U:
10559                         CHECK_STACK (1);
10560
10561                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10562                                 ADD_UNOP (CEE_CONV_OVF_I8);
10563                                 ADD_UNOP (*ip);
10564                         } else {
10565                                 ADD_UNOP (*ip);
10566                         }
10567                         ip++;
10568                         break;
10569                 case CEE_CONV_OVF_U1:
10570                 case CEE_CONV_OVF_U2:
10571                 case CEE_CONV_OVF_U4:
10572                         CHECK_STACK (1);
10573
10574                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10575                                 ADD_UNOP (CEE_CONV_OVF_U8);
10576                                 ADD_UNOP (*ip);
10577                         } else {
10578                                 ADD_UNOP (*ip);
10579                         }
10580                         ip++;
10581                         break;
10582                 case CEE_CONV_OVF_I1_UN:
10583                 case CEE_CONV_OVF_I2_UN:
10584                 case CEE_CONV_OVF_I4_UN:
10585                 case CEE_CONV_OVF_I8_UN:
10586                 case CEE_CONV_OVF_U1_UN:
10587                 case CEE_CONV_OVF_U2_UN:
10588                 case CEE_CONV_OVF_U4_UN:
10589                 case CEE_CONV_OVF_U8_UN:
10590                 case CEE_CONV_OVF_I_UN:
10591                 case CEE_CONV_OVF_U_UN:
10592                 case CEE_CONV_U2:
10593                 case CEE_CONV_U1:
10594                 case CEE_CONV_I:
10595                 case CEE_CONV_U:
10596                         CHECK_STACK (1);
10597                         ADD_UNOP (*ip);
10598                         CHECK_CFG_EXCEPTION;
10599                         ip++;
10600                         break;
10601                 case CEE_ADD_OVF:
10602                 case CEE_ADD_OVF_UN:
10603                 case CEE_MUL_OVF:
10604                 case CEE_MUL_OVF_UN:
10605                 case CEE_SUB_OVF:
10606                 case CEE_SUB_OVF_UN:
10607                         CHECK_STACK (2);
10608                         ADD_BINOP (*ip);
10609                         ip++;
10610                         break;
10611                 case CEE_CPOBJ:
10612                         GSHAREDVT_FAILURE (*ip);
10613                         CHECK_OPSIZE (5);
10614                         CHECK_STACK (2);
10615                         token = read32 (ip + 1);
10616                         klass = mini_get_class (method, token, generic_context);
10617                         CHECK_TYPELOAD (klass);
10618                         sp -= 2;
10619                         if (generic_class_is_reference_type (cfg, klass)) {
10620                                 MonoInst *store, *load;
10621                                 int dreg = alloc_ireg_ref (cfg);
10622
10623                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
10624                                 load->flags |= ins_flag;
10625                                 MONO_ADD_INS (cfg->cbb, load);
10626
10627                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
10628                                 store->flags |= ins_flag;
10629                                 MONO_ADD_INS (cfg->cbb, store);
10630
10631                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
10632                                         emit_write_barrier (cfg, sp [0], sp [1]);
10633                         } else {
10634                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10635                         }
10636                         ins_flag = 0;
10637                         ip += 5;
10638                         break;
10639                 case CEE_LDOBJ: {
10640                         int loc_index = -1;
10641                         int stloc_len = 0;
10642
10643                         CHECK_OPSIZE (5);
10644                         CHECK_STACK (1);
10645                         --sp;
10646                         token = read32 (ip + 1);
10647                         klass = mini_get_class (method, token, generic_context);
10648                         CHECK_TYPELOAD (klass);
10649
10650                         /* Optimize the common ldobj+stloc combination */
10651                         switch (ip [5]) {
10652                         case CEE_STLOC_S:
10653                                 loc_index = ip [6];
10654                                 stloc_len = 2;
10655                                 break;
10656                         case CEE_STLOC_0:
10657                         case CEE_STLOC_1:
10658                         case CEE_STLOC_2:
10659                         case CEE_STLOC_3:
10660                                 loc_index = ip [5] - CEE_STLOC_0;
10661                                 stloc_len = 1;
10662                                 break;
10663                         default:
10664                                 break;
10665                         }
10666
10667                         if ((loc_index != -1) && ip_in_bb (cfg, cfg->cbb, ip + 5)) {
10668                                 CHECK_LOCAL (loc_index);
10669
10670                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10671                                 ins->dreg = cfg->locals [loc_index]->dreg;
10672                                 ins->flags |= ins_flag;
10673                                 ip += 5;
10674                                 ip += stloc_len;
10675                                 if (ins_flag & MONO_INST_VOLATILE) {
10676                                         /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10677                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10678                                 }
10679                                 ins_flag = 0;
10680                                 break;
10681                         }
10682
10683                         /* Optimize the ldobj+stobj combination */
10684                         /* The reference case ends up being a load+store anyway */
10685                         /* Skip this if the operation is volatile. */
10686                         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)) {
10687                                 CHECK_STACK (1);
10688
10689                                 sp --;
10690
10691                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10692
10693                                 ip += 5 + 5;
10694                                 ins_flag = 0;
10695                                 break;
10696                         }
10697
10698                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10699                         ins->flags |= ins_flag;
10700                         *sp++ = ins;
10701
10702                         if (ins_flag & MONO_INST_VOLATILE) {
10703                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10704                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10705                         }
10706
10707                         ip += 5;
10708                         ins_flag = 0;
10709                         inline_costs += 1;
10710                         break;
10711                 }
10712                 case CEE_LDSTR:
10713                         CHECK_STACK_OVF (1);
10714                         CHECK_OPSIZE (5);
10715                         n = read32 (ip + 1);
10716
10717                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
10718                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
10719                                 ins->type = STACK_OBJ;
10720                                 *sp = ins;
10721                         }
10722                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
10723                                 MonoInst *iargs [1];
10724                                 char *str = (char *)mono_method_get_wrapper_data (method, n);
10725
10726                                 if (cfg->compile_aot)
10727                                         EMIT_NEW_LDSTRLITCONST (cfg, iargs [0], str);
10728                                 else
10729                                         EMIT_NEW_PCONST (cfg, iargs [0], str);
10730                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
10731                         } else {
10732                                 if (cfg->opt & MONO_OPT_SHARED) {
10733                                         MonoInst *iargs [3];
10734
10735                                         if (cfg->compile_aot) {
10736                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
10737                                         }
10738                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10739                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
10740                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
10741                                         *sp = mono_emit_jit_icall (cfg, ves_icall_mono_ldstr, iargs);
10742                                         mono_ldstr_checked (cfg->domain, image, mono_metadata_token_index (n), &cfg->error);
10743                                         CHECK_CFG_ERROR;
10744                                 } else {
10745                                         if (cfg->cbb->out_of_line) {
10746                                                 MonoInst *iargs [2];
10747
10748                                                 if (image == mono_defaults.corlib) {
10749                                                         /* 
10750                                                          * Avoid relocations in AOT and save some space by using a 
10751                                                          * version of helper_ldstr specialized to mscorlib.
10752                                                          */
10753                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
10754                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
10755                                                 } else {
10756                                                         /* Avoid creating the string object */
10757                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
10758                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
10759                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
10760                                                 }
10761                                         } 
10762                                         else
10763                                         if (cfg->compile_aot) {
10764                                                 NEW_LDSTRCONST (cfg, ins, image, n);
10765                                                 *sp = ins;
10766                                                 MONO_ADD_INS (cfg->cbb, ins);
10767                                         } 
10768                                         else {
10769                                                 NEW_PCONST (cfg, ins, NULL);
10770                                                 ins->type = STACK_OBJ;
10771                                                 ins->inst_p0 = mono_ldstr_checked (cfg->domain, image, mono_metadata_token_index (n), &cfg->error);
10772                                                 CHECK_CFG_ERROR;
10773                                                 
10774                                                 if (!ins->inst_p0)
10775                                                         OUT_OF_MEMORY_FAILURE;
10776
10777                                                 *sp = ins;
10778                                                 MONO_ADD_INS (cfg->cbb, ins);
10779                                         }
10780                                 }
10781                         }
10782
10783                         sp++;
10784                         ip += 5;
10785                         break;
10786                 case CEE_NEWOBJ: {
10787                         MonoInst *iargs [2];
10788                         MonoMethodSignature *fsig;
10789                         MonoInst this_ins;
10790                         MonoInst *alloc;
10791                         MonoInst *vtable_arg = NULL;
10792
10793                         CHECK_OPSIZE (5);
10794                         token = read32 (ip + 1);
10795                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
10796                         CHECK_CFG_ERROR;
10797
10798                         fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
10799                         CHECK_CFG_ERROR;
10800
10801                         mono_save_token_info (cfg, image, token, cmethod);
10802
10803                         if (!mono_class_init (cmethod->klass))
10804                                 TYPE_LOAD_ERROR (cmethod->klass);
10805
10806                         context_used = mini_method_check_context_used (cfg, cmethod);
10807
10808                         if (mono_security_core_clr_enabled ())
10809                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
10810
10811                         if (cfg->gshared && cmethod && cmethod->klass != method->klass && cmethod->klass->generic_class && mono_method_is_generic_sharable (cmethod, TRUE) && mono_class_needs_cctor_run (cmethod->klass, method)) {
10812                                 emit_class_init (cfg, cmethod->klass);
10813                                 CHECK_TYPELOAD (cmethod->klass);
10814                         }
10815
10816                         /*
10817                         if (cfg->gsharedvt) {
10818                                 if (mini_is_gsharedvt_variable_signature (sig))
10819                                         GSHAREDVT_FAILURE (*ip);
10820                         }
10821                         */
10822
10823                         n = fsig->param_count;
10824                         CHECK_STACK (n);
10825
10826                         /* 
10827                          * Generate smaller code for the common newobj <exception> instruction in
10828                          * argument checking code.
10829                          */
10830                         if (cfg->cbb->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
10831                                 is_exception_class (cmethod->klass) && n <= 2 &&
10832                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
10833                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
10834                                 MonoInst *iargs [3];
10835
10836                                 sp -= n;
10837
10838                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
10839                                 switch (n) {
10840                                 case 0:
10841                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
10842                                         break;
10843                                 case 1:
10844                                         iargs [1] = sp [0];
10845                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
10846                                         break;
10847                                 case 2:
10848                                         iargs [1] = sp [0];
10849                                         iargs [2] = sp [1];
10850                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
10851                                         break;
10852                                 default:
10853                                         g_assert_not_reached ();
10854                                 }
10855
10856                                 ip += 5;
10857                                 inline_costs += 5;
10858                                 break;
10859                         }
10860
10861                         /* move the args to allow room for 'this' in the first position */
10862                         while (n--) {
10863                                 --sp;
10864                                 sp [1] = sp [0];
10865                         }
10866
10867                         /* check_call_signature () requires sp[0] to be set */
10868                         this_ins.type = STACK_OBJ;
10869                         sp [0] = &this_ins;
10870                         if (check_call_signature (cfg, fsig, sp))
10871                                 UNVERIFIED;
10872
10873                         iargs [0] = NULL;
10874
10875                         if (mini_class_is_system_array (cmethod->klass)) {
10876                                 *sp = emit_get_rgctx_method (cfg, context_used,
10877                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
10878
10879                                 /* Avoid varargs in the common case */
10880                                 if (fsig->param_count == 1)
10881                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
10882                                 else if (fsig->param_count == 2)
10883                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
10884                                 else if (fsig->param_count == 3)
10885                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
10886                                 else if (fsig->param_count == 4)
10887                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
10888                                 else
10889                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
10890                         } else if (cmethod->string_ctor) {
10891                                 g_assert (!context_used);
10892                                 g_assert (!vtable_arg);
10893                                 /* we simply pass a null pointer */
10894                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
10895                                 /* now call the string ctor */
10896                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
10897                         } else {
10898                                 if (cmethod->klass->valuetype) {
10899                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
10900                                         emit_init_rvar (cfg, iargs [0]->dreg, &cmethod->klass->byval_arg);
10901                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
10902
10903                                         alloc = NULL;
10904
10905                                         /* 
10906                                          * The code generated by mini_emit_virtual_call () expects
10907                                          * iargs [0] to be a boxed instance, but luckily the vcall
10908                                          * will be transformed into a normal call there.
10909                                          */
10910                                 } else if (context_used) {
10911                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
10912                                         *sp = alloc;
10913                                 } else {
10914                                         MonoVTable *vtable = NULL;
10915
10916                                         if (!cfg->compile_aot)
10917                                                 vtable = mono_class_vtable (cfg->domain, cmethod->klass);
10918                                         CHECK_TYPELOAD (cmethod->klass);
10919
10920                                         /*
10921                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
10922                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
10923                                          * As a workaround, we call class cctors before allocating objects.
10924                                          */
10925                                         if (mini_field_access_needs_cctor_run (cfg, method, cmethod->klass, vtable) && !(g_slist_find (class_inits, cmethod->klass))) {
10926                                                 emit_class_init (cfg, cmethod->klass);
10927                                                 if (cfg->verbose_level > 2)
10928                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
10929                                                 class_inits = g_slist_prepend (class_inits, cmethod->klass);
10930                                         }
10931
10932                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
10933                                         *sp = alloc;
10934                                 }
10935                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
10936
10937                                 if (alloc)
10938                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
10939
10940                                 /* Now call the actual ctor */
10941                                 handle_ctor_call (cfg, cmethod, fsig, context_used, sp, ip, &inline_costs);
10942                                 CHECK_CFG_EXCEPTION;
10943                         }
10944
10945                         if (alloc == NULL) {
10946                                 /* Valuetype */
10947                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
10948                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
10949                                 *sp++= ins;
10950                         } else {
10951                                 *sp++ = alloc;
10952                         }
10953                         
10954                         ip += 5;
10955                         inline_costs += 5;
10956                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip - header->code)))
10957                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10958                         break;
10959                 }
10960                 case CEE_CASTCLASS:
10961                         CHECK_STACK (1);
10962                         --sp;
10963                         CHECK_OPSIZE (5);
10964                         token = read32 (ip + 1);
10965                         klass = mini_get_class (method, token, generic_context);
10966                         CHECK_TYPELOAD (klass);
10967                         if (sp [0]->type != STACK_OBJ)
10968                                 UNVERIFIED;
10969
10970                         ins = handle_castclass (cfg, klass, *sp, ip, &inline_costs);
10971                         CHECK_CFG_EXCEPTION;
10972
10973                         *sp ++ = ins;
10974                         ip += 5;
10975                         break;
10976                 case CEE_ISINST: {
10977                         CHECK_STACK (1);
10978                         --sp;
10979                         CHECK_OPSIZE (5);
10980                         token = read32 (ip + 1);
10981                         klass = mini_get_class (method, token, generic_context);
10982                         CHECK_TYPELOAD (klass);
10983                         if (sp [0]->type != STACK_OBJ)
10984                                 UNVERIFIED;
10985  
10986                         context_used = mini_class_check_context_used (cfg, klass);
10987
10988                         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
10989                                 MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
10990                                 MonoInst *args [3];
10991                                 int idx;
10992
10993                                 /* obj */
10994                                 args [0] = *sp;
10995
10996                                 /* klass */
10997                                 EMIT_NEW_CLASSCONST (cfg, args [1], klass);
10998
10999                                 /* inline cache*/
11000                                 idx = get_castclass_cache_idx (cfg);
11001                                 args [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
11002
11003                                 *sp++ = mono_emit_method_call (cfg, mono_isinst, args, NULL);
11004                                 ip += 5;
11005                                 inline_costs += 2;
11006                         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
11007                                 MonoMethod *mono_isinst;
11008                                 MonoInst *iargs [1];
11009                                 int costs;
11010
11011                                 mono_isinst = mono_marshal_get_isinst (klass); 
11012                                 iargs [0] = sp [0];
11013
11014                                 costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), 
11015                                                                            iargs, ip, cfg->real_offset, TRUE);
11016                                 CHECK_CFG_EXCEPTION;
11017                                 g_assert (costs > 0);
11018                                 
11019                                 ip += 5;
11020                                 cfg->real_offset += 5;
11021
11022                                 *sp++= iargs [0];
11023
11024                                 inline_costs += costs;
11025                         }
11026                         else {
11027                                 ins = handle_isinst (cfg, klass, *sp, context_used);
11028                                 CHECK_CFG_EXCEPTION;
11029                                 *sp ++ = ins;
11030                                 ip += 5;
11031                         }
11032                         break;
11033                 }
11034                 case CEE_UNBOX_ANY: {
11035                         MonoInst *res, *addr;
11036
11037                         CHECK_STACK (1);
11038                         --sp;
11039                         CHECK_OPSIZE (5);
11040                         token = read32 (ip + 1);
11041                         klass = mini_get_class (method, token, generic_context);
11042                         CHECK_TYPELOAD (klass);
11043
11044                         mono_save_token_info (cfg, image, token, klass);
11045
11046                         context_used = mini_class_check_context_used (cfg, klass);
11047
11048                         if (mini_is_gsharedvt_klass (klass)) {
11049                                 res = handle_unbox_gsharedvt (cfg, klass, *sp);
11050                                 inline_costs += 2;
11051                         } else if (generic_class_is_reference_type (cfg, klass)) {
11052                                 res = handle_castclass (cfg, klass, *sp, ip, &inline_costs);
11053                                 CHECK_CFG_EXCEPTION;
11054                         } else if (mono_class_is_nullable (klass)) {
11055                                 res = handle_unbox_nullable (cfg, *sp, klass, context_used);
11056                         } else {
11057                                 addr = handle_unbox (cfg, klass, sp, context_used);
11058                                 /* LDOBJ */
11059                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11060                                 res = ins;
11061                                 inline_costs += 2;
11062                         }
11063
11064                         *sp ++ = res;
11065                         ip += 5;
11066                         break;
11067                 }
11068                 case CEE_BOX: {
11069                         MonoInst *val;
11070                         MonoClass *enum_class;
11071                         MonoMethod *has_flag;
11072
11073                         CHECK_STACK (1);
11074                         --sp;
11075                         val = *sp;
11076                         CHECK_OPSIZE (5);
11077                         token = read32 (ip + 1);
11078                         klass = mini_get_class (method, token, generic_context);
11079                         CHECK_TYPELOAD (klass);
11080
11081                         mono_save_token_info (cfg, image, token, klass);
11082
11083                         context_used = mini_class_check_context_used (cfg, klass);
11084
11085                         if (generic_class_is_reference_type (cfg, klass)) {
11086                                 *sp++ = val;
11087                                 ip += 5;
11088                                 break;
11089                         }
11090
11091                         if (klass == mono_defaults.void_class)
11092                                 UNVERIFIED;
11093                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
11094                                 UNVERIFIED;
11095                         /* frequent check in generic code: box (struct), brtrue */
11096
11097                         /*
11098                          * Look for:
11099                          *
11100                          *   <push int/long ptr>
11101                          *   <push int/long>
11102                          *   box MyFlags
11103                          *   constrained. MyFlags
11104                          *   callvirt instace bool class [mscorlib] System.Enum::HasFlag (class [mscorlib] System.Enum)
11105                          *
11106                          * If we find this sequence and the operand types on box and constrained
11107                          * are equal, we can emit a specialized instruction sequence instead of
11108                          * the very slow HasFlag () call.
11109                          */
11110                         if ((cfg->opt & MONO_OPT_INTRINS) &&
11111                             /* Cheap checks first. */
11112                             ip + 5 + 6 + 5 < end &&
11113                             ip [5] == CEE_PREFIX1 &&
11114                             ip [6] == CEE_CONSTRAINED_ &&
11115                             ip [11] == CEE_CALLVIRT &&
11116                             ip_in_bb (cfg, cfg->cbb, ip + 5 + 6 + 5) &&
11117                             mono_class_is_enum (klass) &&
11118                             (enum_class = mini_get_class (method, read32 (ip + 7), generic_context)) &&
11119                             (has_flag = mini_get_method (cfg, method, read32 (ip + 12), NULL, generic_context)) &&
11120                             has_flag->klass == mono_defaults.enum_class &&
11121                             !strcmp (has_flag->name, "HasFlag") &&
11122                             has_flag->signature->hasthis &&
11123                             has_flag->signature->param_count == 1) {
11124                                 CHECK_TYPELOAD (enum_class);
11125
11126                                 if (enum_class == klass) {
11127                                         MonoInst *enum_this, *enum_flag;
11128
11129                                         ip += 5 + 6 + 5;
11130                                         --sp;
11131
11132                                         enum_this = sp [0];
11133                                         enum_flag = sp [1];
11134
11135                                         *sp++ = handle_enum_has_flag (cfg, klass, enum_this, enum_flag);
11136                                         break;
11137                                 }
11138                         }
11139
11140                         // FIXME: LLVM can't handle the inconsistent bb linking
11141                         if (!mono_class_is_nullable (klass) &&
11142                                 !mini_is_gsharedvt_klass (klass) &&
11143                                 ip + 5 < end && ip_in_bb (cfg, cfg->cbb, ip + 5) &&
11144                                 (ip [5] == CEE_BRTRUE || 
11145                                  ip [5] == CEE_BRTRUE_S ||
11146                                  ip [5] == CEE_BRFALSE ||
11147                                  ip [5] == CEE_BRFALSE_S)) {
11148                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
11149                                 int dreg;
11150                                 MonoBasicBlock *true_bb, *false_bb;
11151
11152                                 ip += 5;
11153
11154                                 if (cfg->verbose_level > 3) {
11155                                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
11156                                         printf ("<box+brtrue opt>\n");
11157                                 }
11158
11159                                 switch (*ip) {
11160                                 case CEE_BRTRUE_S:
11161                                 case CEE_BRFALSE_S:
11162                                         CHECK_OPSIZE (2);
11163                                         ip++;
11164                                         target = ip + 1 + (signed char)(*ip);
11165                                         ip++;
11166                                         break;
11167                                 case CEE_BRTRUE:
11168                                 case CEE_BRFALSE:
11169                                         CHECK_OPSIZE (5);
11170                                         ip++;
11171                                         target = ip + 4 + (gint)(read32 (ip));
11172                                         ip += 4;
11173                                         break;
11174                                 default:
11175                                         g_assert_not_reached ();
11176                                 }
11177
11178                                 /* 
11179                                  * We need to link both bblocks, since it is needed for handling stack
11180                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
11181                                  * Branching to only one of them would lead to inconsistencies, so
11182                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
11183                                  */
11184                                 GET_BBLOCK (cfg, true_bb, target);
11185                                 GET_BBLOCK (cfg, false_bb, ip);
11186
11187                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
11188                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
11189
11190                                 if (sp != stack_start) {
11191                                         handle_stack_args (cfg, stack_start, sp - stack_start);
11192                                         sp = stack_start;
11193                                         CHECK_UNVERIFIABLE (cfg);
11194                                 }
11195
11196                                 if (COMPILE_LLVM (cfg)) {
11197                                         dreg = alloc_ireg (cfg);
11198                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
11199                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
11200
11201                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
11202                                 } else {
11203                                         /* The JIT can't eliminate the iconst+compare */
11204                                         MONO_INST_NEW (cfg, ins, OP_BR);
11205                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
11206                                         MONO_ADD_INS (cfg->cbb, ins);
11207                                 }
11208
11209                                 start_new_bblock = 1;
11210                                 break;
11211                         }
11212
11213                         *sp++ = handle_box (cfg, val, klass, context_used);
11214
11215                         CHECK_CFG_EXCEPTION;
11216                         ip += 5;
11217                         inline_costs += 1;
11218                         break;
11219                 }
11220                 case CEE_UNBOX: {
11221                         CHECK_STACK (1);
11222                         --sp;
11223                         CHECK_OPSIZE (5);
11224                         token = read32 (ip + 1);
11225                         klass = mini_get_class (method, token, generic_context);
11226                         CHECK_TYPELOAD (klass);
11227
11228                         mono_save_token_info (cfg, image, token, klass);
11229
11230                         context_used = mini_class_check_context_used (cfg, klass);
11231
11232                         if (mono_class_is_nullable (klass)) {
11233                                 MonoInst *val;
11234
11235                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
11236                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
11237
11238                                 *sp++= ins;
11239                         } else {
11240                                 ins = handle_unbox (cfg, klass, sp, context_used);
11241                                 *sp++ = ins;
11242                         }
11243                         ip += 5;
11244                         inline_costs += 2;
11245                         break;
11246                 }
11247                 case CEE_LDFLD:
11248                 case CEE_LDFLDA:
11249                 case CEE_STFLD:
11250                 case CEE_LDSFLD:
11251                 case CEE_LDSFLDA:
11252                 case CEE_STSFLD: {
11253                         MonoClassField *field;
11254 #ifndef DISABLE_REMOTING
11255                         int costs;
11256 #endif
11257                         guint foffset;
11258                         gboolean is_instance;
11259                         int op;
11260                         gpointer addr = NULL;
11261                         gboolean is_special_static;
11262                         MonoType *ftype;
11263                         MonoInst *store_val = NULL;
11264                         MonoInst *thread_ins;
11265
11266                         op = *ip;
11267                         is_instance = (op == CEE_LDFLD || op == CEE_LDFLDA || op == CEE_STFLD);
11268                         if (is_instance) {
11269                                 if (op == CEE_STFLD) {
11270                                         CHECK_STACK (2);
11271                                         sp -= 2;
11272                                         store_val = sp [1];
11273                                 } else {
11274                                         CHECK_STACK (1);
11275                                         --sp;
11276                                 }
11277                                 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
11278                                         UNVERIFIED;
11279                                 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
11280                                         UNVERIFIED;
11281                         } else {
11282                                 if (op == CEE_STSFLD) {
11283                                         CHECK_STACK (1);
11284                                         sp--;
11285                                         store_val = sp [0];
11286                                 }
11287                         }
11288
11289                         CHECK_OPSIZE (5);
11290                         token = read32 (ip + 1);
11291                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
11292                                 field = (MonoClassField *)mono_method_get_wrapper_data (method, token);
11293                                 klass = field->parent;
11294                         }
11295                         else {
11296                                 field = mono_field_from_token_checked (image, token, &klass, generic_context, &cfg->error);
11297                                 CHECK_CFG_ERROR;
11298                         }
11299                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
11300                                 FIELD_ACCESS_FAILURE (method, field);
11301                         mono_class_init (klass);
11302
11303                         /* if the class is Critical then transparent code cannot access it's fields */
11304                         if (!is_instance && mono_security_core_clr_enabled ())
11305                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
11306
11307                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
11308                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
11309                         if (mono_security_core_clr_enabled ())
11310                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
11311                         */
11312
11313                         ftype = mono_field_get_type (field);
11314
11315                         /*
11316                          * LDFLD etc. is usable on static fields as well, so convert those cases to
11317                          * the static case.
11318                          */
11319                         if (is_instance && ftype->attrs & FIELD_ATTRIBUTE_STATIC) {
11320                                 switch (op) {
11321                                 case CEE_LDFLD:
11322                                         op = CEE_LDSFLD;
11323                                         break;
11324                                 case CEE_STFLD:
11325                                         op = CEE_STSFLD;
11326                                         break;
11327                                 case CEE_LDFLDA:
11328                                         op = CEE_LDSFLDA;
11329                                         break;
11330                                 default:
11331                                         g_assert_not_reached ();
11332                                 }
11333                                 is_instance = FALSE;
11334                         }
11335
11336                         context_used = mini_class_check_context_used (cfg, klass);
11337
11338                         /* INSTANCE CASE */
11339
11340                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
11341                         if (op == CEE_STFLD) {
11342                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
11343                                         UNVERIFIED;
11344 #ifndef DISABLE_REMOTING
11345                                 if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
11346                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
11347                                         MonoInst *iargs [5];
11348
11349                                         GSHAREDVT_FAILURE (op);
11350
11351                                         iargs [0] = sp [0];
11352                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11353                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
11354                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
11355                                                     field->offset);
11356                                         iargs [4] = sp [1];
11357
11358                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
11359                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
11360                                                                                            iargs, ip, cfg->real_offset, TRUE);
11361                                                 CHECK_CFG_EXCEPTION;
11362                                                 g_assert (costs > 0);
11363                                                       
11364                                                 cfg->real_offset += 5;
11365
11366                                                 inline_costs += costs;
11367                                         } else {
11368                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
11369                                         }
11370                                 } else
11371 #endif
11372                                 {
11373                                         MonoInst *store, *wbarrier_ptr_ins = NULL;
11374
11375                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
11376
11377                                         if (mini_is_gsharedvt_klass (klass)) {
11378                                                 MonoInst *offset_ins;
11379
11380                                                 context_used = mini_class_check_context_used (cfg, klass);
11381
11382                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11383                                                 /* The value is offset by 1 */
11384                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11385                                                 dreg = alloc_ireg_mp (cfg);
11386                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11387                                                 wbarrier_ptr_ins = ins;
11388                                                 /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
11389                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
11390                                         } else {
11391                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
11392                                         }
11393                                         if (sp [0]->opcode != OP_LDADDR)
11394                                                 store->flags |= MONO_INST_FAULT;
11395
11396                                         if (cfg->gen_write_barriers && mini_type_to_stind (cfg, field->type) == CEE_STIND_REF && !(sp [1]->opcode == OP_PCONST && sp [1]->inst_c0 == 0)) {
11397                                                 if (mini_is_gsharedvt_klass (klass)) {
11398                                                         g_assert (wbarrier_ptr_ins);
11399                                                         emit_write_barrier (cfg, wbarrier_ptr_ins, sp [1]);
11400                                                 } else {
11401                                                         /* insert call to write barrier */
11402                                                         MonoInst *ptr;
11403                                                         int dreg;
11404
11405                                                         dreg = alloc_ireg_mp (cfg);
11406                                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
11407                                                         emit_write_barrier (cfg, ptr, sp [1]);
11408                                                 }
11409                                         }
11410
11411                                         store->flags |= ins_flag;
11412                                 }
11413                                 ins_flag = 0;
11414                                 ip += 5;
11415                                 break;
11416                         }
11417
11418 #ifndef DISABLE_REMOTING
11419                         if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
11420                                 MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
11421                                 MonoInst *iargs [4];
11422
11423                                 GSHAREDVT_FAILURE (op);
11424
11425                                 iargs [0] = sp [0];
11426                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11427                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
11428                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
11429                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
11430                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
11431                                                                                    iargs, ip, cfg->real_offset, TRUE);
11432                                         CHECK_CFG_EXCEPTION;
11433                                         g_assert (costs > 0);
11434                                                       
11435                                         cfg->real_offset += 5;
11436
11437                                         *sp++ = iargs [0];
11438
11439                                         inline_costs += costs;
11440                                 } else {
11441                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
11442                                         *sp++ = ins;
11443                                 }
11444                         } else 
11445 #endif
11446                         if (is_instance) {
11447                                 if (sp [0]->type == STACK_VTYPE) {
11448                                         MonoInst *var;
11449
11450                                         /* Have to compute the address of the variable */
11451
11452                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
11453                                         if (!var)
11454                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
11455                                         else
11456                                                 g_assert (var->klass == klass);
11457                                         
11458                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
11459                                         sp [0] = ins;
11460                                 }
11461
11462                                 if (op == CEE_LDFLDA) {
11463                                         if (sp [0]->type == STACK_OBJ) {
11464                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
11465                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
11466                                         }
11467
11468                                         dreg = alloc_ireg_mp (cfg);
11469
11470                                         if (mini_is_gsharedvt_klass (klass)) {
11471                                                 MonoInst *offset_ins;
11472
11473                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11474                                                 /* The value is offset by 1 */
11475                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11476                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11477                                         } else {
11478                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
11479                                         }
11480                                         ins->klass = mono_class_from_mono_type (field->type);
11481                                         ins->type = STACK_MP;
11482                                         *sp++ = ins;
11483                                 } else {
11484                                         MonoInst *load;
11485
11486                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
11487
11488                                         if (mini_is_gsharedvt_klass (klass)) {
11489                                                 MonoInst *offset_ins;
11490
11491                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11492                                                 /* The value is offset by 1 */
11493                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11494                                                 dreg = alloc_ireg_mp (cfg);
11495                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11496                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
11497                                         } else {
11498                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
11499                                         }
11500                                         load->flags |= ins_flag;
11501                                         if (sp [0]->opcode != OP_LDADDR)
11502                                                 load->flags |= MONO_INST_FAULT;
11503                                         *sp++ = load;
11504                                 }
11505                         }
11506
11507                         if (is_instance) {
11508                                 ins_flag = 0;
11509                                 ip += 5;
11510                                 break;
11511                         }
11512
11513                         /* STATIC CASE */
11514                         context_used = mini_class_check_context_used (cfg, klass);
11515
11516                         if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL) {
11517                                 mono_error_set_field_load (&cfg->error, field->parent, field->name, "Using static instructions with literal field");
11518                                 CHECK_CFG_ERROR;
11519                         }
11520
11521                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
11522                          * to be called here.
11523                          */
11524                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
11525                                 mono_class_vtable (cfg->domain, klass);
11526                                 CHECK_TYPELOAD (klass);
11527                         }
11528                         mono_domain_lock (cfg->domain);
11529                         if (cfg->domain->special_static_fields)
11530                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
11531                         mono_domain_unlock (cfg->domain);
11532
11533                         is_special_static = mono_class_field_is_special_static (field);
11534
11535                         if (is_special_static && ((gsize)addr & 0x80000000) == 0)
11536                                 thread_ins = mono_get_thread_intrinsic (cfg);
11537                         else
11538                                 thread_ins = NULL;
11539
11540                         /* Generate IR to compute the field address */
11541                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && thread_ins && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
11542                                 /*
11543                                  * Fast access to TLS data
11544                                  * Inline version of get_thread_static_data () in
11545                                  * threads.c.
11546                                  */
11547                                 guint32 offset;
11548                                 int idx, static_data_reg, array_reg, dreg;
11549
11550                                 GSHAREDVT_FAILURE (op);
11551
11552                                 MONO_ADD_INS (cfg->cbb, thread_ins);
11553                                 static_data_reg = alloc_ireg (cfg);
11554                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
11555
11556                                 if (cfg->compile_aot) {
11557                                         int offset_reg, offset2_reg, idx_reg;
11558
11559                                         /* For TLS variables, this will return the TLS offset */
11560                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
11561                                         offset_reg = ins->dreg;
11562                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
11563                                         idx_reg = alloc_ireg (cfg);
11564                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, idx_reg, offset_reg, 0x3f);
11565                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
11566                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
11567                                         array_reg = alloc_ireg (cfg);
11568                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
11569                                         offset2_reg = alloc_ireg (cfg);
11570                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, offset2_reg, offset_reg, 6);
11571                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset2_reg, 0x1ffffff);
11572                                         dreg = alloc_ireg (cfg);
11573                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
11574                                 } else {
11575                                         offset = (gsize)addr & 0x7fffffff;
11576                                         idx = offset & 0x3f;
11577
11578                                         array_reg = alloc_ireg (cfg);
11579                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
11580                                         dreg = alloc_ireg (cfg);
11581                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, ((offset >> 6) & 0x1ffffff));
11582                                 }
11583                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
11584                                         (cfg->compile_aot && is_special_static) ||
11585                                         (context_used && is_special_static)) {
11586                                 MonoInst *iargs [2];
11587
11588                                 g_assert (field->parent);
11589                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11590                                 if (context_used) {
11591                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
11592                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
11593                                 } else {
11594                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11595                                 }
11596                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11597                         } else if (context_used) {
11598                                 MonoInst *static_data;
11599
11600                                 /*
11601                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
11602                                         method->klass->name_space, method->klass->name, method->name,
11603                                         depth, field->offset);
11604                                 */
11605
11606                                 if (mono_class_needs_cctor_run (klass, method))
11607                                         emit_class_init (cfg, klass);
11608
11609                                 /*
11610                                  * The pointer we're computing here is
11611                                  *
11612                                  *   super_info.static_data + field->offset
11613                                  */
11614                                 static_data = emit_get_rgctx_klass (cfg, context_used,
11615                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
11616
11617                                 if (mini_is_gsharedvt_klass (klass)) {
11618                                         MonoInst *offset_ins;
11619
11620                                         offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11621                                         /* The value is offset by 1 */
11622                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11623                                         dreg = alloc_ireg_mp (cfg);
11624                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
11625                                 } else if (field->offset == 0) {
11626                                         ins = static_data;
11627                                 } else {
11628                                         int addr_reg = mono_alloc_preg (cfg);
11629                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
11630                                 }
11631                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
11632                                 MonoInst *iargs [2];
11633
11634                                 g_assert (field->parent);
11635                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11636                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11637                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11638                         } else {
11639                                 MonoVTable *vtable = NULL;
11640
11641                                 if (!cfg->compile_aot)
11642                                         vtable = mono_class_vtable (cfg->domain, klass);
11643                                 CHECK_TYPELOAD (klass);
11644
11645                                 if (!addr) {
11646                                         if (mini_field_access_needs_cctor_run (cfg, method, klass, vtable)) {
11647                                                 if (!(g_slist_find (class_inits, klass))) {
11648                                                         emit_class_init (cfg, klass);
11649                                                         if (cfg->verbose_level > 2)
11650                                                                 printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
11651                                                         class_inits = g_slist_prepend (class_inits, klass);
11652                                                 }
11653                                         } else {
11654                                                 if (cfg->run_cctors) {
11655                                                         /* This makes so that inline cannot trigger */
11656                                                         /* .cctors: too many apps depend on them */
11657                                                         /* running with a specific order... */
11658                                                         g_assert (vtable);
11659                                                         if (! vtable->initialized)
11660                                                                 INLINE_FAILURE ("class init");
11661                                                         if (!mono_runtime_class_init_full (vtable, &cfg->error)) {
11662                                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
11663                                                                 goto exception_exit;
11664                                                         }
11665                                                 }
11666                                         }
11667                                         if (cfg->compile_aot)
11668                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
11669                                         else {
11670                                                 g_assert (vtable);
11671                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11672                                                 g_assert (addr);
11673                                                 EMIT_NEW_PCONST (cfg, ins, addr);
11674                                         }
11675                                 } else {
11676                                         MonoInst *iargs [1];
11677                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
11678                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
11679                                 }
11680                         }
11681
11682                         /* Generate IR to do the actual load/store operation */
11683
11684                         if ((op == CEE_STFLD || op == CEE_STSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11685                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11686                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11687                         }
11688
11689                         if (op == CEE_LDSFLDA) {
11690                                 ins->klass = mono_class_from_mono_type (ftype);
11691                                 ins->type = STACK_PTR;
11692                                 *sp++ = ins;
11693                         } else if (op == CEE_STSFLD) {
11694                                 MonoInst *store;
11695
11696                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
11697                                 store->flags |= ins_flag;
11698                         } else {
11699                                 gboolean is_const = FALSE;
11700                                 MonoVTable *vtable = NULL;
11701                                 gpointer addr = NULL;
11702
11703                                 if (!context_used) {
11704                                         vtable = mono_class_vtable (cfg->domain, klass);
11705                                         CHECK_TYPELOAD (klass);
11706                                 }
11707                                 if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) ||
11708                                                 (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) {
11709                                         int ro_type = ftype->type;
11710                                         if (!addr)
11711                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11712                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
11713                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
11714                                         }
11715
11716                                         GSHAREDVT_FAILURE (op);
11717
11718                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
11719                                         is_const = TRUE;
11720                                         switch (ro_type) {
11721                                         case MONO_TYPE_BOOLEAN:
11722                                         case MONO_TYPE_U1:
11723                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
11724                                                 sp++;
11725                                                 break;
11726                                         case MONO_TYPE_I1:
11727                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
11728                                                 sp++;
11729                                                 break;                                          
11730                                         case MONO_TYPE_CHAR:
11731                                         case MONO_TYPE_U2:
11732                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
11733                                                 sp++;
11734                                                 break;
11735                                         case MONO_TYPE_I2:
11736                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
11737                                                 sp++;
11738                                                 break;
11739                                                 break;
11740                                         case MONO_TYPE_I4:
11741                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
11742                                                 sp++;
11743                                                 break;                                          
11744                                         case MONO_TYPE_U4:
11745                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
11746                                                 sp++;
11747                                                 break;
11748                                         case MONO_TYPE_I:
11749                                         case MONO_TYPE_U:
11750                                         case MONO_TYPE_PTR:
11751                                         case MONO_TYPE_FNPTR:
11752                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11753                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
11754                                                 sp++;
11755                                                 break;
11756                                         case MONO_TYPE_STRING:
11757                                         case MONO_TYPE_OBJECT:
11758                                         case MONO_TYPE_CLASS:
11759                                         case MONO_TYPE_SZARRAY:
11760                                         case MONO_TYPE_ARRAY:
11761                                                 if (!mono_gc_is_moving ()) {
11762                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11763                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
11764                                                         sp++;
11765                                                 } else {
11766                                                         is_const = FALSE;
11767                                                 }
11768                                                 break;
11769                                         case MONO_TYPE_I8:
11770                                         case MONO_TYPE_U8:
11771                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
11772                                                 sp++;
11773                                                 break;
11774                                         case MONO_TYPE_R4:
11775                                         case MONO_TYPE_R8:
11776                                         case MONO_TYPE_VALUETYPE:
11777                                         default:
11778                                                 is_const = FALSE;
11779                                                 break;
11780                                         }
11781                                 }
11782
11783                                 if (!is_const) {
11784                                         MonoInst *load;
11785
11786                                         CHECK_STACK_OVF (1);
11787
11788                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
11789                                         load->flags |= ins_flag;
11790                                         ins_flag = 0;
11791                                         *sp++ = load;
11792                                 }
11793                         }
11794
11795                         if ((op == CEE_LDFLD || op == CEE_LDSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11796                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
11797                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
11798                         }
11799
11800                         ins_flag = 0;
11801                         ip += 5;
11802                         break;
11803                 }
11804                 case CEE_STOBJ:
11805                         CHECK_STACK (2);
11806                         sp -= 2;
11807                         CHECK_OPSIZE (5);
11808                         token = read32 (ip + 1);
11809                         klass = mini_get_class (method, token, generic_context);
11810                         CHECK_TYPELOAD (klass);
11811                         if (ins_flag & MONO_INST_VOLATILE) {
11812                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11813                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11814                         }
11815                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
11816                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
11817                         ins->flags |= ins_flag;
11818                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
11819                                         generic_class_is_reference_type (cfg, klass)) {
11820                                 /* insert call to write barrier */
11821                                 emit_write_barrier (cfg, sp [0], sp [1]);
11822                         }
11823                         ins_flag = 0;
11824                         ip += 5;
11825                         inline_costs += 1;
11826                         break;
11827
11828                         /*
11829                          * Array opcodes
11830                          */
11831                 case CEE_NEWARR: {
11832                         MonoInst *len_ins;
11833                         const char *data_ptr;
11834                         int data_size = 0;
11835                         guint32 field_token;
11836
11837                         CHECK_STACK (1);
11838                         --sp;
11839
11840                         CHECK_OPSIZE (5);
11841                         token = read32 (ip + 1);
11842
11843                         klass = mini_get_class (method, token, generic_context);
11844                         CHECK_TYPELOAD (klass);
11845
11846                         context_used = mini_class_check_context_used (cfg, klass);
11847
11848                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
11849                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_OVF_U4);
11850                                 ins->sreg1 = sp [0]->dreg;
11851                                 ins->type = STACK_I4;
11852                                 ins->dreg = alloc_ireg (cfg);
11853                                 MONO_ADD_INS (cfg->cbb, ins);
11854                                 *sp = mono_decompose_opcode (cfg, ins);
11855                         }
11856
11857                         if (context_used) {
11858                                 MonoInst *args [3];
11859                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11860                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
11861
11862                                 /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
11863
11864                                 /* vtable */
11865                                 args [0] = emit_get_rgctx_klass (cfg, context_used,
11866                                         array_class, MONO_RGCTX_INFO_VTABLE);
11867                                 /* array len */
11868                                 args [1] = sp [0];
11869
11870                                 if (managed_alloc)
11871                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
11872                                 else
11873                                         ins = mono_emit_jit_icall (cfg, ves_icall_array_new_specific, args);
11874                         } else {
11875                                 if (cfg->opt & MONO_OPT_SHARED) {
11876                                         /* Decompose now to avoid problems with references to the domainvar */
11877                                         MonoInst *iargs [3];
11878
11879                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11880                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11881                                         iargs [2] = sp [0];
11882
11883                                         ins = mono_emit_jit_icall (cfg, ves_icall_array_new, iargs);
11884                                 } else {
11885                                         /* Decompose later since it is needed by abcrem */
11886                                         MonoClass *array_type = mono_array_class_get (klass, 1);
11887                                         mono_class_vtable (cfg->domain, array_type);
11888                                         CHECK_TYPELOAD (array_type);
11889
11890                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
11891                                         ins->dreg = alloc_ireg_ref (cfg);
11892                                         ins->sreg1 = sp [0]->dreg;
11893                                         ins->inst_newa_class = klass;
11894                                         ins->type = STACK_OBJ;
11895                                         ins->klass = array_type;
11896                                         MONO_ADD_INS (cfg->cbb, ins);
11897                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11898                                         cfg->cbb->has_array_access = TRUE;
11899
11900                                         /* Needed so mono_emit_load_get_addr () gets called */
11901                                         mono_get_got_var (cfg);
11902                                 }
11903                         }
11904
11905                         len_ins = sp [0];
11906                         ip += 5;
11907                         *sp++ = ins;
11908                         inline_costs += 1;
11909
11910                         /* 
11911                          * we inline/optimize the initialization sequence if possible.
11912                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
11913                          * for small sizes open code the memcpy
11914                          * ensure the rva field is big enough
11915                          */
11916                         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))) {
11917                                 MonoMethod *memcpy_method = get_memcpy_method ();
11918                                 MonoInst *iargs [3];
11919                                 int add_reg = alloc_ireg_mp (cfg);
11920
11921                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, MONO_STRUCT_OFFSET (MonoArray, vector));
11922                                 if (cfg->compile_aot) {
11923                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
11924                                 } else {
11925                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
11926                                 }
11927                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
11928                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
11929                                 ip += 11;
11930                         }
11931
11932                         break;
11933                 }
11934                 case CEE_LDLEN:
11935                         CHECK_STACK (1);
11936                         --sp;
11937                         if (sp [0]->type != STACK_OBJ)
11938                                 UNVERIFIED;
11939
11940                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
11941                         ins->dreg = alloc_preg (cfg);
11942                         ins->sreg1 = sp [0]->dreg;
11943                         ins->type = STACK_I4;
11944                         /* This flag will be inherited by the decomposition */
11945                         ins->flags |= MONO_INST_FAULT;
11946                         MONO_ADD_INS (cfg->cbb, ins);
11947                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11948                         cfg->cbb->has_array_access = TRUE;
11949                         ip ++;
11950                         *sp++ = ins;
11951                         break;
11952                 case CEE_LDELEMA:
11953                         CHECK_STACK (2);
11954                         sp -= 2;
11955                         CHECK_OPSIZE (5);
11956                         if (sp [0]->type != STACK_OBJ)
11957                                 UNVERIFIED;
11958
11959                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11960
11961                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11962                         CHECK_TYPELOAD (klass);
11963                         /* we need to make sure that this array is exactly the type it needs
11964                          * to be for correctness. the wrappers are lax with their usage
11965                          * so we need to ignore them here
11966                          */
11967                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
11968                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11969                                 mini_emit_check_array_type (cfg, sp [0], array_class);
11970                                 CHECK_TYPELOAD (array_class);
11971                         }
11972
11973                         readonly = FALSE;
11974                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11975                         *sp++ = ins;
11976                         ip += 5;
11977                         break;
11978                 case CEE_LDELEM:
11979                 case CEE_LDELEM_I1:
11980                 case CEE_LDELEM_U1:
11981                 case CEE_LDELEM_I2:
11982                 case CEE_LDELEM_U2:
11983                 case CEE_LDELEM_I4:
11984                 case CEE_LDELEM_U4:
11985                 case CEE_LDELEM_I8:
11986                 case CEE_LDELEM_I:
11987                 case CEE_LDELEM_R4:
11988                 case CEE_LDELEM_R8:
11989                 case CEE_LDELEM_REF: {
11990                         MonoInst *addr;
11991
11992                         CHECK_STACK (2);
11993                         sp -= 2;
11994
11995                         if (*ip == CEE_LDELEM) {
11996                                 CHECK_OPSIZE (5);
11997                                 token = read32 (ip + 1);
11998                                 klass = mini_get_class (method, token, generic_context);
11999                                 CHECK_TYPELOAD (klass);
12000                                 mono_class_init (klass);
12001                         }
12002                         else
12003                                 klass = array_access_to_klass (*ip);
12004
12005                         if (sp [0]->type != STACK_OBJ)
12006                                 UNVERIFIED;
12007
12008                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
12009
12010                         if (mini_is_gsharedvt_variable_klass (klass)) {
12011                                 // FIXME-VT: OP_ICONST optimization
12012                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
12013                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
12014                                 ins->opcode = OP_LOADV_MEMBASE;
12015                         } else if (sp [1]->opcode == OP_ICONST) {
12016                                 int array_reg = sp [0]->dreg;
12017                                 int index_reg = sp [1]->dreg;
12018                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
12019
12020                                 if (SIZEOF_REGISTER == 8 && COMPILE_LLVM (cfg))
12021                                         MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, index_reg);
12022
12023                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
12024                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
12025                         } else {
12026                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
12027                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
12028                         }
12029                         *sp++ = ins;
12030                         if (*ip == CEE_LDELEM)
12031                                 ip += 5;
12032                         else
12033                                 ++ip;
12034                         break;
12035                 }
12036                 case CEE_STELEM_I:
12037                 case CEE_STELEM_I1:
12038                 case CEE_STELEM_I2:
12039                 case CEE_STELEM_I4:
12040                 case CEE_STELEM_I8:
12041                 case CEE_STELEM_R4:
12042                 case CEE_STELEM_R8:
12043                 case CEE_STELEM_REF:
12044                 case CEE_STELEM: {
12045                         CHECK_STACK (3);
12046                         sp -= 3;
12047
12048                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
12049
12050                         if (*ip == CEE_STELEM) {
12051                                 CHECK_OPSIZE (5);
12052                                 token = read32 (ip + 1);
12053                                 klass = mini_get_class (method, token, generic_context);
12054                                 CHECK_TYPELOAD (klass);
12055                                 mono_class_init (klass);
12056                         }
12057                         else
12058                                 klass = array_access_to_klass (*ip);
12059
12060                         if (sp [0]->type != STACK_OBJ)
12061                                 UNVERIFIED;
12062
12063                         emit_array_store (cfg, klass, sp, TRUE);
12064
12065                         if (*ip == CEE_STELEM)
12066                                 ip += 5;
12067                         else
12068                                 ++ip;
12069                         inline_costs += 1;
12070                         break;
12071                 }
12072                 case CEE_CKFINITE: {
12073                         CHECK_STACK (1);
12074                         --sp;
12075
12076                         if (cfg->llvm_only) {
12077                                 MonoInst *iargs [1];
12078
12079                                 iargs [0] = sp [0];
12080                                 *sp++ = mono_emit_jit_icall (cfg, mono_ckfinite, iargs);
12081                         } else  {
12082                                 MONO_INST_NEW (cfg, ins, OP_CKFINITE);
12083                                 ins->sreg1 = sp [0]->dreg;
12084                                 ins->dreg = alloc_freg (cfg);
12085                                 ins->type = STACK_R8;
12086                                 MONO_ADD_INS (cfg->cbb, ins);
12087
12088                                 *sp++ = mono_decompose_opcode (cfg, ins);
12089                         }
12090
12091                         ++ip;
12092                         break;
12093                 }
12094                 case CEE_REFANYVAL: {
12095                         MonoInst *src_var, *src;
12096
12097                         int klass_reg = alloc_preg (cfg);
12098                         int dreg = alloc_preg (cfg);
12099
12100                         GSHAREDVT_FAILURE (*ip);
12101
12102                         CHECK_STACK (1);
12103                         MONO_INST_NEW (cfg, ins, *ip);
12104                         --sp;
12105                         CHECK_OPSIZE (5);
12106                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
12107                         CHECK_TYPELOAD (klass);
12108
12109                         context_used = mini_class_check_context_used (cfg, klass);
12110
12111                         // FIXME:
12112                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12113                         if (!src_var)
12114                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
12115                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
12116                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass));
12117
12118                         if (context_used) {
12119                                 MonoInst *klass_ins;
12120
12121                                 klass_ins = emit_get_rgctx_klass (cfg, context_used,
12122                                                 klass, MONO_RGCTX_INFO_KLASS);
12123
12124                                 // FIXME:
12125                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
12126                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
12127                         } else {
12128                                 mini_emit_class_check (cfg, klass_reg, klass);
12129                         }
12130                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value));
12131                         ins->type = STACK_MP;
12132                         ins->klass = klass;
12133                         *sp++ = ins;
12134                         ip += 5;
12135                         break;
12136                 }
12137                 case CEE_MKREFANY: {
12138                         MonoInst *loc, *addr;
12139
12140                         GSHAREDVT_FAILURE (*ip);
12141
12142                         CHECK_STACK (1);
12143                         MONO_INST_NEW (cfg, ins, *ip);
12144                         --sp;
12145                         CHECK_OPSIZE (5);
12146                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
12147                         CHECK_TYPELOAD (klass);
12148
12149                         context_used = mini_class_check_context_used (cfg, klass);
12150
12151                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
12152                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
12153
12154                         if (context_used) {
12155                                 MonoInst *const_ins;
12156                                 int type_reg = alloc_preg (cfg);
12157
12158                                 const_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
12159                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
12160                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
12161                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
12162                         } else if (cfg->compile_aot) {
12163                                 int const_reg = alloc_preg (cfg);
12164                                 int type_reg = alloc_preg (cfg);
12165
12166                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
12167                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
12168                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
12169                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
12170                         } else {
12171                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), &klass->byval_arg);
12172                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), klass);
12173                         }
12174                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
12175
12176                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
12177                         ins->type = STACK_VTYPE;
12178                         ins->klass = mono_defaults.typed_reference_class;
12179                         *sp++ = ins;
12180                         ip += 5;
12181                         break;
12182                 }
12183                 case CEE_LDTOKEN: {
12184                         gpointer handle;
12185                         MonoClass *handle_class;
12186
12187                         CHECK_STACK_OVF (1);
12188
12189                         CHECK_OPSIZE (5);
12190                         n = read32 (ip + 1);
12191
12192                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
12193                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
12194                                 handle = mono_method_get_wrapper_data (method, n);
12195                                 handle_class = (MonoClass *)mono_method_get_wrapper_data (method, n + 1);
12196                                 if (handle_class == mono_defaults.typehandle_class)
12197                                         handle = &((MonoClass*)handle)->byval_arg;
12198                         }
12199                         else {
12200                                 handle = mono_ldtoken_checked (image, n, &handle_class, generic_context, &cfg->error);
12201                                 CHECK_CFG_ERROR;
12202                         }
12203                         if (!handle)
12204                                 LOAD_ERROR;
12205                         mono_class_init (handle_class);
12206                         if (cfg->gshared) {
12207                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
12208                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
12209                                         /* This case handles ldtoken
12210                                            of an open type, like for
12211                                            typeof(Gen<>). */
12212                                         context_used = 0;
12213                                 } else if (handle_class == mono_defaults.typehandle_class) {
12214                                         context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type ((MonoType *)handle));
12215                                 } else if (handle_class == mono_defaults.fieldhandle_class)
12216                                         context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
12217                                 else if (handle_class == mono_defaults.methodhandle_class)
12218                                         context_used = mini_method_check_context_used (cfg, (MonoMethod *)handle);
12219                                 else
12220                                         g_assert_not_reached ();
12221                         }
12222
12223                         if ((cfg->opt & MONO_OPT_SHARED) &&
12224                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
12225                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
12226                                 MonoInst *addr, *vtvar, *iargs [3];
12227                                 int method_context_used;
12228
12229                                 method_context_used = mini_method_check_context_used (cfg, method);
12230
12231                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
12232
12233                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
12234                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
12235                                 if (method_context_used) {
12236                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
12237                                                 method, MONO_RGCTX_INFO_METHOD);
12238                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
12239                                 } else {
12240                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
12241                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
12242                                 }
12243                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12244
12245                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
12246
12247                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12248                         } else {
12249                                 if ((ip + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 5) && 
12250                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
12251                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
12252                                         (cmethod->klass == mono_defaults.systemtype_class) &&
12253                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
12254                                         MonoClass *tclass = mono_class_from_mono_type ((MonoType *)handle);
12255
12256                                         mono_class_init (tclass);
12257                                         if (context_used) {
12258                                                 ins = emit_get_rgctx_klass (cfg, context_used,
12259                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
12260                                         } else if (cfg->compile_aot) {
12261                                                 if (method->wrapper_type) {
12262                                                         mono_error_init (&error); //got to do it since there are multiple conditionals below
12263                                                         if (mono_class_get_checked (tclass->image, tclass->type_token, &error) == tclass && !generic_context) {
12264                                                                 /* Special case for static synchronized wrappers */
12265                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
12266                                                         } else {
12267                                                                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
12268                                                                 /* FIXME: n is not a normal token */
12269                                                                 DISABLE_AOT (cfg);
12270                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12271                                                         }
12272                                                 } else {
12273                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
12274                                                 }
12275                                         } else {
12276                                                 MonoReflectionType *rt = mono_type_get_object_checked (cfg->domain, (MonoType *)handle, &cfg->error);
12277                                                 CHECK_CFG_ERROR;
12278                                                 EMIT_NEW_PCONST (cfg, ins, rt);
12279                                         }
12280                                         ins->type = STACK_OBJ;
12281                                         ins->klass = cmethod->klass;
12282                                         ip += 5;
12283                                 } else {
12284                                         MonoInst *addr, *vtvar;
12285
12286                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
12287
12288                                         if (context_used) {
12289                                                 if (handle_class == mono_defaults.typehandle_class) {
12290                                                         ins = emit_get_rgctx_klass (cfg, context_used,
12291                                                                         mono_class_from_mono_type ((MonoType *)handle),
12292                                                                         MONO_RGCTX_INFO_TYPE);
12293                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
12294                                                         ins = emit_get_rgctx_method (cfg, context_used,
12295                                                                         (MonoMethod *)handle, MONO_RGCTX_INFO_METHOD);
12296                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
12297                                                         ins = emit_get_rgctx_field (cfg, context_used,
12298                                                                         (MonoClassField *)handle, MONO_RGCTX_INFO_CLASS_FIELD);
12299                                                 } else {
12300                                                         g_assert_not_reached ();
12301                                                 }
12302                                         } else if (cfg->compile_aot) {
12303                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n, generic_context);
12304                                         } else {
12305                                                 EMIT_NEW_PCONST (cfg, ins, handle);
12306                                         }
12307                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12308                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
12309                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12310                                 }
12311                         }
12312
12313                         *sp++ = ins;
12314                         ip += 5;
12315                         break;
12316                 }
12317                 case CEE_THROW:
12318                         CHECK_STACK (1);
12319                         MONO_INST_NEW (cfg, ins, OP_THROW);
12320                         --sp;
12321                         ins->sreg1 = sp [0]->dreg;
12322                         ip++;
12323                         cfg->cbb->out_of_line = TRUE;
12324                         MONO_ADD_INS (cfg->cbb, ins);
12325                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
12326                         MONO_ADD_INS (cfg->cbb, ins);
12327                         sp = stack_start;
12328                         
12329                         link_bblock (cfg, cfg->cbb, end_bblock);
12330                         start_new_bblock = 1;
12331                         /* This can complicate code generation for llvm since the return value might not be defined */
12332                         if (COMPILE_LLVM (cfg))
12333                                 INLINE_FAILURE ("throw");
12334                         break;
12335                 case CEE_ENDFINALLY:
12336                         /* mono_save_seq_point_info () depends on this */
12337                         if (sp != stack_start)
12338                                 emit_seq_point (cfg, method, ip, FALSE, FALSE);
12339                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
12340                         MONO_ADD_INS (cfg->cbb, ins);
12341                         ip++;
12342                         start_new_bblock = 1;
12343
12344                         /*
12345                          * Control will leave the method so empty the stack, otherwise
12346                          * the next basic block will start with a nonempty stack.
12347                          */
12348                         while (sp != stack_start) {
12349                                 sp--;
12350                         }
12351                         break;
12352                 case CEE_LEAVE:
12353                 case CEE_LEAVE_S: {
12354                         GList *handlers;
12355
12356                         if (*ip == CEE_LEAVE) {
12357                                 CHECK_OPSIZE (5);
12358                                 target = ip + 5 + (gint32)read32(ip + 1);
12359                         } else {
12360                                 CHECK_OPSIZE (2);
12361                                 target = ip + 2 + (signed char)(ip [1]);
12362                         }
12363
12364                         /* empty the stack */
12365                         while (sp != stack_start) {
12366                                 sp--;
12367                         }
12368
12369                         /* 
12370                          * If this leave statement is in a catch block, check for a
12371                          * pending exception, and rethrow it if necessary.
12372                          * We avoid doing this in runtime invoke wrappers, since those are called
12373                          * by native code which excepts the wrapper to catch all exceptions.
12374                          */
12375                         for (i = 0; i < header->num_clauses; ++i) {
12376                                 MonoExceptionClause *clause = &header->clauses [i];
12377
12378                                 /* 
12379                                  * Use <= in the final comparison to handle clauses with multiple
12380                                  * leave statements, like in bug #78024.
12381                                  * The ordering of the exception clauses guarantees that we find the
12382                                  * innermost clause.
12383                                  */
12384                                 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) {
12385                                         MonoInst *exc_ins;
12386                                         MonoBasicBlock *dont_throw;
12387
12388                                         /*
12389                                           MonoInst *load;
12390
12391                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
12392                                         */
12393
12394                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
12395
12396                                         NEW_BBLOCK (cfg, dont_throw);
12397
12398                                         /*
12399                                          * Currently, we always rethrow the abort exception, despite the 
12400                                          * fact that this is not correct. See thread6.cs for an example. 
12401                                          * But propagating the abort exception is more important than 
12402                                          * getting the sematics right.
12403                                          */
12404                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
12405                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
12406                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
12407
12408                                         MONO_START_BB (cfg, dont_throw);
12409                                 }
12410                         }
12411
12412 #ifdef ENABLE_LLVM
12413                         cfg->cbb->try_end = (intptr_t)(ip - header->code);
12414 #endif
12415
12416                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
12417                                 GList *tmp;
12418                                 MonoExceptionClause *clause;
12419
12420                                 for (tmp = handlers; tmp; tmp = tmp->next) {
12421                                         clause = (MonoExceptionClause *)tmp->data;
12422                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
12423                                         g_assert (tblock);
12424                                         link_bblock (cfg, cfg->cbb, tblock);
12425                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
12426                                         ins->inst_target_bb = tblock;
12427                                         ins->inst_eh_block = clause;
12428                                         MONO_ADD_INS (cfg->cbb, ins);
12429                                         cfg->cbb->has_call_handler = 1;
12430                                         if (COMPILE_LLVM (cfg)) {
12431                                                 MonoBasicBlock *target_bb;
12432
12433                                                 /* 
12434                                                  * Link the finally bblock with the target, since it will
12435                                                  * conceptually branch there.
12436                                                  */
12437                                                 GET_BBLOCK (cfg, tblock, cfg->cil_start + clause->handler_offset + clause->handler_len - 1);
12438                                                 GET_BBLOCK (cfg, target_bb, target);
12439                                                 link_bblock (cfg, tblock, target_bb);
12440                                         }
12441                                 }
12442                                 g_list_free (handlers);
12443                         } 
12444
12445                         MONO_INST_NEW (cfg, ins, OP_BR);
12446                         MONO_ADD_INS (cfg->cbb, ins);
12447                         GET_BBLOCK (cfg, tblock, target);
12448                         link_bblock (cfg, cfg->cbb, tblock);
12449                         ins->inst_target_bb = tblock;
12450
12451                         start_new_bblock = 1;
12452
12453                         if (*ip == CEE_LEAVE)
12454                                 ip += 5;
12455                         else
12456                                 ip += 2;
12457
12458                         break;
12459                 }
12460
12461                         /*
12462                          * Mono specific opcodes
12463                          */
12464                 case MONO_CUSTOM_PREFIX: {
12465
12466                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
12467
12468                         CHECK_OPSIZE (2);
12469                         switch (ip [1]) {
12470                         case CEE_MONO_ICALL: {
12471                                 gpointer func;
12472                                 MonoJitICallInfo *info;
12473
12474                                 token = read32 (ip + 2);
12475                                 func = mono_method_get_wrapper_data (method, token);
12476                                 info = mono_find_jit_icall_by_addr (func);
12477                                 if (!info)
12478                                         g_error ("Could not find icall address in wrapper %s", mono_method_full_name (method, 1));
12479                                 g_assert (info);
12480
12481                                 CHECK_STACK (info->sig->param_count);
12482                                 sp -= info->sig->param_count;
12483
12484                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
12485                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
12486                                         *sp++ = ins;
12487
12488                                 ip += 6;
12489                                 inline_costs += 10 * num_calls++;
12490
12491                                 break;
12492                         }
12493                         case CEE_MONO_LDPTR_CARD_TABLE:
12494                         case CEE_MONO_LDPTR_NURSERY_START:
12495                         case CEE_MONO_LDPTR_NURSERY_BITS:
12496                         case CEE_MONO_LDPTR_INT_REQ_FLAG: {
12497                                 CHECK_STACK_OVF (1);
12498
12499                                 switch (ip [1]) {
12500                                         case CEE_MONO_LDPTR_CARD_TABLE:
12501                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
12502                                                 break;
12503                                         case CEE_MONO_LDPTR_NURSERY_START:
12504                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_START, NULL);
12505                                                 break;
12506                                         case CEE_MONO_LDPTR_NURSERY_BITS:
12507                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_BITS, NULL);
12508                                                 break;
12509                                         case CEE_MONO_LDPTR_INT_REQ_FLAG:
12510                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
12511                                                 break;
12512                                 }
12513
12514                                 *sp++ = ins;
12515                                 ip += 2;
12516                                 inline_costs += 10 * num_calls++;
12517                                 break;
12518                         }
12519                         case CEE_MONO_LDPTR: {
12520                                 gpointer ptr;
12521
12522                                 CHECK_STACK_OVF (1);
12523                                 CHECK_OPSIZE (6);
12524                                 token = read32 (ip + 2);
12525
12526                                 ptr = mono_method_get_wrapper_data (method, token);
12527                                 EMIT_NEW_PCONST (cfg, ins, ptr);
12528                                 *sp++ = ins;
12529                                 ip += 6;
12530                                 inline_costs += 10 * num_calls++;
12531                                 /* Can't embed random pointers into AOT code */
12532                                 DISABLE_AOT (cfg);
12533                                 break;
12534                         }
12535                         case CEE_MONO_JIT_ICALL_ADDR: {
12536                                 MonoJitICallInfo *callinfo;
12537                                 gpointer ptr;
12538
12539                                 CHECK_STACK_OVF (1);
12540                                 CHECK_OPSIZE (6);
12541                                 token = read32 (ip + 2);
12542
12543                                 ptr = mono_method_get_wrapper_data (method, token);
12544                                 callinfo = mono_find_jit_icall_by_addr (ptr);
12545                                 g_assert (callinfo);
12546                                 EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
12547                                 *sp++ = ins;
12548                                 ip += 6;
12549                                 inline_costs += 10 * num_calls++;
12550                                 break;
12551                         }
12552                         case CEE_MONO_ICALL_ADDR: {
12553                                 MonoMethod *cmethod;
12554                                 gpointer ptr;
12555
12556                                 CHECK_STACK_OVF (1);
12557                                 CHECK_OPSIZE (6);
12558                                 token = read32 (ip + 2);
12559
12560                                 cmethod = (MonoMethod *)mono_method_get_wrapper_data (method, token);
12561
12562                                 if (cfg->compile_aot) {
12563                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
12564                                 } else {
12565                                         ptr = mono_lookup_internal_call (cmethod);
12566                                         g_assert (ptr);
12567                                         EMIT_NEW_PCONST (cfg, ins, ptr);
12568                                 }
12569                                 *sp++ = ins;
12570                                 ip += 6;
12571                                 break;
12572                         }
12573                         case CEE_MONO_VTADDR: {
12574                                 MonoInst *src_var, *src;
12575
12576                                 CHECK_STACK (1);
12577                                 --sp;
12578
12579                                 // FIXME:
12580                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12581                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
12582                                 *sp++ = src;
12583                                 ip += 2;
12584                                 break;
12585                         }
12586                         case CEE_MONO_NEWOBJ: {
12587                                 MonoInst *iargs [2];
12588
12589                                 CHECK_STACK_OVF (1);
12590                                 CHECK_OPSIZE (6);
12591                                 token = read32 (ip + 2);
12592                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12593                                 mono_class_init (klass);
12594                                 NEW_DOMAINCONST (cfg, iargs [0]);
12595                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
12596                                 NEW_CLASSCONST (cfg, iargs [1], klass);
12597                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
12598                                 *sp++ = mono_emit_jit_icall (cfg, ves_icall_object_new, iargs);
12599                                 ip += 6;
12600                                 inline_costs += 10 * num_calls++;
12601                                 break;
12602                         }
12603                         case CEE_MONO_OBJADDR:
12604                                 CHECK_STACK (1);
12605                                 --sp;
12606                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
12607                                 ins->dreg = alloc_ireg_mp (cfg);
12608                                 ins->sreg1 = sp [0]->dreg;
12609                                 ins->type = STACK_MP;
12610                                 MONO_ADD_INS (cfg->cbb, ins);
12611                                 *sp++ = ins;
12612                                 ip += 2;
12613                                 break;
12614                         case CEE_MONO_LDNATIVEOBJ:
12615                                 /*
12616                                  * Similar to LDOBJ, but instead load the unmanaged 
12617                                  * representation of the vtype to the stack.
12618                                  */
12619                                 CHECK_STACK (1);
12620                                 CHECK_OPSIZE (6);
12621                                 --sp;
12622                                 token = read32 (ip + 2);
12623                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12624                                 g_assert (klass->valuetype);
12625                                 mono_class_init (klass);
12626
12627                                 {
12628                                         MonoInst *src, *dest, *temp;
12629
12630                                         src = sp [0];
12631                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
12632                                         temp->backend.is_pinvoke = 1;
12633                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
12634                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
12635
12636                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
12637                                         dest->type = STACK_VTYPE;
12638                                         dest->klass = klass;
12639
12640                                         *sp ++ = dest;
12641                                         ip += 6;
12642                                 }
12643                                 break;
12644                         case CEE_MONO_RETOBJ: {
12645                                 /*
12646                                  * Same as RET, but return the native representation of a vtype
12647                                  * to the caller.
12648                                  */
12649                                 g_assert (cfg->ret);
12650                                 g_assert (mono_method_signature (method)->pinvoke); 
12651                                 CHECK_STACK (1);
12652                                 --sp;
12653                                 
12654                                 CHECK_OPSIZE (6);
12655                                 token = read32 (ip + 2);    
12656                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12657
12658                                 if (!cfg->vret_addr) {
12659                                         g_assert (cfg->ret_var_is_local);
12660
12661                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
12662                                 } else {
12663                                         EMIT_NEW_RETLOADA (cfg, ins);
12664                                 }
12665                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
12666                                 
12667                                 if (sp != stack_start)
12668                                         UNVERIFIED;
12669                                 
12670                                 MONO_INST_NEW (cfg, ins, OP_BR);
12671                                 ins->inst_target_bb = end_bblock;
12672                                 MONO_ADD_INS (cfg->cbb, ins);
12673                                 link_bblock (cfg, cfg->cbb, end_bblock);
12674                                 start_new_bblock = 1;
12675                                 ip += 6;
12676                                 break;
12677                         }
12678                         case CEE_MONO_CISINST:
12679                         case CEE_MONO_CCASTCLASS: {
12680                                 int token;
12681                                 CHECK_STACK (1);
12682                                 --sp;
12683                                 CHECK_OPSIZE (6);
12684                                 token = read32 (ip + 2);
12685                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12686                                 if (ip [1] == CEE_MONO_CISINST)
12687                                         ins = handle_cisinst (cfg, klass, sp [0]);
12688                                 else
12689                                         ins = handle_ccastclass (cfg, klass, sp [0]);
12690                                 *sp++ = ins;
12691                                 ip += 6;
12692                                 break;
12693                         }
12694                         case CEE_MONO_SAVE_LMF:
12695                         case CEE_MONO_RESTORE_LMF:
12696                                 ip += 2;
12697                                 break;
12698                         case CEE_MONO_CLASSCONST:
12699                                 CHECK_STACK_OVF (1);
12700                                 CHECK_OPSIZE (6);
12701                                 token = read32 (ip + 2);
12702                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
12703                                 *sp++ = ins;
12704                                 ip += 6;
12705                                 inline_costs += 10 * num_calls++;
12706                                 break;
12707                         case CEE_MONO_NOT_TAKEN:
12708                                 cfg->cbb->out_of_line = TRUE;
12709                                 ip += 2;
12710                                 break;
12711                         case CEE_MONO_TLS: {
12712                                 MonoTlsKey key;
12713
12714                                 CHECK_STACK_OVF (1);
12715                                 CHECK_OPSIZE (6);
12716                                 key = (MonoTlsKey)read32 (ip + 2);
12717                                 g_assert (key < TLS_KEY_NUM);
12718
12719                                 ins = mono_create_tls_get (cfg, key);
12720                                 if (!ins) {
12721                                         if (cfg->compile_aot) {
12722                                                 DISABLE_AOT (cfg);
12723                                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
12724                                                 ins->dreg = alloc_preg (cfg);
12725                                                 ins->type = STACK_PTR;
12726                                         } else {
12727                                                 g_assert_not_reached ();
12728                                         }
12729                                 }
12730                                 ins->type = STACK_PTR;
12731                                 MONO_ADD_INS (cfg->cbb, ins);
12732                                 *sp++ = ins;
12733                                 ip += 6;
12734                                 break;
12735                         }
12736                         case CEE_MONO_DYN_CALL: {
12737                                 MonoCallInst *call;
12738
12739                                 /* It would be easier to call a trampoline, but that would put an
12740                                  * extra frame on the stack, confusing exception handling. So
12741                                  * implement it inline using an opcode for now.
12742                                  */
12743
12744                                 if (!cfg->dyn_call_var) {
12745                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12746                                         /* prevent it from being register allocated */
12747                                         cfg->dyn_call_var->flags |= MONO_INST_VOLATILE;
12748                                 }
12749
12750                                 /* Has to use a call inst since it local regalloc expects it */
12751                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
12752                                 ins = (MonoInst*)call;
12753                                 sp -= 2;
12754                                 ins->sreg1 = sp [0]->dreg;
12755                                 ins->sreg2 = sp [1]->dreg;
12756                                 MONO_ADD_INS (cfg->cbb, ins);
12757
12758                                 cfg->param_area = MAX (cfg->param_area, cfg->backend->dyn_call_param_area);
12759
12760                                 ip += 2;
12761                                 inline_costs += 10 * num_calls++;
12762
12763                                 break;
12764                         }
12765                         case CEE_MONO_MEMORY_BARRIER: {
12766                                 CHECK_OPSIZE (6);
12767                                 emit_memory_barrier (cfg, (int)read32 (ip + 2));
12768                                 ip += 6;
12769                                 break;
12770                         }
12771                         case CEE_MONO_JIT_ATTACH: {
12772                                 MonoInst *args [16], *domain_ins;
12773                                 MonoInst *ad_ins, *jit_tls_ins;
12774                                 MonoBasicBlock *next_bb = NULL, *call_bb = NULL;
12775
12776                                 g_assert (!mono_threads_is_coop_enabled ());
12777
12778                                 cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12779
12780                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12781                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12782
12783                                 ad_ins = mono_get_domain_intrinsic (cfg);
12784                                 jit_tls_ins = mono_get_jit_tls_intrinsic (cfg);
12785
12786                                 if (cfg->backend->have_tls_get && ad_ins && jit_tls_ins) {
12787                                         NEW_BBLOCK (cfg, next_bb);
12788                                         NEW_BBLOCK (cfg, call_bb);
12789
12790                                         if (cfg->compile_aot) {
12791                                                 /* AOT code is only used in the root domain */
12792                                                 EMIT_NEW_PCONST (cfg, domain_ins, NULL);
12793                                         } else {
12794                                                 EMIT_NEW_PCONST (cfg, domain_ins, cfg->domain);
12795                                         }
12796                                         MONO_ADD_INS (cfg->cbb, ad_ins);
12797                                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, ad_ins->dreg, domain_ins->dreg);
12798                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, call_bb);
12799
12800                                         MONO_ADD_INS (cfg->cbb, jit_tls_ins);
12801                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, jit_tls_ins->dreg, 0);
12802                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, call_bb);
12803
12804                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, next_bb);
12805                                         MONO_START_BB (cfg, call_bb);
12806                                 }
12807
12808                                 /* AOT code is only used in the root domain */
12809                                 EMIT_NEW_PCONST (cfg, args [0], cfg->compile_aot ? NULL : cfg->domain);
12810                                 ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
12811                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12812
12813                                 if (next_bb)
12814                                         MONO_START_BB (cfg, next_bb);
12815
12816
12817                                 ip += 2;
12818                                 break;
12819                         }
12820                         case CEE_MONO_JIT_DETACH: {
12821                                 MonoInst *args [16];
12822
12823                                 /* Restore the original domain */
12824                                 dreg = alloc_ireg (cfg);
12825                                 EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->orig_domain_var->dreg);
12826                                 mono_emit_jit_icall (cfg, mono_jit_set_domain, args);
12827                                 ip += 2;
12828                                 break;
12829                         }
12830                         case CEE_MONO_CALLI_EXTRA_ARG: {
12831                                 MonoInst *addr;
12832                                 MonoMethodSignature *fsig;
12833                                 MonoInst *arg;
12834
12835                                 /*
12836                                  * This is the same as CEE_CALLI, but passes an additional argument
12837                                  * to the called method in llvmonly mode.
12838                                  * This is only used by delegate invoke wrappers to call the
12839                                  * actual delegate method.
12840                                  */
12841                                 g_assert (method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE);
12842
12843                                 CHECK_OPSIZE (6);
12844                                 token = read32 (ip + 2);
12845
12846                                 ins = NULL;
12847
12848                                 cmethod = NULL;
12849                                 CHECK_STACK (1);
12850                                 --sp;
12851                                 addr = *sp;
12852                                 fsig = mini_get_signature (method, token, generic_context, &cfg->error);
12853                                 CHECK_CFG_ERROR;
12854
12855                                 if (cfg->llvm_only)
12856                                         cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, fsig);
12857
12858                                 n = fsig->param_count + fsig->hasthis + 1;
12859
12860                                 CHECK_STACK (n);
12861
12862                                 sp -= n;
12863                                 arg = sp [n - 1];
12864
12865                                 if (cfg->llvm_only) {
12866                                         /*
12867                                          * The lowest bit of 'arg' determines whenever the callee uses the gsharedvt
12868                                          * cconv. This is set by mono_init_delegate ().
12869                                          */
12870                                         if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig)) {
12871                                                 MonoInst *callee = addr;
12872                                                 MonoInst *call, *localloc_ins;
12873                                                 MonoBasicBlock *is_gsharedvt_bb, *end_bb;
12874                                                 int low_bit_reg = alloc_preg (cfg);
12875
12876                                                 NEW_BBLOCK (cfg, is_gsharedvt_bb);
12877                                                 NEW_BBLOCK (cfg, end_bb);
12878
12879                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, low_bit_reg, arg->dreg, 1);
12880                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_bit_reg, 0);
12881                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_gsharedvt_bb);
12882
12883                                                 /* Normal case: callee uses a normal cconv, have to add an out wrapper */
12884                                                 addr = emit_get_rgctx_sig (cfg, context_used,
12885                                                                                                    fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
12886                                                 /*
12887                                                  * ADDR points to a gsharedvt-out wrapper, have to pass <callee, arg> as an extra arg.
12888                                                  */
12889                                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
12890                                                 ins->dreg = alloc_preg (cfg);
12891                                                 ins->inst_imm = 2 * SIZEOF_VOID_P;
12892                                                 MONO_ADD_INS (cfg->cbb, ins);
12893                                                 localloc_ins = ins;
12894                                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12895                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, 0, callee->dreg);
12896                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, SIZEOF_VOID_P, arg->dreg);
12897
12898                                                 call = emit_extra_arg_calli (cfg, fsig, sp, localloc_ins->dreg, addr);
12899                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12900
12901                                                 /* Gsharedvt case: callee uses a gsharedvt cconv, no conversion is needed */
12902                                                 MONO_START_BB (cfg, is_gsharedvt_bb);
12903                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PXOR_IMM, arg->dreg, arg->dreg, 1);
12904                                                 ins = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
12905                                                 ins->dreg = call->dreg;
12906
12907                                                 MONO_START_BB (cfg, end_bb);
12908                                         } else {
12909                                                 /* Caller uses a normal calling conv */
12910
12911                                                 MonoInst *callee = addr;
12912                                                 MonoInst *call, *localloc_ins;
12913                                                 MonoBasicBlock *is_gsharedvt_bb, *end_bb;
12914                                                 int low_bit_reg = alloc_preg (cfg);
12915
12916                                                 NEW_BBLOCK (cfg, is_gsharedvt_bb);
12917                                                 NEW_BBLOCK (cfg, end_bb);
12918
12919                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, low_bit_reg, arg->dreg, 1);
12920                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_bit_reg, 0);
12921                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_gsharedvt_bb);
12922
12923                                                 /* Normal case: callee uses a normal cconv, no conversion is needed */
12924                                                 call = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
12925                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12926                                                 /* Gsharedvt case: callee uses a gsharedvt cconv, have to add an in wrapper */
12927                                                 MONO_START_BB (cfg, is_gsharedvt_bb);
12928                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PXOR_IMM, arg->dreg, arg->dreg, 1);
12929                                                 NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER, fsig);
12930                                                 MONO_ADD_INS (cfg->cbb, addr);
12931                                                 /*
12932                                                  * ADDR points to a gsharedvt-in wrapper, have to pass <callee, arg> as an extra arg.
12933                                                  */
12934                                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
12935                                                 ins->dreg = alloc_preg (cfg);
12936                                                 ins->inst_imm = 2 * SIZEOF_VOID_P;
12937                                                 MONO_ADD_INS (cfg->cbb, ins);
12938                                                 localloc_ins = ins;
12939                                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12940                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, 0, callee->dreg);
12941                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, SIZEOF_VOID_P, arg->dreg);
12942
12943                                                 ins = emit_extra_arg_calli (cfg, fsig, sp, localloc_ins->dreg, addr);
12944                                                 ins->dreg = call->dreg;
12945                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12946
12947                                                 MONO_START_BB (cfg, end_bb);
12948                                         }
12949                                 } else {
12950                                         /* Same as CEE_CALLI */
12951                                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
12952                                                 /*
12953                                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
12954                                                  */
12955                                                 MonoInst *callee = addr;
12956
12957                                                 addr = emit_get_rgctx_sig (cfg, context_used,
12958                                                                                                    fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
12959                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
12960                                         } else {
12961                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
12962                                         }
12963                                 }
12964
12965                                 if (!MONO_TYPE_IS_VOID (fsig->ret))
12966                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
12967
12968                                 CHECK_CFG_EXCEPTION;
12969
12970                                 ip += 6;
12971                                 ins_flag = 0;
12972                                 constrained_class = NULL;
12973                                 break;
12974                         }
12975                         case CEE_MONO_LDDOMAIN:
12976                                 CHECK_STACK_OVF (1);
12977                                 EMIT_NEW_PCONST (cfg, ins, cfg->compile_aot ? NULL : cfg->domain);
12978                                 ip += 2;
12979                                 *sp++ = ins;
12980                                 break;
12981                         default:
12982                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
12983                                 break;
12984                         }
12985                         break;
12986                 }
12987
12988                 case CEE_PREFIX1: {
12989                         CHECK_OPSIZE (2);
12990                         switch (ip [1]) {
12991                         case CEE_ARGLIST: {
12992                                 /* somewhat similar to LDTOKEN */
12993                                 MonoInst *addr, *vtvar;
12994                                 CHECK_STACK_OVF (1);
12995                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
12996
12997                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12998                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
12999
13000                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
13001                                 ins->type = STACK_VTYPE;
13002                                 ins->klass = mono_defaults.argumenthandle_class;
13003                                 *sp++ = ins;
13004                                 ip += 2;
13005                                 break;
13006                         }
13007                         case CEE_CEQ:
13008                         case CEE_CGT:
13009                         case CEE_CGT_UN:
13010                         case CEE_CLT:
13011                         case CEE_CLT_UN: {
13012                                 MonoInst *cmp, *arg1, *arg2;
13013
13014                                 CHECK_STACK (2);
13015                                 sp -= 2;
13016                                 arg1 = sp [0];
13017                                 arg2 = sp [1];
13018
13019                                 /*
13020                                  * The following transforms:
13021                                  *    CEE_CEQ    into OP_CEQ
13022                                  *    CEE_CGT    into OP_CGT
13023                                  *    CEE_CGT_UN into OP_CGT_UN
13024                                  *    CEE_CLT    into OP_CLT
13025                                  *    CEE_CLT_UN into OP_CLT_UN
13026                                  */
13027                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
13028
13029                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
13030                                 cmp->sreg1 = arg1->dreg;
13031                                 cmp->sreg2 = arg2->dreg;
13032                                 type_from_op (cfg, cmp, arg1, arg2);
13033                                 CHECK_TYPE (cmp);
13034                                 add_widen_op (cfg, cmp, &arg1, &arg2);
13035                                 if ((arg1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((arg1->type == STACK_PTR) || (arg1->type == STACK_OBJ) || (arg1->type == STACK_MP))))
13036                                         cmp->opcode = OP_LCOMPARE;
13037                                 else if (arg1->type == STACK_R4)
13038                                         cmp->opcode = OP_RCOMPARE;
13039                                 else if (arg1->type == STACK_R8)
13040                                         cmp->opcode = OP_FCOMPARE;
13041                                 else
13042                                         cmp->opcode = OP_ICOMPARE;
13043                                 MONO_ADD_INS (cfg->cbb, cmp);
13044                                 ins->type = STACK_I4;
13045                                 ins->dreg = alloc_dreg (cfg, (MonoStackType)ins->type);
13046                                 type_from_op (cfg, ins, arg1, arg2);
13047
13048                                 if (cmp->opcode == OP_FCOMPARE || cmp->opcode == OP_RCOMPARE) {
13049                                         /*
13050                                          * The backends expect the fceq opcodes to do the
13051                                          * comparison too.
13052                                          */
13053                                         ins->sreg1 = cmp->sreg1;
13054                                         ins->sreg2 = cmp->sreg2;
13055                                         NULLIFY_INS (cmp);
13056                                 }
13057                                 MONO_ADD_INS (cfg->cbb, ins);
13058                                 *sp++ = ins;
13059                                 ip += 2;
13060                                 break;
13061                         }
13062                         case CEE_LDFTN: {
13063                                 MonoInst *argconst;
13064                                 MonoMethod *cil_method;
13065
13066                                 CHECK_STACK_OVF (1);
13067                                 CHECK_OPSIZE (6);
13068                                 n = read32 (ip + 2);
13069                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
13070                                 CHECK_CFG_ERROR;
13071
13072                                 mono_class_init (cmethod->klass);
13073
13074                                 mono_save_token_info (cfg, image, n, cmethod);
13075
13076                                 context_used = mini_method_check_context_used (cfg, cmethod);
13077
13078                                 cil_method = cmethod;
13079                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
13080                                         emit_method_access_failure (cfg, method, cil_method);
13081
13082                                 if (mono_security_core_clr_enabled ())
13083                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
13084
13085                                 /* 
13086                                  * Optimize the common case of ldftn+delegate creation
13087                                  */
13088                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
13089                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
13090                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
13091                                                 MonoInst *target_ins, *handle_ins;
13092                                                 MonoMethod *invoke;
13093                                                 int invoke_context_used;
13094
13095                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
13096                                                 if (!invoke || !mono_method_signature (invoke))
13097                                                         LOAD_ERROR;
13098
13099                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
13100
13101                                                 target_ins = sp [-1];
13102
13103                                                 if (mono_security_core_clr_enabled ())
13104                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
13105
13106                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
13107                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
13108                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
13109                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
13110                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
13111                                                         }
13112                                                 }
13113
13114                                                 /* FIXME: SGEN support */
13115                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
13116                                                         ip += 6;
13117                                                         if (cfg->verbose_level > 3)
13118                                                                 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));
13119                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, FALSE))) {
13120                                                                 sp --;
13121                                                                 *sp = handle_ins;
13122                                                                 CHECK_CFG_EXCEPTION;
13123                                                                 ip += 5;
13124                                                                 sp ++;
13125                                                                 break;
13126                                                         }
13127                                                         ip -= 6;
13128                                                 }
13129                                         }
13130                                 }
13131
13132                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
13133                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
13134                                 *sp++ = ins;
13135                                 
13136                                 ip += 6;
13137                                 inline_costs += 10 * num_calls++;
13138                                 break;
13139                         }
13140                         case CEE_LDVIRTFTN: {
13141                                 MonoInst *args [2];
13142
13143                                 CHECK_STACK (1);
13144                                 CHECK_OPSIZE (6);
13145                                 n = read32 (ip + 2);
13146                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
13147                                 CHECK_CFG_ERROR;
13148
13149                                 mono_class_init (cmethod->klass);
13150  
13151                                 context_used = mini_method_check_context_used (cfg, cmethod);
13152
13153                                 if (mono_security_core_clr_enabled ())
13154                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
13155
13156                                 /*
13157                                  * Optimize the common case of ldvirtftn+delegate creation
13158                                  */
13159                                 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)) {
13160                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
13161                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
13162                                                 MonoInst *target_ins, *handle_ins;
13163                                                 MonoMethod *invoke;
13164                                                 int invoke_context_used;
13165                                                 gboolean is_virtual = cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL;
13166
13167                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
13168                                                 if (!invoke || !mono_method_signature (invoke))
13169                                                         LOAD_ERROR;
13170
13171                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
13172
13173                                                 target_ins = sp [-1];
13174
13175                                                 if (mono_security_core_clr_enabled ())
13176                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
13177
13178                                                 /* FIXME: SGEN support */
13179                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
13180                                                         ip += 6;
13181                                                         if (cfg->verbose_level > 3)
13182                                                                 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));
13183                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, is_virtual))) {
13184                                                                 sp -= 2;
13185                                                                 *sp = handle_ins;
13186                                                                 CHECK_CFG_EXCEPTION;
13187                                                                 ip += 5;
13188                                                                 sp ++;
13189                                                                 break;
13190                                                         }
13191                                                         ip -= 6;
13192                                                 }
13193                                         }
13194                                 }
13195
13196                                 --sp;
13197                                 args [0] = *sp;
13198
13199                                 args [1] = emit_get_rgctx_method (cfg, context_used,
13200                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
13201
13202                                 if (context_used)
13203                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
13204                                 else
13205                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
13206
13207                                 ip += 6;
13208                                 inline_costs += 10 * num_calls++;
13209                                 break;
13210                         }
13211                         case CEE_LDARG:
13212                                 CHECK_STACK_OVF (1);
13213                                 CHECK_OPSIZE (4);
13214                                 n = read16 (ip + 2);
13215                                 CHECK_ARG (n);
13216                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
13217                                 *sp++ = ins;
13218                                 ip += 4;
13219                                 break;
13220                         case CEE_LDARGA:
13221                                 CHECK_STACK_OVF (1);
13222                                 CHECK_OPSIZE (4);
13223                                 n = read16 (ip + 2);
13224                                 CHECK_ARG (n);
13225                                 NEW_ARGLOADA (cfg, ins, n);
13226                                 MONO_ADD_INS (cfg->cbb, ins);
13227                                 *sp++ = ins;
13228                                 ip += 4;
13229                                 break;
13230                         case CEE_STARG:
13231                                 CHECK_STACK (1);
13232                                 --sp;
13233                                 CHECK_OPSIZE (4);
13234                                 n = read16 (ip + 2);
13235                                 CHECK_ARG (n);
13236                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
13237                                         UNVERIFIED;
13238                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
13239                                 ip += 4;
13240                                 break;
13241                         case CEE_LDLOC:
13242                                 CHECK_STACK_OVF (1);
13243                                 CHECK_OPSIZE (4);
13244                                 n = read16 (ip + 2);
13245                                 CHECK_LOCAL (n);
13246                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
13247                                 *sp++ = ins;
13248                                 ip += 4;
13249                                 break;
13250                         case CEE_LDLOCA: {
13251                                 unsigned char *tmp_ip;
13252                                 CHECK_STACK_OVF (1);
13253                                 CHECK_OPSIZE (4);
13254                                 n = read16 (ip + 2);
13255                                 CHECK_LOCAL (n);
13256
13257                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
13258                                         ip = tmp_ip;
13259                                         inline_costs += 1;
13260                                         break;
13261                                 }                       
13262                                 
13263                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
13264                                 *sp++ = ins;
13265                                 ip += 4;
13266                                 break;
13267                         }
13268                         case CEE_STLOC:
13269                                 CHECK_STACK (1);
13270                                 --sp;
13271                                 CHECK_OPSIZE (4);
13272                                 n = read16 (ip + 2);
13273                                 CHECK_LOCAL (n);
13274                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
13275                                         UNVERIFIED;
13276                                 emit_stloc_ir (cfg, sp, header, n);
13277                                 ip += 4;
13278                                 inline_costs += 1;
13279                                 break;
13280                         case CEE_LOCALLOC:
13281                                 CHECK_STACK (1);
13282                                 --sp;
13283                                 if (sp != stack_start) 
13284                                         UNVERIFIED;
13285                                 if (cfg->method != method) 
13286                                         /* 
13287                                          * Inlining this into a loop in a parent could lead to 
13288                                          * stack overflows which is different behavior than the
13289                                          * non-inlined case, thus disable inlining in this case.
13290                                          */
13291                                         INLINE_FAILURE("localloc");
13292
13293                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
13294                                 ins->dreg = alloc_preg (cfg);
13295                                 ins->sreg1 = sp [0]->dreg;
13296                                 ins->type = STACK_PTR;
13297                                 MONO_ADD_INS (cfg->cbb, ins);
13298
13299                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
13300                                 if (init_locals)
13301                                         ins->flags |= MONO_INST_INIT;
13302
13303                                 *sp++ = ins;
13304                                 ip += 2;
13305                                 break;
13306                         case CEE_ENDFILTER: {
13307                                 MonoExceptionClause *clause, *nearest;
13308                                 int cc;
13309
13310                                 CHECK_STACK (1);
13311                                 --sp;
13312                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
13313                                         UNVERIFIED;
13314                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
13315                                 ins->sreg1 = (*sp)->dreg;
13316                                 MONO_ADD_INS (cfg->cbb, ins);
13317                                 start_new_bblock = 1;
13318                                 ip += 2;
13319
13320                                 nearest = NULL;
13321                                 for (cc = 0; cc < header->num_clauses; ++cc) {
13322                                         clause = &header->clauses [cc];
13323                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
13324                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
13325                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset)))
13326                                                 nearest = clause;
13327                                 }
13328                                 g_assert (nearest);
13329                                 if ((ip - header->code) != nearest->handler_offset)
13330                                         UNVERIFIED;
13331
13332                                 break;
13333                         }
13334                         case CEE_UNALIGNED_:
13335                                 ins_flag |= MONO_INST_UNALIGNED;
13336                                 /* FIXME: record alignment? we can assume 1 for now */
13337                                 CHECK_OPSIZE (3);
13338                                 ip += 3;
13339                                 break;
13340                         case CEE_VOLATILE_:
13341                                 ins_flag |= MONO_INST_VOLATILE;
13342                                 ip += 2;
13343                                 break;
13344                         case CEE_TAIL_:
13345                                 ins_flag   |= MONO_INST_TAILCALL;
13346                                 cfg->flags |= MONO_CFG_HAS_TAIL;
13347                                 /* Can't inline tail calls at this time */
13348                                 inline_costs += 100000;
13349                                 ip += 2;
13350                                 break;
13351                         case CEE_INITOBJ:
13352                                 CHECK_STACK (1);
13353                                 --sp;
13354                                 CHECK_OPSIZE (6);
13355                                 token = read32 (ip + 2);
13356                                 klass = mini_get_class (method, token, generic_context);
13357                                 CHECK_TYPELOAD (klass);
13358                                 if (generic_class_is_reference_type (cfg, klass))
13359                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
13360                                 else
13361                                         mini_emit_initobj (cfg, *sp, NULL, klass);
13362                                 ip += 6;
13363                                 inline_costs += 1;
13364                                 break;
13365                         case CEE_CONSTRAINED_:
13366                                 CHECK_OPSIZE (6);
13367                                 token = read32 (ip + 2);
13368                                 constrained_class = mini_get_class (method, token, generic_context);
13369                                 CHECK_TYPELOAD (constrained_class);
13370                                 ip += 6;
13371                                 break;
13372                         case CEE_CPBLK:
13373                         case CEE_INITBLK: {
13374                                 MonoInst *iargs [3];
13375                                 CHECK_STACK (3);
13376                                 sp -= 3;
13377
13378                                 /* Skip optimized paths for volatile operations. */
13379                                 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)) {
13380                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
13381                                 } 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)) {
13382                                         /* emit_memset only works when val == 0 */
13383                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
13384                                 } else {
13385                                         MonoInst *call;
13386                                         iargs [0] = sp [0];
13387                                         iargs [1] = sp [1];
13388                                         iargs [2] = sp [2];
13389                                         if (ip [1] == CEE_CPBLK) {
13390                                                 /*
13391                                                  * FIXME: It's unclear whether we should be emitting both the acquire
13392                                                  * and release barriers for cpblk. It is technically both a load and
13393                                                  * store operation, so it seems like that's the sensible thing to do.
13394                                                  *
13395                                                  * FIXME: We emit full barriers on both sides of the operation for
13396                                                  * simplicity. We should have a separate atomic memcpy method instead.
13397                                                  */
13398                                                 MonoMethod *memcpy_method = get_memcpy_method ();
13399
13400                                                 if (ins_flag & MONO_INST_VOLATILE)
13401                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
13402
13403                                                 call = mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
13404                                                 call->flags |= ins_flag;
13405
13406                                                 if (ins_flag & MONO_INST_VOLATILE)
13407                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
13408                                         } else {
13409                                                 MonoMethod *memset_method = get_memset_method ();
13410                                                 if (ins_flag & MONO_INST_VOLATILE) {
13411                                                         /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
13412                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
13413                                                 }
13414                                                 call = mono_emit_method_call (cfg, memset_method, iargs, NULL);
13415                                                 call->flags |= ins_flag;
13416                                         }
13417                                 }
13418                                 ip += 2;
13419                                 ins_flag = 0;
13420                                 inline_costs += 1;
13421                                 break;
13422                         }
13423                         case CEE_NO_:
13424                                 CHECK_OPSIZE (3);
13425                                 if (ip [2] & 0x1)
13426                                         ins_flag |= MONO_INST_NOTYPECHECK;
13427                                 if (ip [2] & 0x2)
13428                                         ins_flag |= MONO_INST_NORANGECHECK;
13429                                 /* we ignore the no-nullcheck for now since we
13430                                  * really do it explicitly only when doing callvirt->call
13431                                  */
13432                                 ip += 3;
13433                                 break;
13434                         case CEE_RETHROW: {
13435                                 MonoInst *load;
13436                                 int handler_offset = -1;
13437
13438                                 for (i = 0; i < header->num_clauses; ++i) {
13439                                         MonoExceptionClause *clause = &header->clauses [i];
13440                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
13441                                                 handler_offset = clause->handler_offset;
13442                                                 break;
13443                                         }
13444                                 }
13445
13446                                 cfg->cbb->flags |= BB_EXCEPTION_UNSAFE;
13447
13448                                 if (handler_offset == -1)
13449                                         UNVERIFIED;
13450
13451                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
13452                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
13453                                 ins->sreg1 = load->dreg;
13454                                 MONO_ADD_INS (cfg->cbb, ins);
13455
13456                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
13457                                 MONO_ADD_INS (cfg->cbb, ins);
13458
13459                                 sp = stack_start;
13460                                 link_bblock (cfg, cfg->cbb, end_bblock);
13461                                 start_new_bblock = 1;
13462                                 ip += 2;
13463                                 break;
13464                         }
13465                         case CEE_SIZEOF: {
13466                                 guint32 val;
13467                                 int ialign;
13468
13469                                 CHECK_STACK_OVF (1);
13470                                 CHECK_OPSIZE (6);
13471                                 token = read32 (ip + 2);
13472                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !image_is_dynamic (method->klass->image) && !generic_context) {
13473                                         MonoType *type = mono_type_create_from_typespec_checked (image, token, &cfg->error);
13474                                         CHECK_CFG_ERROR;
13475
13476                                         val = mono_type_size (type, &ialign);
13477                                 } else {
13478                                         MonoClass *klass = mini_get_class (method, token, generic_context);
13479                                         CHECK_TYPELOAD (klass);
13480
13481                                         val = mono_type_size (&klass->byval_arg, &ialign);
13482
13483                                         if (mini_is_gsharedvt_klass (klass))
13484                                                 GSHAREDVT_FAILURE (*ip);
13485                                 }
13486                                 EMIT_NEW_ICONST (cfg, ins, val);
13487                                 *sp++= ins;
13488                                 ip += 6;
13489                                 break;
13490                         }
13491                         case CEE_REFANYTYPE: {
13492                                 MonoInst *src_var, *src;
13493
13494                                 GSHAREDVT_FAILURE (*ip);
13495
13496                                 CHECK_STACK (1);
13497                                 --sp;
13498
13499                                 // FIXME:
13500                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
13501                                 if (!src_var)
13502                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
13503                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
13504                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type));
13505                                 *sp++ = ins;
13506                                 ip += 2;
13507                                 break;
13508                         }
13509                         case CEE_READONLY_:
13510                                 readonly = TRUE;
13511                                 ip += 2;
13512                                 break;
13513
13514                         case CEE_UNUSED56:
13515                         case CEE_UNUSED57:
13516                         case CEE_UNUSED70:
13517                         case CEE_UNUSED:
13518                         case CEE_UNUSED99:
13519                                 UNVERIFIED;
13520                                 
13521                         default:
13522                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
13523                                 UNVERIFIED;
13524                         }
13525                         break;
13526                 }
13527                 case CEE_UNUSED58:
13528                 case CEE_UNUSED1:
13529                         UNVERIFIED;
13530
13531                 default:
13532                         g_warning ("opcode 0x%02x not handled", *ip);
13533                         UNVERIFIED;
13534                 }
13535         }
13536         if (start_new_bblock != 1)
13537                 UNVERIFIED;
13538
13539         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
13540         if (cfg->cbb->next_bb) {
13541                 /* This could already be set because of inlining, #693905 */
13542                 MonoBasicBlock *bb = cfg->cbb;
13543
13544                 while (bb->next_bb)
13545                         bb = bb->next_bb;
13546                 bb->next_bb = end_bblock;
13547         } else {
13548                 cfg->cbb->next_bb = end_bblock;
13549         }
13550
13551         if (cfg->method == method && cfg->domainvar) {
13552                 MonoInst *store;
13553                 MonoInst *get_domain;
13554
13555                 cfg->cbb = init_localsbb;
13556
13557                 if ((get_domain = mono_get_domain_intrinsic (cfg))) {
13558                         MONO_ADD_INS (cfg->cbb, get_domain);
13559                 } else {
13560                         get_domain = mono_emit_jit_icall (cfg, mono_domain_get, NULL);
13561                 }
13562                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
13563                 MONO_ADD_INS (cfg->cbb, store);
13564         }
13565
13566 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
13567         if (cfg->compile_aot)
13568                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
13569                 mono_get_got_var (cfg);
13570 #endif
13571
13572         if (cfg->method == method && cfg->got_var)
13573                 mono_emit_load_got_addr (cfg);
13574
13575         if (init_localsbb) {
13576                 cfg->cbb = init_localsbb;
13577                 cfg->ip = NULL;
13578                 for (i = 0; i < header->num_locals; ++i) {
13579                         emit_init_local (cfg, i, header->locals [i], init_locals);
13580                 }
13581         }
13582
13583         if (cfg->init_ref_vars && cfg->method == method) {
13584                 /* Emit initialization for ref vars */
13585                 // FIXME: Avoid duplication initialization for IL locals.
13586                 for (i = 0; i < cfg->num_varinfo; ++i) {
13587                         MonoInst *ins = cfg->varinfo [i];
13588
13589                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
13590                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
13591                 }
13592         }
13593
13594         if (cfg->lmf_var && cfg->method == method && !cfg->llvm_only) {
13595                 cfg->cbb = init_localsbb;
13596                 emit_push_lmf (cfg);
13597         }
13598
13599         cfg->cbb = init_localsbb;
13600         emit_instrumentation_call (cfg, mono_profiler_method_enter);
13601
13602         if (seq_points) {
13603                 MonoBasicBlock *bb;
13604
13605                 /*
13606                  * Make seq points at backward branch targets interruptable.
13607                  */
13608                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
13609                         if (bb->code && bb->in_count > 1 && bb->code->opcode == OP_SEQ_POINT)
13610                                 bb->code->flags |= MONO_INST_SINGLE_STEP_LOC;
13611         }
13612
13613         /* Add a sequence point for method entry/exit events */
13614         if (seq_points && cfg->gen_sdb_seq_points) {
13615                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
13616                 MONO_ADD_INS (init_localsbb, ins);
13617                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
13618                 MONO_ADD_INS (cfg->bb_exit, ins);
13619         }
13620
13621         /*
13622          * Add seq points for IL offsets which have line number info, but wasn't generated a seq point during JITting because
13623          * the code they refer to was dead (#11880).
13624          */
13625         if (sym_seq_points) {
13626                 for (i = 0; i < header->code_size; ++i) {
13627                         if (mono_bitset_test_fast (seq_point_locs, i) && !mono_bitset_test_fast (seq_point_set_locs, i)) {
13628                                 MonoInst *ins;
13629
13630                                 NEW_SEQ_POINT (cfg, ins, i, FALSE);
13631                                 mono_add_seq_point (cfg, NULL, ins, SEQ_POINT_NATIVE_OFFSET_DEAD_CODE);
13632                         }
13633                 }
13634         }
13635
13636         cfg->ip = NULL;
13637
13638         if (cfg->method == method) {
13639                 MonoBasicBlock *bb;
13640                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13641                         bb->region = mono_find_block_region (cfg, bb->real_offset);
13642                         if (cfg->spvars)
13643                                 mono_create_spvar_for_region (cfg, bb->region);
13644                         if (cfg->verbose_level > 2)
13645                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
13646                 }
13647         } else {
13648                 MonoBasicBlock *bb;
13649                 /* get_most_deep_clause () in mini-llvm.c depends on this for inlined bblocks */
13650                 for (bb = start_bblock; bb != end_bblock; bb  = bb->next_bb) {
13651                         bb->real_offset = inline_offset;
13652                 }
13653         }
13654
13655         if (inline_costs < 0) {
13656                 char *mname;
13657
13658                 /* Method is too large */
13659                 mname = mono_method_full_name (method, TRUE);
13660                 mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Method %s is too complex.", mname));
13661                 g_free (mname);
13662         }
13663
13664         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
13665                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
13666
13667         goto cleanup;
13668
13669 mono_error_exit:
13670         g_assert (!mono_error_ok (&cfg->error));
13671         goto cleanup;
13672  
13673  exception_exit:
13674         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
13675         goto cleanup;
13676
13677  unverified:
13678         set_exception_type_from_invalid_il (cfg, method, ip);
13679         goto cleanup;
13680
13681  cleanup:
13682         g_slist_free (class_inits);
13683         mono_basic_block_free (original_bb);
13684         cfg->dont_inline = g_list_remove (cfg->dont_inline, method);
13685         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
13686         if (cfg->exception_type)
13687                 return -1;
13688         else
13689                 return inline_costs;
13690 }
13691
13692 static int
13693 store_membase_reg_to_store_membase_imm (int opcode)
13694 {
13695         switch (opcode) {
13696         case OP_STORE_MEMBASE_REG:
13697                 return OP_STORE_MEMBASE_IMM;
13698         case OP_STOREI1_MEMBASE_REG:
13699                 return OP_STOREI1_MEMBASE_IMM;
13700         case OP_STOREI2_MEMBASE_REG:
13701                 return OP_STOREI2_MEMBASE_IMM;
13702         case OP_STOREI4_MEMBASE_REG:
13703                 return OP_STOREI4_MEMBASE_IMM;
13704         case OP_STOREI8_MEMBASE_REG:
13705                 return OP_STOREI8_MEMBASE_IMM;
13706         default:
13707                 g_assert_not_reached ();
13708         }
13709
13710         return -1;
13711 }               
13712
13713 int
13714 mono_op_to_op_imm (int opcode)
13715 {
13716         switch (opcode) {
13717         case OP_IADD:
13718                 return OP_IADD_IMM;
13719         case OP_ISUB:
13720                 return OP_ISUB_IMM;
13721         case OP_IDIV:
13722                 return OP_IDIV_IMM;
13723         case OP_IDIV_UN:
13724                 return OP_IDIV_UN_IMM;
13725         case OP_IREM:
13726                 return OP_IREM_IMM;
13727         case OP_IREM_UN:
13728                 return OP_IREM_UN_IMM;
13729         case OP_IMUL:
13730                 return OP_IMUL_IMM;
13731         case OP_IAND:
13732                 return OP_IAND_IMM;
13733         case OP_IOR:
13734                 return OP_IOR_IMM;
13735         case OP_IXOR:
13736                 return OP_IXOR_IMM;
13737         case OP_ISHL:
13738                 return OP_ISHL_IMM;
13739         case OP_ISHR:
13740                 return OP_ISHR_IMM;
13741         case OP_ISHR_UN:
13742                 return OP_ISHR_UN_IMM;
13743
13744         case OP_LADD:
13745                 return OP_LADD_IMM;
13746         case OP_LSUB:
13747                 return OP_LSUB_IMM;
13748         case OP_LAND:
13749                 return OP_LAND_IMM;
13750         case OP_LOR:
13751                 return OP_LOR_IMM;
13752         case OP_LXOR:
13753                 return OP_LXOR_IMM;
13754         case OP_LSHL:
13755                 return OP_LSHL_IMM;
13756         case OP_LSHR:
13757                 return OP_LSHR_IMM;
13758         case OP_LSHR_UN:
13759                 return OP_LSHR_UN_IMM;
13760 #if SIZEOF_REGISTER == 8
13761         case OP_LREM:
13762                 return OP_LREM_IMM;
13763 #endif
13764
13765         case OP_COMPARE:
13766                 return OP_COMPARE_IMM;
13767         case OP_ICOMPARE:
13768                 return OP_ICOMPARE_IMM;
13769         case OP_LCOMPARE:
13770                 return OP_LCOMPARE_IMM;
13771
13772         case OP_STORE_MEMBASE_REG:
13773                 return OP_STORE_MEMBASE_IMM;
13774         case OP_STOREI1_MEMBASE_REG:
13775                 return OP_STOREI1_MEMBASE_IMM;
13776         case OP_STOREI2_MEMBASE_REG:
13777                 return OP_STOREI2_MEMBASE_IMM;
13778         case OP_STOREI4_MEMBASE_REG:
13779                 return OP_STOREI4_MEMBASE_IMM;
13780
13781 #if defined(TARGET_X86) || defined (TARGET_AMD64)
13782         case OP_X86_PUSH:
13783                 return OP_X86_PUSH_IMM;
13784         case OP_X86_COMPARE_MEMBASE_REG:
13785                 return OP_X86_COMPARE_MEMBASE_IMM;
13786 #endif
13787 #if defined(TARGET_AMD64)
13788         case OP_AMD64_ICOMPARE_MEMBASE_REG:
13789                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13790 #endif
13791         case OP_VOIDCALL_REG:
13792                 return OP_VOIDCALL;
13793         case OP_CALL_REG:
13794                 return OP_CALL;
13795         case OP_LCALL_REG:
13796                 return OP_LCALL;
13797         case OP_FCALL_REG:
13798                 return OP_FCALL;
13799         case OP_LOCALLOC:
13800                 return OP_LOCALLOC_IMM;
13801         }
13802
13803         return -1;
13804 }
13805
13806 static int
13807 ldind_to_load_membase (int opcode)
13808 {
13809         switch (opcode) {
13810         case CEE_LDIND_I1:
13811                 return OP_LOADI1_MEMBASE;
13812         case CEE_LDIND_U1:
13813                 return OP_LOADU1_MEMBASE;
13814         case CEE_LDIND_I2:
13815                 return OP_LOADI2_MEMBASE;
13816         case CEE_LDIND_U2:
13817                 return OP_LOADU2_MEMBASE;
13818         case CEE_LDIND_I4:
13819                 return OP_LOADI4_MEMBASE;
13820         case CEE_LDIND_U4:
13821                 return OP_LOADU4_MEMBASE;
13822         case CEE_LDIND_I:
13823                 return OP_LOAD_MEMBASE;
13824         case CEE_LDIND_REF:
13825                 return OP_LOAD_MEMBASE;
13826         case CEE_LDIND_I8:
13827                 return OP_LOADI8_MEMBASE;
13828         case CEE_LDIND_R4:
13829                 return OP_LOADR4_MEMBASE;
13830         case CEE_LDIND_R8:
13831                 return OP_LOADR8_MEMBASE;
13832         default:
13833                 g_assert_not_reached ();
13834         }
13835
13836         return -1;
13837 }
13838
13839 static int
13840 stind_to_store_membase (int opcode)
13841 {
13842         switch (opcode) {
13843         case CEE_STIND_I1:
13844                 return OP_STOREI1_MEMBASE_REG;
13845         case CEE_STIND_I2:
13846                 return OP_STOREI2_MEMBASE_REG;
13847         case CEE_STIND_I4:
13848                 return OP_STOREI4_MEMBASE_REG;
13849         case CEE_STIND_I:
13850         case CEE_STIND_REF:
13851                 return OP_STORE_MEMBASE_REG;
13852         case CEE_STIND_I8:
13853                 return OP_STOREI8_MEMBASE_REG;
13854         case CEE_STIND_R4:
13855                 return OP_STORER4_MEMBASE_REG;
13856         case CEE_STIND_R8:
13857                 return OP_STORER8_MEMBASE_REG;
13858         default:
13859                 g_assert_not_reached ();
13860         }
13861
13862         return -1;
13863 }
13864
13865 int
13866 mono_load_membase_to_load_mem (int opcode)
13867 {
13868         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
13869 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13870         switch (opcode) {
13871         case OP_LOAD_MEMBASE:
13872                 return OP_LOAD_MEM;
13873         case OP_LOADU1_MEMBASE:
13874                 return OP_LOADU1_MEM;
13875         case OP_LOADU2_MEMBASE:
13876                 return OP_LOADU2_MEM;
13877         case OP_LOADI4_MEMBASE:
13878                 return OP_LOADI4_MEM;
13879         case OP_LOADU4_MEMBASE:
13880                 return OP_LOADU4_MEM;
13881 #if SIZEOF_REGISTER == 8
13882         case OP_LOADI8_MEMBASE:
13883                 return OP_LOADI8_MEM;
13884 #endif
13885         }
13886 #endif
13887
13888         return -1;
13889 }
13890
13891 static inline int
13892 op_to_op_dest_membase (int store_opcode, int opcode)
13893 {
13894 #if defined(TARGET_X86)
13895         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
13896                 return -1;
13897
13898         switch (opcode) {
13899         case OP_IADD:
13900                 return OP_X86_ADD_MEMBASE_REG;
13901         case OP_ISUB:
13902                 return OP_X86_SUB_MEMBASE_REG;
13903         case OP_IAND:
13904                 return OP_X86_AND_MEMBASE_REG;
13905         case OP_IOR:
13906                 return OP_X86_OR_MEMBASE_REG;
13907         case OP_IXOR:
13908                 return OP_X86_XOR_MEMBASE_REG;
13909         case OP_ADD_IMM:
13910         case OP_IADD_IMM:
13911                 return OP_X86_ADD_MEMBASE_IMM;
13912         case OP_SUB_IMM:
13913         case OP_ISUB_IMM:
13914                 return OP_X86_SUB_MEMBASE_IMM;
13915         case OP_AND_IMM:
13916         case OP_IAND_IMM:
13917                 return OP_X86_AND_MEMBASE_IMM;
13918         case OP_OR_IMM:
13919         case OP_IOR_IMM:
13920                 return OP_X86_OR_MEMBASE_IMM;
13921         case OP_XOR_IMM:
13922         case OP_IXOR_IMM:
13923                 return OP_X86_XOR_MEMBASE_IMM;
13924         case OP_MOVE:
13925                 return OP_NOP;
13926         }
13927 #endif
13928
13929 #if defined(TARGET_AMD64)
13930         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
13931                 return -1;
13932
13933         switch (opcode) {
13934         case OP_IADD:
13935                 return OP_X86_ADD_MEMBASE_REG;
13936         case OP_ISUB:
13937                 return OP_X86_SUB_MEMBASE_REG;
13938         case OP_IAND:
13939                 return OP_X86_AND_MEMBASE_REG;
13940         case OP_IOR:
13941                 return OP_X86_OR_MEMBASE_REG;
13942         case OP_IXOR:
13943                 return OP_X86_XOR_MEMBASE_REG;
13944         case OP_IADD_IMM:
13945                 return OP_X86_ADD_MEMBASE_IMM;
13946         case OP_ISUB_IMM:
13947                 return OP_X86_SUB_MEMBASE_IMM;
13948         case OP_IAND_IMM:
13949                 return OP_X86_AND_MEMBASE_IMM;
13950         case OP_IOR_IMM:
13951                 return OP_X86_OR_MEMBASE_IMM;
13952         case OP_IXOR_IMM:
13953                 return OP_X86_XOR_MEMBASE_IMM;
13954         case OP_LADD:
13955                 return OP_AMD64_ADD_MEMBASE_REG;
13956         case OP_LSUB:
13957                 return OP_AMD64_SUB_MEMBASE_REG;
13958         case OP_LAND:
13959                 return OP_AMD64_AND_MEMBASE_REG;
13960         case OP_LOR:
13961                 return OP_AMD64_OR_MEMBASE_REG;
13962         case OP_LXOR:
13963                 return OP_AMD64_XOR_MEMBASE_REG;
13964         case OP_ADD_IMM:
13965         case OP_LADD_IMM:
13966                 return OP_AMD64_ADD_MEMBASE_IMM;
13967         case OP_SUB_IMM:
13968         case OP_LSUB_IMM:
13969                 return OP_AMD64_SUB_MEMBASE_IMM;
13970         case OP_AND_IMM:
13971         case OP_LAND_IMM:
13972                 return OP_AMD64_AND_MEMBASE_IMM;
13973         case OP_OR_IMM:
13974         case OP_LOR_IMM:
13975                 return OP_AMD64_OR_MEMBASE_IMM;
13976         case OP_XOR_IMM:
13977         case OP_LXOR_IMM:
13978                 return OP_AMD64_XOR_MEMBASE_IMM;
13979         case OP_MOVE:
13980                 return OP_NOP;
13981         }
13982 #endif
13983
13984         return -1;
13985 }
13986
13987 static inline int
13988 op_to_op_store_membase (int store_opcode, int opcode)
13989 {
13990 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13991         switch (opcode) {
13992         case OP_ICEQ:
13993                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13994                         return OP_X86_SETEQ_MEMBASE;
13995         case OP_CNE:
13996                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13997                         return OP_X86_SETNE_MEMBASE;
13998         }
13999 #endif
14000
14001         return -1;
14002 }
14003
14004 static inline int
14005 op_to_op_src1_membase (MonoCompile *cfg, int load_opcode, int opcode)
14006 {
14007 #ifdef TARGET_X86
14008         /* FIXME: This has sign extension issues */
14009         /*
14010         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
14011                 return OP_X86_COMPARE_MEMBASE8_IMM;
14012         */
14013
14014         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
14015                 return -1;
14016
14017         switch (opcode) {
14018         case OP_X86_PUSH:
14019                 return OP_X86_PUSH_MEMBASE;
14020         case OP_COMPARE_IMM:
14021         case OP_ICOMPARE_IMM:
14022                 return OP_X86_COMPARE_MEMBASE_IMM;
14023         case OP_COMPARE:
14024         case OP_ICOMPARE:
14025                 return OP_X86_COMPARE_MEMBASE_REG;
14026         }
14027 #endif
14028
14029 #ifdef TARGET_AMD64
14030         /* FIXME: This has sign extension issues */
14031         /*
14032         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
14033                 return OP_X86_COMPARE_MEMBASE8_IMM;
14034         */
14035
14036         switch (opcode) {
14037         case OP_X86_PUSH:
14038                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
14039                         return OP_X86_PUSH_MEMBASE;
14040                 break;
14041                 /* FIXME: This only works for 32 bit immediates
14042         case OP_COMPARE_IMM:
14043         case OP_LCOMPARE_IMM:
14044                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
14045                         return OP_AMD64_COMPARE_MEMBASE_IMM;
14046                 */
14047         case OP_ICOMPARE_IMM:
14048                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
14049                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
14050                 break;
14051         case OP_COMPARE:
14052         case OP_LCOMPARE:
14053                 if (cfg->backend->ilp32 && load_opcode == OP_LOAD_MEMBASE)
14054                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
14055                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
14056                         return OP_AMD64_COMPARE_MEMBASE_REG;
14057                 break;
14058         case OP_ICOMPARE:
14059                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
14060                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
14061                 break;
14062         }
14063 #endif
14064
14065         return -1;
14066 }
14067
14068 static inline int
14069 op_to_op_src2_membase (MonoCompile *cfg, int load_opcode, int opcode)
14070 {
14071 #ifdef TARGET_X86
14072         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
14073                 return -1;
14074         
14075         switch (opcode) {
14076         case OP_COMPARE:
14077         case OP_ICOMPARE:
14078                 return OP_X86_COMPARE_REG_MEMBASE;
14079         case OP_IADD:
14080                 return OP_X86_ADD_REG_MEMBASE;
14081         case OP_ISUB:
14082                 return OP_X86_SUB_REG_MEMBASE;
14083         case OP_IAND:
14084                 return OP_X86_AND_REG_MEMBASE;
14085         case OP_IOR:
14086                 return OP_X86_OR_REG_MEMBASE;
14087         case OP_IXOR:
14088                 return OP_X86_XOR_REG_MEMBASE;
14089         }
14090 #endif
14091
14092 #ifdef TARGET_AMD64
14093         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && cfg->backend->ilp32)) {
14094                 switch (opcode) {
14095                 case OP_ICOMPARE:
14096                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
14097                 case OP_IADD:
14098                         return OP_X86_ADD_REG_MEMBASE;
14099                 case OP_ISUB:
14100                         return OP_X86_SUB_REG_MEMBASE;
14101                 case OP_IAND:
14102                         return OP_X86_AND_REG_MEMBASE;
14103                 case OP_IOR:
14104                         return OP_X86_OR_REG_MEMBASE;
14105                 case OP_IXOR:
14106                         return OP_X86_XOR_REG_MEMBASE;
14107                 }
14108         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32)) {
14109                 switch (opcode) {
14110                 case OP_COMPARE:
14111                 case OP_LCOMPARE:
14112                         return OP_AMD64_COMPARE_REG_MEMBASE;
14113                 case OP_LADD:
14114                         return OP_AMD64_ADD_REG_MEMBASE;
14115                 case OP_LSUB:
14116                         return OP_AMD64_SUB_REG_MEMBASE;
14117                 case OP_LAND:
14118                         return OP_AMD64_AND_REG_MEMBASE;
14119                 case OP_LOR:
14120                         return OP_AMD64_OR_REG_MEMBASE;
14121                 case OP_LXOR:
14122                         return OP_AMD64_XOR_REG_MEMBASE;
14123                 }
14124         }
14125 #endif
14126
14127         return -1;
14128 }
14129
14130 int
14131 mono_op_to_op_imm_noemul (int opcode)
14132 {
14133         switch (opcode) {
14134 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
14135         case OP_LSHR:
14136         case OP_LSHL:
14137         case OP_LSHR_UN:
14138                 return -1;
14139 #endif
14140 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
14141         case OP_IDIV:
14142         case OP_IDIV_UN:
14143         case OP_IREM:
14144         case OP_IREM_UN:
14145                 return -1;
14146 #endif
14147 #if defined(MONO_ARCH_EMULATE_MUL_DIV)
14148         case OP_IMUL:
14149                 return -1;
14150 #endif
14151         default:
14152                 return mono_op_to_op_imm (opcode);
14153         }
14154 }
14155
14156 /**
14157  * mono_handle_global_vregs:
14158  *
14159  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
14160  * for them.
14161  */
14162 void
14163 mono_handle_global_vregs (MonoCompile *cfg)
14164 {
14165         gint32 *vreg_to_bb;
14166         MonoBasicBlock *bb;
14167         int i, pos;
14168
14169         vreg_to_bb = (gint32 *)mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
14170
14171 #ifdef MONO_ARCH_SIMD_INTRINSICS
14172         if (cfg->uses_simd_intrinsics)
14173                 mono_simd_simplify_indirection (cfg);
14174 #endif
14175
14176         /* Find local vregs used in more than one bb */
14177         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
14178                 MonoInst *ins = bb->code;       
14179                 int block_num = bb->block_num;
14180
14181                 if (cfg->verbose_level > 2)
14182                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
14183
14184                 cfg->cbb = bb;
14185                 for (; ins; ins = ins->next) {
14186                         const char *spec = INS_INFO (ins->opcode);
14187                         int regtype = 0, regindex;
14188                         gint32 prev_bb;
14189
14190                         if (G_UNLIKELY (cfg->verbose_level > 2))
14191                                 mono_print_ins (ins);
14192
14193                         g_assert (ins->opcode >= MONO_CEE_LAST);
14194
14195                         for (regindex = 0; regindex < 4; regindex ++) {
14196                                 int vreg = 0;
14197
14198                                 if (regindex == 0) {
14199                                         regtype = spec [MONO_INST_DEST];
14200                                         if (regtype == ' ')
14201                                                 continue;
14202                                         vreg = ins->dreg;
14203                                 } else if (regindex == 1) {
14204                                         regtype = spec [MONO_INST_SRC1];
14205                                         if (regtype == ' ')
14206                                                 continue;
14207                                         vreg = ins->sreg1;
14208                                 } else if (regindex == 2) {
14209                                         regtype = spec [MONO_INST_SRC2];
14210                                         if (regtype == ' ')
14211                                                 continue;
14212                                         vreg = ins->sreg2;
14213                                 } else if (regindex == 3) {
14214                                         regtype = spec [MONO_INST_SRC3];
14215                                         if (regtype == ' ')
14216                                                 continue;
14217                                         vreg = ins->sreg3;
14218                                 }
14219
14220 #if SIZEOF_REGISTER == 4
14221                                 /* In the LLVM case, the long opcodes are not decomposed */
14222                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
14223                                         /*
14224                                          * Since some instructions reference the original long vreg,
14225                                          * and some reference the two component vregs, it is quite hard
14226                                          * to determine when it needs to be global. So be conservative.
14227                                          */
14228                                         if (!get_vreg_to_inst (cfg, vreg)) {
14229                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
14230
14231                                                 if (cfg->verbose_level > 2)
14232                                                         printf ("LONG VREG R%d made global.\n", vreg);
14233                                         }
14234
14235                                         /*
14236                                          * Make the component vregs volatile since the optimizations can
14237                                          * get confused otherwise.
14238                                          */
14239                                         get_vreg_to_inst (cfg, MONO_LVREG_LS (vreg))->flags |= MONO_INST_VOLATILE;
14240                                         get_vreg_to_inst (cfg, MONO_LVREG_MS (vreg))->flags |= MONO_INST_VOLATILE;
14241                                 }
14242 #endif
14243
14244                                 g_assert (vreg != -1);
14245
14246                                 prev_bb = vreg_to_bb [vreg];
14247                                 if (prev_bb == 0) {
14248                                         /* 0 is a valid block num */
14249                                         vreg_to_bb [vreg] = block_num + 1;
14250                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
14251                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
14252                                                 continue;
14253
14254                                         if (!get_vreg_to_inst (cfg, vreg)) {
14255                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14256                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
14257
14258                                                 switch (regtype) {
14259                                                 case 'i':
14260                                                         if (vreg_is_ref (cfg, vreg))
14261                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg);
14262                                                         else
14263                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
14264                                                         break;
14265                                                 case 'l':
14266                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
14267                                                         break;
14268                                                 case 'f':
14269                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
14270                                                         break;
14271                                                 case 'v':
14272                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
14273                                                         break;
14274                                                 default:
14275                                                         g_assert_not_reached ();
14276                                                 }
14277                                         }
14278
14279                                         /* Flag as having been used in more than one bb */
14280                                         vreg_to_bb [vreg] = -1;
14281                                 }
14282                         }
14283                 }
14284         }
14285
14286         /* If a variable is used in only one bblock, convert it into a local vreg */
14287         for (i = 0; i < cfg->num_varinfo; i++) {
14288                 MonoInst *var = cfg->varinfo [i];
14289                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
14290
14291                 switch (var->type) {
14292                 case STACK_I4:
14293                 case STACK_OBJ:
14294                 case STACK_PTR:
14295                 case STACK_MP:
14296                 case STACK_VTYPE:
14297 #if SIZEOF_REGISTER == 8
14298                 case STACK_I8:
14299 #endif
14300 #if !defined(TARGET_X86)
14301                 /* Enabling this screws up the fp stack on x86 */
14302                 case STACK_R8:
14303 #endif
14304                         if (mono_arch_is_soft_float ())
14305                                 break;
14306
14307                         /*
14308                         if (var->type == STACK_VTYPE && cfg->gsharedvt && mini_is_gsharedvt_variable_type (var->inst_vtype))
14309                                 break;
14310                         */
14311
14312                         /* Arguments are implicitly global */
14313                         /* Putting R4 vars into registers doesn't work currently */
14314                         /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
14315                         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) {
14316                                 /* 
14317                                  * Make that the variable's liveness interval doesn't contain a call, since
14318                                  * that would cause the lvreg to be spilled, making the whole optimization
14319                                  * useless.
14320                                  */
14321                                 /* This is too slow for JIT compilation */
14322 #if 0
14323                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
14324                                         MonoInst *ins;
14325                                         int def_index, call_index, ins_index;
14326                                         gboolean spilled = FALSE;
14327
14328                                         def_index = -1;
14329                                         call_index = -1;
14330                                         ins_index = 0;
14331                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
14332                                                 const char *spec = INS_INFO (ins->opcode);
14333
14334                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
14335                                                         def_index = ins_index;
14336
14337                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
14338                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
14339                                                         if (call_index > def_index) {
14340                                                                 spilled = TRUE;
14341                                                                 break;
14342                                                         }
14343                                                 }
14344
14345                                                 if (MONO_IS_CALL (ins))
14346                                                         call_index = ins_index;
14347
14348                                                 ins_index ++;
14349                                         }
14350
14351                                         if (spilled)
14352                                                 break;
14353                                 }
14354 #endif
14355
14356                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14357                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
14358                                 var->flags |= MONO_INST_IS_DEAD;
14359                                 cfg->vreg_to_inst [var->dreg] = NULL;
14360                         }
14361                         break;
14362                 }
14363         }
14364
14365         /* 
14366          * Compress the varinfo and vars tables so the liveness computation is faster and
14367          * takes up less space.
14368          */
14369         pos = 0;
14370         for (i = 0; i < cfg->num_varinfo; ++i) {
14371                 MonoInst *var = cfg->varinfo [i];
14372                 if (pos < i && cfg->locals_start == i)
14373                         cfg->locals_start = pos;
14374                 if (!(var->flags & MONO_INST_IS_DEAD)) {
14375                         if (pos < i) {
14376                                 cfg->varinfo [pos] = cfg->varinfo [i];
14377                                 cfg->varinfo [pos]->inst_c0 = pos;
14378                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
14379                                 cfg->vars [pos].idx = pos;
14380 #if SIZEOF_REGISTER == 4
14381                                 if (cfg->varinfo [pos]->type == STACK_I8) {
14382                                         /* Modify the two component vars too */
14383                                         MonoInst *var1;
14384
14385                                         var1 = get_vreg_to_inst (cfg, MONO_LVREG_LS (cfg->varinfo [pos]->dreg));
14386                                         var1->inst_c0 = pos;
14387                                         var1 = get_vreg_to_inst (cfg, MONO_LVREG_MS (cfg->varinfo [pos]->dreg));
14388                                         var1->inst_c0 = pos;
14389                                 }
14390 #endif
14391                         }
14392                         pos ++;
14393                 }
14394         }
14395         cfg->num_varinfo = pos;
14396         if (cfg->locals_start > cfg->num_varinfo)
14397                 cfg->locals_start = cfg->num_varinfo;
14398 }
14399
14400 /*
14401  * mono_allocate_gsharedvt_vars:
14402  *
14403  *   Allocate variables with gsharedvt types to entries in the MonoGSharedVtMethodRuntimeInfo.entries array.
14404  * Initialize cfg->gsharedvt_vreg_to_idx with the mapping between vregs and indexes.
14405  */
14406 void
14407 mono_allocate_gsharedvt_vars (MonoCompile *cfg)
14408 {
14409         int i;
14410
14411         cfg->gsharedvt_vreg_to_idx = (int *)mono_mempool_alloc0 (cfg->mempool, sizeof (int) * cfg->next_vreg);
14412
14413         for (i = 0; i < cfg->num_varinfo; ++i) {
14414                 MonoInst *ins = cfg->varinfo [i];
14415                 int idx;
14416
14417                 if (mini_is_gsharedvt_variable_type (ins->inst_vtype)) {
14418                         if (i >= cfg->locals_start) {
14419                                 /* Local */
14420                                 idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
14421                                 cfg->gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
14422                                 ins->opcode = OP_GSHAREDVT_LOCAL;
14423                                 ins->inst_imm = idx;
14424                         } else {
14425                                 /* Arg */
14426                                 cfg->gsharedvt_vreg_to_idx [ins->dreg] = -1;
14427                                 ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
14428                         }
14429                 }
14430         }
14431 }
14432
14433 /**
14434  * mono_spill_global_vars:
14435  *
14436  *   Generate spill code for variables which are not allocated to registers, 
14437  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
14438  * code is generated which could be optimized by the local optimization passes.
14439  */
14440 void
14441 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
14442 {
14443         MonoBasicBlock *bb;
14444         char spec2 [16];
14445         int orig_next_vreg;
14446         guint32 *vreg_to_lvreg;
14447         guint32 *lvregs;
14448         guint32 i, lvregs_len;
14449         gboolean dest_has_lvreg = FALSE;
14450         MonoStackType stacktypes [128];
14451         MonoInst **live_range_start, **live_range_end;
14452         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
14453
14454         *need_local_opts = FALSE;
14455
14456         memset (spec2, 0, sizeof (spec2));
14457
14458         /* FIXME: Move this function to mini.c */
14459         stacktypes ['i'] = STACK_PTR;
14460         stacktypes ['l'] = STACK_I8;
14461         stacktypes ['f'] = STACK_R8;
14462 #ifdef MONO_ARCH_SIMD_INTRINSICS
14463         stacktypes ['x'] = STACK_VTYPE;
14464 #endif
14465
14466 #if SIZEOF_REGISTER == 4
14467         /* Create MonoInsts for longs */
14468         for (i = 0; i < cfg->num_varinfo; i++) {
14469                 MonoInst *ins = cfg->varinfo [i];
14470
14471                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
14472                         switch (ins->type) {
14473                         case STACK_R8:
14474                         case STACK_I8: {
14475                                 MonoInst *tree;
14476
14477                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
14478                                         break;
14479
14480                                 g_assert (ins->opcode == OP_REGOFFSET);
14481
14482                                 tree = get_vreg_to_inst (cfg, MONO_LVREG_LS (ins->dreg));
14483                                 g_assert (tree);
14484                                 tree->opcode = OP_REGOFFSET;
14485                                 tree->inst_basereg = ins->inst_basereg;
14486                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
14487
14488                                 tree = get_vreg_to_inst (cfg, MONO_LVREG_MS (ins->dreg));
14489                                 g_assert (tree);
14490                                 tree->opcode = OP_REGOFFSET;
14491                                 tree->inst_basereg = ins->inst_basereg;
14492                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
14493                                 break;
14494                         }
14495                         default:
14496                                 break;
14497                         }
14498                 }
14499         }
14500 #endif
14501
14502         if (cfg->compute_gc_maps) {
14503                 /* registers need liveness info even for !non refs */
14504                 for (i = 0; i < cfg->num_varinfo; i++) {
14505                         MonoInst *ins = cfg->varinfo [i];
14506
14507                         if (ins->opcode == OP_REGVAR)
14508                                 ins->flags |= MONO_INST_GC_TRACK;
14509                 }
14510         }
14511                 
14512         /* FIXME: widening and truncation */
14513
14514         /*
14515          * As an optimization, when a variable allocated to the stack is first loaded into 
14516          * an lvreg, we will remember the lvreg and use it the next time instead of loading
14517          * the variable again.
14518          */
14519         orig_next_vreg = cfg->next_vreg;
14520         vreg_to_lvreg = (guint32 *)mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
14521         lvregs = (guint32 *)mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
14522         lvregs_len = 0;
14523
14524         /* 
14525          * These arrays contain the first and last instructions accessing a given
14526          * variable.
14527          * Since we emit bblocks in the same order we process them here, and we
14528          * don't split live ranges, these will precisely describe the live range of
14529          * the variable, i.e. the instruction range where a valid value can be found
14530          * in the variables location.
14531          * The live range is computed using the liveness info computed by the liveness pass.
14532          * We can't use vmv->range, since that is an abstract live range, and we need
14533          * one which is instruction precise.
14534          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
14535          */
14536         /* FIXME: Only do this if debugging info is requested */
14537         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
14538         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
14539         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
14540         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
14541         
14542         /* Add spill loads/stores */
14543         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
14544                 MonoInst *ins;
14545
14546                 if (cfg->verbose_level > 2)
14547                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
14548
14549                 /* Clear vreg_to_lvreg array */
14550                 for (i = 0; i < lvregs_len; i++)
14551                         vreg_to_lvreg [lvregs [i]] = 0;
14552                 lvregs_len = 0;
14553
14554                 cfg->cbb = bb;
14555                 MONO_BB_FOR_EACH_INS (bb, ins) {
14556                         const char *spec = INS_INFO (ins->opcode);
14557                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
14558                         gboolean store, no_lvreg;
14559                         int sregs [MONO_MAX_SRC_REGS];
14560
14561                         if (G_UNLIKELY (cfg->verbose_level > 2))
14562                                 mono_print_ins (ins);
14563
14564                         if (ins->opcode == OP_NOP)
14565                                 continue;
14566
14567                         /* 
14568                          * We handle LDADDR here as well, since it can only be decomposed
14569                          * when variable addresses are known.
14570                          */
14571                         if (ins->opcode == OP_LDADDR) {
14572                                 MonoInst *var = (MonoInst *)ins->inst_p0;
14573
14574                                 if (var->opcode == OP_VTARG_ADDR) {
14575                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
14576                                         MonoInst *vtaddr = var->inst_left;
14577                                         if (vtaddr->opcode == OP_REGVAR) {
14578                                                 ins->opcode = OP_MOVE;
14579                                                 ins->sreg1 = vtaddr->dreg;
14580                                         }
14581                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
14582                                                 ins->opcode = OP_LOAD_MEMBASE;
14583                                                 ins->inst_basereg = vtaddr->inst_basereg;
14584                                                 ins->inst_offset = vtaddr->inst_offset;
14585                                         } else
14586                                                 NOT_IMPLEMENTED;
14587                                 } else if (cfg->gsharedvt && cfg->gsharedvt_vreg_to_idx [var->dreg] < 0) {
14588                                         /* gsharedvt arg passed by ref */
14589                                         g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
14590
14591                                         ins->opcode = OP_LOAD_MEMBASE;
14592                                         ins->inst_basereg = var->inst_basereg;
14593                                         ins->inst_offset = var->inst_offset;
14594                                 } else if (cfg->gsharedvt && cfg->gsharedvt_vreg_to_idx [var->dreg]) {
14595                                         MonoInst *load, *load2, *load3;
14596                                         int idx = cfg->gsharedvt_vreg_to_idx [var->dreg] - 1;
14597                                         int reg1, reg2, reg3;
14598                                         MonoInst *info_var = cfg->gsharedvt_info_var;
14599                                         MonoInst *locals_var = cfg->gsharedvt_locals_var;
14600
14601                                         /*
14602                                          * gsharedvt local.
14603                                          * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
14604                                          */
14605
14606                                         g_assert (var->opcode == OP_GSHAREDVT_LOCAL);
14607
14608                                         g_assert (info_var);
14609                                         g_assert (locals_var);
14610
14611                                         /* Mark the instruction used to compute the locals var as used */
14612                                         cfg->gsharedvt_locals_var_ins = NULL;
14613
14614                                         /* Load the offset */
14615                                         if (info_var->opcode == OP_REGOFFSET) {
14616                                                 reg1 = alloc_ireg (cfg);
14617                                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, reg1, info_var->inst_basereg, info_var->inst_offset);
14618                                         } else if (info_var->opcode == OP_REGVAR) {
14619                                                 load = NULL;
14620                                                 reg1 = info_var->dreg;
14621                                         } else {
14622                                                 g_assert_not_reached ();
14623                                         }
14624                                         reg2 = alloc_ireg (cfg);
14625                                         NEW_LOAD_MEMBASE (cfg, load2, OP_LOADI4_MEMBASE, reg2, reg1, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
14626                                         /* Load the locals area address */
14627                                         reg3 = alloc_ireg (cfg);
14628                                         if (locals_var->opcode == OP_REGOFFSET) {
14629                                                 NEW_LOAD_MEMBASE (cfg, load3, OP_LOAD_MEMBASE, reg3, locals_var->inst_basereg, locals_var->inst_offset);
14630                                         } else if (locals_var->opcode == OP_REGVAR) {
14631                                                 NEW_UNALU (cfg, load3, OP_MOVE, reg3, locals_var->dreg);
14632                                         } else {
14633                                                 g_assert_not_reached ();
14634                                         }
14635                                         /* Compute the address */
14636                                         ins->opcode = OP_PADD;
14637                                         ins->sreg1 = reg3;
14638                                         ins->sreg2 = reg2;
14639
14640                                         mono_bblock_insert_before_ins (bb, ins, load3);
14641                                         mono_bblock_insert_before_ins (bb, load3, load2);
14642                                         if (load)
14643                                                 mono_bblock_insert_before_ins (bb, load2, load);
14644                                 } else {
14645                                         g_assert (var->opcode == OP_REGOFFSET);
14646
14647                                         ins->opcode = OP_ADD_IMM;
14648                                         ins->sreg1 = var->inst_basereg;
14649                                         ins->inst_imm = var->inst_offset;
14650                                 }
14651
14652                                 *need_local_opts = TRUE;
14653                                 spec = INS_INFO (ins->opcode);
14654                         }
14655
14656                         if (ins->opcode < MONO_CEE_LAST) {
14657                                 mono_print_ins (ins);
14658                                 g_assert_not_reached ();
14659                         }
14660
14661                         /*
14662                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
14663                          * src register.
14664                          * FIXME:
14665                          */
14666                         if (MONO_IS_STORE_MEMBASE (ins)) {
14667                                 tmp_reg = ins->dreg;
14668                                 ins->dreg = ins->sreg2;
14669                                 ins->sreg2 = tmp_reg;
14670                                 store = TRUE;
14671
14672                                 spec2 [MONO_INST_DEST] = ' ';
14673                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14674                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14675                                 spec2 [MONO_INST_SRC3] = ' ';
14676                                 spec = spec2;
14677                         } else if (MONO_IS_STORE_MEMINDEX (ins))
14678                                 g_assert_not_reached ();
14679                         else
14680                                 store = FALSE;
14681                         no_lvreg = FALSE;
14682
14683                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
14684                                 printf ("\t %.3s %d", spec, ins->dreg);
14685                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
14686                                 for (srcindex = 0; srcindex < num_sregs; ++srcindex)
14687                                         printf (" %d", sregs [srcindex]);
14688                                 printf ("\n");
14689                         }
14690
14691                         /***************/
14692                         /*    DREG     */
14693                         /***************/
14694                         regtype = spec [MONO_INST_DEST];
14695                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
14696                         prev_dreg = -1;
14697
14698                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
14699                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
14700                                 MonoInst *store_ins;
14701                                 int store_opcode;
14702                                 MonoInst *def_ins = ins;
14703                                 int dreg = ins->dreg; /* The original vreg */
14704
14705                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
14706
14707                                 if (var->opcode == OP_REGVAR) {
14708                                         ins->dreg = var->dreg;
14709                                 } 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)) {
14710                                         /* 
14711                                          * Instead of emitting a load+store, use a _membase opcode.
14712                                          */
14713                                         g_assert (var->opcode == OP_REGOFFSET);
14714                                         if (ins->opcode == OP_MOVE) {
14715                                                 NULLIFY_INS (ins);
14716                                                 def_ins = NULL;
14717                                         } else {
14718                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
14719                                                 ins->inst_basereg = var->inst_basereg;
14720                                                 ins->inst_offset = var->inst_offset;
14721                                                 ins->dreg = -1;
14722                                         }
14723                                         spec = INS_INFO (ins->opcode);
14724                                 } else {
14725                                         guint32 lvreg;
14726
14727                                         g_assert (var->opcode == OP_REGOFFSET);
14728
14729                                         prev_dreg = ins->dreg;
14730
14731                                         /* Invalidate any previous lvreg for this vreg */
14732                                         vreg_to_lvreg [ins->dreg] = 0;
14733
14734                                         lvreg = 0;
14735
14736                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
14737                                                 regtype = 'l';
14738                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
14739                                         }
14740
14741                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
14742
14743 #if SIZEOF_REGISTER != 8
14744                                         if (regtype == 'l') {
14745                                                 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));
14746                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14747                                                 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));
14748                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14749                                                 def_ins = store_ins;
14750                                         }
14751                                         else
14752 #endif
14753                                         {
14754                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
14755
14756                                                 /* Try to fuse the store into the instruction itself */
14757                                                 /* FIXME: Add more instructions */
14758                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
14759                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
14760                                                         ins->inst_imm = ins->inst_c0;
14761                                                         ins->inst_destbasereg = var->inst_basereg;
14762                                                         ins->inst_offset = var->inst_offset;
14763                                                         spec = INS_INFO (ins->opcode);
14764                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE) || (ins->opcode == OP_RMOVE))) {
14765                                                         ins->opcode = store_opcode;
14766                                                         ins->inst_destbasereg = var->inst_basereg;
14767                                                         ins->inst_offset = var->inst_offset;
14768
14769                                                         no_lvreg = TRUE;
14770
14771                                                         tmp_reg = ins->dreg;
14772                                                         ins->dreg = ins->sreg2;
14773                                                         ins->sreg2 = tmp_reg;
14774                                                         store = TRUE;
14775
14776                                                         spec2 [MONO_INST_DEST] = ' ';
14777                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14778                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14779                                                         spec2 [MONO_INST_SRC3] = ' ';
14780                                                         spec = spec2;
14781                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
14782                                                         // FIXME: The backends expect the base reg to be in inst_basereg
14783                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
14784                                                         ins->dreg = -1;
14785                                                         ins->inst_basereg = var->inst_basereg;
14786                                                         ins->inst_offset = var->inst_offset;
14787                                                         spec = INS_INFO (ins->opcode);
14788                                                 } else {
14789                                                         /* printf ("INS: "); mono_print_ins (ins); */
14790                                                         /* Create a store instruction */
14791                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
14792
14793                                                         /* Insert it after the instruction */
14794                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
14795
14796                                                         def_ins = store_ins;
14797
14798                                                         /* 
14799                                                          * We can't assign ins->dreg to var->dreg here, since the
14800                                                          * sregs could use it. So set a flag, and do it after
14801                                                          * the sregs.
14802                                                          */
14803                                                         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)))
14804                                                                 dest_has_lvreg = TRUE;
14805                                                 }
14806                                         }
14807                                 }
14808
14809                                 if (def_ins && !live_range_start [dreg]) {
14810                                         live_range_start [dreg] = def_ins;
14811                                         live_range_start_bb [dreg] = bb;
14812                                 }
14813
14814                                 if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) {
14815                                         MonoInst *tmp;
14816
14817                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
14818                                         tmp->inst_c1 = dreg;
14819                                         mono_bblock_insert_after_ins (bb, def_ins, tmp);
14820                                 }
14821                         }
14822
14823                         /************/
14824                         /*  SREGS   */
14825                         /************/
14826                         num_sregs = mono_inst_get_src_registers (ins, sregs);
14827                         for (srcindex = 0; srcindex < 3; ++srcindex) {
14828                                 regtype = spec [MONO_INST_SRC1 + srcindex];
14829                                 sreg = sregs [srcindex];
14830
14831                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
14832                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
14833                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
14834                                         MonoInst *use_ins = ins;
14835                                         MonoInst *load_ins;
14836                                         guint32 load_opcode;
14837
14838                                         if (var->opcode == OP_REGVAR) {
14839                                                 sregs [srcindex] = var->dreg;
14840                                                 //mono_inst_set_src_registers (ins, sregs);
14841                                                 live_range_end [sreg] = use_ins;
14842                                                 live_range_end_bb [sreg] = bb;
14843
14844                                                 if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14845                                                         MonoInst *tmp;
14846
14847                                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14848                                                         /* var->dreg is a hreg */
14849                                                         tmp->inst_c1 = sreg;
14850                                                         mono_bblock_insert_after_ins (bb, ins, tmp);
14851                                                 }
14852
14853                                                 continue;
14854                                         }
14855
14856                                         g_assert (var->opcode == OP_REGOFFSET);
14857                                                 
14858                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
14859
14860                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
14861
14862                                         if (vreg_to_lvreg [sreg]) {
14863                                                 g_assert (vreg_to_lvreg [sreg] != -1);
14864
14865                                                 /* The variable is already loaded to an lvreg */
14866                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14867                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
14868                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
14869                                                 //mono_inst_set_src_registers (ins, sregs);
14870                                                 continue;
14871                                         }
14872
14873                                         /* Try to fuse the load into the instruction */
14874                                         if ((srcindex == 0) && (op_to_op_src1_membase (cfg, load_opcode, ins->opcode) != -1)) {
14875                                                 ins->opcode = op_to_op_src1_membase (cfg, load_opcode, ins->opcode);
14876                                                 sregs [0] = var->inst_basereg;
14877                                                 //mono_inst_set_src_registers (ins, sregs);
14878                                                 ins->inst_offset = var->inst_offset;
14879                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (cfg, load_opcode, ins->opcode) != -1)) {
14880                                                 ins->opcode = op_to_op_src2_membase (cfg, load_opcode, ins->opcode);
14881                                                 sregs [1] = var->inst_basereg;
14882                                                 //mono_inst_set_src_registers (ins, sregs);
14883                                                 ins->inst_offset = var->inst_offset;
14884                                         } else {
14885                                                 if (MONO_IS_REAL_MOVE (ins)) {
14886                                                         ins->opcode = OP_NOP;
14887                                                         sreg = ins->dreg;
14888                                                 } else {
14889                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
14890
14891                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
14892
14893                                                         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) {
14894                                                                 if (var->dreg == prev_dreg) {
14895                                                                         /*
14896                                                                          * sreg refers to the value loaded by the load
14897                                                                          * emitted below, but we need to use ins->dreg
14898                                                                          * since it refers to the store emitted earlier.
14899                                                                          */
14900                                                                         sreg = ins->dreg;
14901                                                                 }
14902                                                                 g_assert (sreg != -1);
14903                                                                 vreg_to_lvreg [var->dreg] = sreg;
14904                                                                 g_assert (lvregs_len < 1024);
14905                                                                 lvregs [lvregs_len ++] = var->dreg;
14906                                                         }
14907                                                 }
14908
14909                                                 sregs [srcindex] = sreg;
14910                                                 //mono_inst_set_src_registers (ins, sregs);
14911
14912 #if SIZEOF_REGISTER != 8
14913                                                 if (regtype == 'l') {
14914                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, MONO_LVREG_MS (sreg), var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
14915                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14916                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, MONO_LVREG_LS (sreg), var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
14917                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14918                                                         use_ins = load_ins;
14919                                                 }
14920                                                 else
14921 #endif
14922                                                 {
14923 #if SIZEOF_REGISTER == 4
14924                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
14925 #endif
14926                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
14927                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14928                                                         use_ins = load_ins;
14929                                                 }
14930                                         }
14931
14932                                         if (var->dreg < orig_next_vreg) {
14933                                                 live_range_end [var->dreg] = use_ins;
14934                                                 live_range_end_bb [var->dreg] = bb;
14935                                         }
14936
14937                                         if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14938                                                 MonoInst *tmp;
14939
14940                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14941                                                 tmp->inst_c1 = var->dreg;
14942                                                 mono_bblock_insert_after_ins (bb, ins, tmp);
14943                                         }
14944                                 }
14945                         }
14946                         mono_inst_set_src_registers (ins, sregs);
14947
14948                         if (dest_has_lvreg) {
14949                                 g_assert (ins->dreg != -1);
14950                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
14951                                 g_assert (lvregs_len < 1024);
14952                                 lvregs [lvregs_len ++] = prev_dreg;
14953                                 dest_has_lvreg = FALSE;
14954                         }
14955
14956                         if (store) {
14957                                 tmp_reg = ins->dreg;
14958                                 ins->dreg = ins->sreg2;
14959                                 ins->sreg2 = tmp_reg;
14960                         }
14961
14962                         if (MONO_IS_CALL (ins)) {
14963                                 /* Clear vreg_to_lvreg array */
14964                                 for (i = 0; i < lvregs_len; i++)
14965                                         vreg_to_lvreg [lvregs [i]] = 0;
14966                                 lvregs_len = 0;
14967                         } else if (ins->opcode == OP_NOP) {
14968                                 ins->dreg = -1;
14969                                 MONO_INST_NULLIFY_SREGS (ins);
14970                         }
14971
14972                         if (cfg->verbose_level > 2)
14973                                 mono_print_ins_index (1, ins);
14974                 }
14975
14976                 /* Extend the live range based on the liveness info */
14977                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
14978                         for (i = 0; i < cfg->num_varinfo; i ++) {
14979                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
14980
14981                                 if (vreg_is_volatile (cfg, vi->vreg))
14982                                         /* The liveness info is incomplete */
14983                                         continue;
14984
14985                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
14986                                         /* Live from at least the first ins of this bb */
14987                                         live_range_start [vi->vreg] = bb->code;
14988                                         live_range_start_bb [vi->vreg] = bb;
14989                                 }
14990
14991                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
14992                                         /* Live at least until the last ins of this bb */
14993                                         live_range_end [vi->vreg] = bb->last_ins;
14994                                         live_range_end_bb [vi->vreg] = bb;
14995                                 }
14996                         }
14997                 }
14998         }
14999         
15000         /*
15001          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
15002          * by storing the current native offset into MonoMethodVar->live_range_start/end.
15003          */
15004         if (cfg->backend->have_liverange_ops && cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
15005                 for (i = 0; i < cfg->num_varinfo; ++i) {
15006                         int vreg = MONO_VARINFO (cfg, i)->vreg;
15007                         MonoInst *ins;
15008
15009                         if (live_range_start [vreg]) {
15010                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
15011                                 ins->inst_c0 = i;
15012                                 ins->inst_c1 = vreg;
15013                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
15014                         }
15015                         if (live_range_end [vreg]) {
15016                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
15017                                 ins->inst_c0 = i;
15018                                 ins->inst_c1 = vreg;
15019                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
15020                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
15021                                 else
15022                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
15023                         }
15024                 }
15025         }
15026
15027         if (cfg->gsharedvt_locals_var_ins) {
15028                 /* Nullify if unused */
15029                 cfg->gsharedvt_locals_var_ins->opcode = OP_PCONST;
15030                 cfg->gsharedvt_locals_var_ins->inst_imm = 0;
15031         }
15032
15033         g_free (live_range_start);
15034         g_free (live_range_end);
15035         g_free (live_range_start_bb);
15036         g_free (live_range_end_bb);
15037 }
15038
15039 /**
15040  * FIXME:
15041  * - use 'iadd' instead of 'int_add'
15042  * - handling ovf opcodes: decompose in method_to_ir.
15043  * - unify iregs/fregs
15044  *   -> partly done, the missing parts are:
15045  *   - a more complete unification would involve unifying the hregs as well, so
15046  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
15047  *     would no longer map to the machine hregs, so the code generators would need to
15048  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
15049  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
15050  *     fp/non-fp branches speeds it up by about 15%.
15051  * - use sext/zext opcodes instead of shifts
15052  * - add OP_ICALL
15053  * - get rid of TEMPLOADs if possible and use vregs instead
15054  * - clean up usage of OP_P/OP_ opcodes
15055  * - cleanup usage of DUMMY_USE
15056  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
15057  *   stack
15058  * - set the stack type and allocate a dreg in the EMIT_NEW macros
15059  * - get rid of all the <foo>2 stuff when the new JIT is ready.
15060  * - make sure handle_stack_args () is called before the branch is emitted
15061  * - when the new IR is done, get rid of all unused stuff
15062  * - COMPARE/BEQ as separate instructions or unify them ?
15063  *   - keeping them separate allows specialized compare instructions like
15064  *     compare_imm, compare_membase
15065  *   - most back ends unify fp compare+branch, fp compare+ceq
15066  * - integrate mono_save_args into inline_method
15067  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
15068  * - handle long shift opts on 32 bit platforms somehow: they require 
15069  *   3 sregs (2 for arg1 and 1 for arg2)
15070  * - make byref a 'normal' type.
15071  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
15072  *   variable if needed.
15073  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
15074  *   like inline_method.
15075  * - remove inlining restrictions
15076  * - fix LNEG and enable cfold of INEG
15077  * - generalize x86 optimizations like ldelema as a peephole optimization
15078  * - add store_mem_imm for amd64
15079  * - optimize the loading of the interruption flag in the managed->native wrappers
15080  * - avoid special handling of OP_NOP in passes
15081  * - move code inserting instructions into one function/macro.
15082  * - try a coalescing phase after liveness analysis
15083  * - add float -> vreg conversion + local optimizations on !x86
15084  * - figure out how to handle decomposed branches during optimizations, ie.
15085  *   compare+branch, op_jump_table+op_br etc.
15086  * - promote RuntimeXHandles to vregs
15087  * - vtype cleanups:
15088  *   - add a NEW_VARLOADA_VREG macro
15089  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
15090  *   accessing vtype fields.
15091  * - get rid of I8CONST on 64 bit platforms
15092  * - dealing with the increase in code size due to branches created during opcode
15093  *   decomposition:
15094  *   - use extended basic blocks
15095  *     - all parts of the JIT
15096  *     - handle_global_vregs () && local regalloc
15097  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
15098  * - sources of increase in code size:
15099  *   - vtypes
15100  *   - long compares
15101  *   - isinst and castclass
15102  *   - lvregs not allocated to global registers even if used multiple times
15103  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
15104  *   meaningful.
15105  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
15106  * - add all micro optimizations from the old JIT
15107  * - put tree optimizations into the deadce pass
15108  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
15109  *   specific function.
15110  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
15111  *   fcompare + branchCC.
15112  * - create a helper function for allocating a stack slot, taking into account 
15113  *   MONO_CFG_HAS_SPILLUP.
15114  * - merge r68207.
15115  * - merge the ia64 switch changes.
15116  * - optimize mono_regstate2_alloc_int/float.
15117  * - fix the pessimistic handling of variables accessed in exception handler blocks.
15118  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
15119  *   parts of the tree could be separated by other instructions, killing the tree
15120  *   arguments, or stores killing loads etc. Also, should we fold loads into other
15121  *   instructions if the result of the load is used multiple times ?
15122  * - make the REM_IMM optimization in mini-x86.c arch-independent.
15123  * - LAST MERGE: 108395.
15124  * - when returning vtypes in registers, generate IR and append it to the end of the
15125  *   last bb instead of doing it in the epilog.
15126  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
15127  */
15128
15129 /*
15130
15131 NOTES
15132 -----
15133
15134 - When to decompose opcodes:
15135   - earlier: this makes some optimizations hard to implement, since the low level IR
15136   no longer contains the neccessary information. But it is easier to do.
15137   - later: harder to implement, enables more optimizations.
15138 - Branches inside bblocks:
15139   - created when decomposing complex opcodes. 
15140     - branches to another bblock: harmless, but not tracked by the branch 
15141       optimizations, so need to branch to a label at the start of the bblock.
15142     - branches to inside the same bblock: very problematic, trips up the local
15143       reg allocator. Can be fixed by spitting the current bblock, but that is a
15144       complex operation, since some local vregs can become global vregs etc.
15145 - Local/global vregs:
15146   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
15147     local register allocator.
15148   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
15149     structure, created by mono_create_var (). Assigned to hregs or the stack by
15150     the global register allocator.
15151 - When to do optimizations like alu->alu_imm:
15152   - earlier -> saves work later on since the IR will be smaller/simpler
15153   - later -> can work on more instructions
15154 - Handling of valuetypes:
15155   - When a vtype is pushed on the stack, a new temporary is created, an 
15156     instruction computing its address (LDADDR) is emitted and pushed on
15157     the stack. Need to optimize cases when the vtype is used immediately as in
15158     argument passing, stloc etc.
15159 - Instead of the to_end stuff in the old JIT, simply call the function handling
15160   the values on the stack before emitting the last instruction of the bb.
15161 */
15162
15163 #endif /* DISABLE_JIT */