Merge pull request #1730 from BrzVlad/feature-arm-fast-tls
[mono.git] / mono / mini / method-to-ir.c
1 /*
2  * method-to-ir.c: Convert CIL to the JIT internal representation
3  *
4  * Author:
5  *   Paolo Molaro (lupus@ximian.com)
6  *   Dietmar Maurer (dietmar@ximian.com)
7  *
8  * (C) 2002 Ximian, Inc.
9  * Copyright 2003-2010 Novell, Inc (http://www.novell.com)
10  * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
11  */
12
13 #include <config.h>
14
15 #ifndef DISABLE_JIT
16
17 #include <signal.h>
18
19 #ifdef HAVE_UNISTD_H
20 #include <unistd.h>
21 #endif
22
23 #include <math.h>
24 #include <string.h>
25 #include <ctype.h>
26
27 #ifdef HAVE_SYS_TIME_H
28 #include <sys/time.h>
29 #endif
30
31 #ifdef HAVE_ALLOCA_H
32 #include <alloca.h>
33 #endif
34
35 #include <mono/utils/memcheck.h>
36 #include "mini.h"
37 #include <mono/metadata/abi-details.h>
38 #include <mono/metadata/assembly.h>
39 #include <mono/metadata/attrdefs.h>
40 #include <mono/metadata/loader.h>
41 #include <mono/metadata/tabledefs.h>
42 #include <mono/metadata/class.h>
43 #include <mono/metadata/object.h>
44 #include <mono/metadata/exception.h>
45 #include <mono/metadata/opcodes.h>
46 #include <mono/metadata/mono-endian.h>
47 #include <mono/metadata/tokentype.h>
48 #include <mono/metadata/tabledefs.h>
49 #include <mono/metadata/marshal.h>
50 #include <mono/metadata/debug-helpers.h>
51 #include <mono/metadata/mono-debug.h>
52 #include <mono/metadata/mono-debug-debugger.h>
53 #include <mono/metadata/gc-internal.h>
54 #include <mono/metadata/security-manager.h>
55 #include <mono/metadata/threads-types.h>
56 #include <mono/metadata/security-core-clr.h>
57 #include <mono/metadata/monitor.h>
58 #include <mono/metadata/profiler-private.h>
59 #include <mono/metadata/profiler.h>
60 #include <mono/metadata/debug-mono-symfile.h>
61 #include <mono/utils/mono-compiler.h>
62 #include <mono/utils/mono-memory-model.h>
63 #include <mono/metadata/mono-basic-block.h>
64
65 #include "trace.h"
66
67 #include "ir-emit.h"
68
69 #include "jit-icalls.h"
70 #include "jit.h"
71 #include "debugger-agent.h"
72 #include "seq-points.h"
73
74 #define BRANCH_COST 10
75 #define INLINE_LENGTH_LIMIT 20
76
77 /* These have 'cfg' as an implicit argument */
78 #define INLINE_FAILURE(msg) do {                                                                        \
79         if ((cfg->method != cfg->current_method) && (cfg->current_method->wrapper_type == MONO_WRAPPER_NONE)) { \
80                 inline_failure (cfg, msg);                                                                              \
81                 goto exception_exit;                                                                                    \
82         } \
83         } while (0)
84 #define CHECK_CFG_EXCEPTION do {\
85                 if (cfg->exception_type != MONO_EXCEPTION_NONE) \
86                         goto exception_exit;                                            \
87         } while (0)
88 #define METHOD_ACCESS_FAILURE(method, cmethod) do {                     \
89                 method_access_failure ((cfg), (method), (cmethod));                     \
90                 goto exception_exit;                                                                            \
91         } while (0)
92 #define FIELD_ACCESS_FAILURE(method, field) do {                                        \
93                 field_access_failure ((cfg), (method), (field));                        \
94                 goto exception_exit;    \
95         } while (0)
96 #define GENERIC_SHARING_FAILURE(opcode) do {            \
97                 if (cfg->gshared) {                                                                     \
98                         gshared_failure (cfg, opcode, __FILE__, __LINE__);      \
99                         goto exception_exit;    \
100                 }                       \
101         } while (0)
102 #define GSHAREDVT_FAILURE(opcode) do {          \
103         if (cfg->gsharedvt) {                                                                                           \
104                 gsharedvt_failure (cfg, opcode, __FILE__, __LINE__);                    \
105                 goto exception_exit;                                                                                    \
106         }                                                                                                                                       \
107         } while (0)
108 #define OUT_OF_MEMORY_FAILURE do {      \
109                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_OUT_OF_MEMORY);             \
110                 goto exception_exit;    \
111         } while (0)
112 #define DISABLE_AOT(cfg) do { \
113                 if ((cfg)->verbose_level >= 2)                                            \
114                         printf ("AOT disabled: %s:%d\n", __FILE__, __LINE__);   \
115                 (cfg)->disable_aot = TRUE;                                                        \
116         } while (0)
117 #define LOAD_ERROR do { \
118                 break_on_unverified ();                                                         \
119                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD); \
120                 goto exception_exit;                                                                    \
121         } while (0)
122
123 #define TYPE_LOAD_ERROR(klass) do { \
124                 cfg->exception_ptr = klass; \
125                 LOAD_ERROR;                                     \
126         } while (0)
127
128 #define CHECK_CFG_ERROR do {\
129                 if (!mono_error_ok (&cfg->error)) { \
130                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);        \
131                         goto mono_error_exit; \
132                 } \
133         } while (0)
134
135 /* Determine whenever 'ins' represents a load of the 'this' argument */
136 #define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && ((ins)->opcode == OP_MOVE) && ((ins)->sreg1 == cfg->args [0]->dreg))
137
138 static int ldind_to_load_membase (int opcode);
139 static int stind_to_store_membase (int opcode);
140
141 int mono_op_to_op_imm (int opcode);
142 int mono_op_to_op_imm_noemul (int opcode);
143
144 MONO_API MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
145
146 static int inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
147                                                   guchar *ip, guint real_offset, gboolean inline_always);
148
149 /* helper methods signatures */
150 static MonoMethodSignature *helper_sig_class_init_trampoline;
151 static MonoMethodSignature *helper_sig_domain_get;
152 static MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline;
153 static MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline;
154 static MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline_llvm;
155 static MonoMethodSignature *helper_sig_monitor_enter_v4_trampoline_llvm;
156
157 /*
158  * Instruction metadata
159  */
160 #ifdef MINI_OP
161 #undef MINI_OP
162 #endif
163 #ifdef MINI_OP3
164 #undef MINI_OP3
165 #endif
166 #define MINI_OP(a,b,dest,src1,src2) dest, src1, src2, ' ',
167 #define MINI_OP3(a,b,dest,src1,src2,src3) dest, src1, src2, src3,
168 #define NONE ' '
169 #define IREG 'i'
170 #define FREG 'f'
171 #define VREG 'v'
172 #define XREG 'x'
173 #if SIZEOF_REGISTER == 8 && SIZEOF_REGISTER == SIZEOF_VOID_P
174 #define LREG IREG
175 #else
176 #define LREG 'l'
177 #endif
178 /* keep in sync with the enum in mini.h */
179 const char
180 ins_info[] = {
181 #include "mini-ops.h"
182 };
183 #undef MINI_OP
184 #undef MINI_OP3
185
186 #define MINI_OP(a,b,dest,src1,src2) ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0)),
187 #define MINI_OP3(a,b,dest,src1,src2,src3) ((src3) != NONE ? 3 : ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0))),
188 /* 
189  * This should contain the index of the last sreg + 1. This is not the same
190  * as the number of sregs for opcodes like IA64_CMP_EQ_IMM.
191  */
192 const gint8 ins_sreg_counts[] = {
193 #include "mini-ops.h"
194 };
195 #undef MINI_OP
196 #undef MINI_OP3
197
198 #define MONO_INIT_VARINFO(vi,id) do { \
199         (vi)->range.first_use.pos.bid = 0xffff; \
200         (vi)->reg = -1; \
201         (vi)->idx = (id); \
202 } while (0)
203
204 guint32
205 mono_alloc_ireg (MonoCompile *cfg)
206 {
207         return alloc_ireg (cfg);
208 }
209
210 guint32
211 mono_alloc_lreg (MonoCompile *cfg)
212 {
213         return alloc_lreg (cfg);
214 }
215
216 guint32
217 mono_alloc_freg (MonoCompile *cfg)
218 {
219         return alloc_freg (cfg);
220 }
221
222 guint32
223 mono_alloc_preg (MonoCompile *cfg)
224 {
225         return alloc_preg (cfg);
226 }
227
228 guint32
229 mono_alloc_dreg (MonoCompile *cfg, MonoStackType stack_type)
230 {
231         return alloc_dreg (cfg, stack_type);
232 }
233
234 /*
235  * mono_alloc_ireg_ref:
236  *
237  *   Allocate an IREG, and mark it as holding a GC ref.
238  */
239 guint32
240 mono_alloc_ireg_ref (MonoCompile *cfg)
241 {
242         return alloc_ireg_ref (cfg);
243 }
244
245 /*
246  * mono_alloc_ireg_mp:
247  *
248  *   Allocate an IREG, and mark it as holding a managed pointer.
249  */
250 guint32
251 mono_alloc_ireg_mp (MonoCompile *cfg)
252 {
253         return alloc_ireg_mp (cfg);
254 }
255
256 /*
257  * mono_alloc_ireg_copy:
258  *
259  *   Allocate an IREG with the same GC type as VREG.
260  */
261 guint32
262 mono_alloc_ireg_copy (MonoCompile *cfg, guint32 vreg)
263 {
264         if (vreg_is_ref (cfg, vreg))
265                 return alloc_ireg_ref (cfg);
266         else if (vreg_is_mp (cfg, vreg))
267                 return alloc_ireg_mp (cfg);
268         else
269                 return alloc_ireg (cfg);
270 }
271
272 guint
273 mono_type_to_regmove (MonoCompile *cfg, MonoType *type)
274 {
275         if (type->byref)
276                 return OP_MOVE;
277
278         type = mini_get_underlying_type (cfg, type);
279 handle_enum:
280         switch (type->type) {
281         case MONO_TYPE_I1:
282         case MONO_TYPE_U1:
283                 return OP_MOVE;
284         case MONO_TYPE_I2:
285         case MONO_TYPE_U2:
286                 return OP_MOVE;
287         case MONO_TYPE_I4:
288         case MONO_TYPE_U4:
289                 return OP_MOVE;
290         case MONO_TYPE_I:
291         case MONO_TYPE_U:
292         case MONO_TYPE_PTR:
293         case MONO_TYPE_FNPTR:
294                 return OP_MOVE;
295         case MONO_TYPE_CLASS:
296         case MONO_TYPE_STRING:
297         case MONO_TYPE_OBJECT:
298         case MONO_TYPE_SZARRAY:
299         case MONO_TYPE_ARRAY:    
300                 return OP_MOVE;
301         case MONO_TYPE_I8:
302         case MONO_TYPE_U8:
303 #if SIZEOF_REGISTER == 8
304                 return OP_MOVE;
305 #else
306                 return OP_LMOVE;
307 #endif
308         case MONO_TYPE_R4:
309                 return cfg->r4fp ? OP_RMOVE : OP_FMOVE;
310         case MONO_TYPE_R8:
311                 return OP_FMOVE;
312         case MONO_TYPE_VALUETYPE:
313                 if (type->data.klass->enumtype) {
314                         type = mono_class_enum_basetype (type->data.klass);
315                         goto handle_enum;
316                 }
317                 if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
318                         return OP_XMOVE;
319                 return OP_VMOVE;
320         case MONO_TYPE_TYPEDBYREF:
321                 return OP_VMOVE;
322         case MONO_TYPE_GENERICINST:
323                 type = &type->data.generic_class->container_class->byval_arg;
324                 goto handle_enum;
325         case MONO_TYPE_VAR:
326         case MONO_TYPE_MVAR:
327                 g_assert (cfg->generic_sharing_context);
328                 if (mini_type_var_is_vt (cfg, type))
329                         return OP_VMOVE;
330                 else
331                         return mono_type_to_regmove (cfg, mini_get_underlying_type (cfg, type));
332         default:
333                 g_error ("unknown type 0x%02x in type_to_regstore", type->type);
334         }
335         return -1;
336 }
337
338 void
339 mono_print_bb (MonoBasicBlock *bb, const char *msg)
340 {
341         int i;
342         MonoInst *tree;
343
344         printf ("\n%s %d: [IN: ", msg, bb->block_num);
345         for (i = 0; i < bb->in_count; ++i)
346                 printf (" BB%d(%d)", bb->in_bb [i]->block_num, bb->in_bb [i]->dfn);
347         printf (", OUT: ");
348         for (i = 0; i < bb->out_count; ++i)
349                 printf (" BB%d(%d)", bb->out_bb [i]->block_num, bb->out_bb [i]->dfn);
350         printf (" ]\n");
351         for (tree = bb->code; tree; tree = tree->next)
352                 mono_print_ins_index (-1, tree);
353 }
354
355 void
356 mono_create_helper_signatures (void)
357 {
358         helper_sig_domain_get = mono_create_icall_signature ("ptr");
359         helper_sig_class_init_trampoline = mono_create_icall_signature ("void");
360         helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
361         helper_sig_monitor_enter_exit_trampoline = mono_create_icall_signature ("void");
362         helper_sig_monitor_enter_exit_trampoline_llvm = mono_create_icall_signature ("void object");
363         helper_sig_monitor_enter_v4_trampoline_llvm = mono_create_icall_signature ("void object ptr");
364 }
365
366 static MONO_NEVER_INLINE void
367 break_on_unverified (void)
368 {
369         if (mini_get_debug_options ()->break_on_unverified)
370                 G_BREAKPOINT ();
371 }
372
373 static MONO_NEVER_INLINE void
374 method_access_failure (MonoCompile *cfg, MonoMethod *method, MonoMethod *cil_method)
375 {
376         char *method_fname = mono_method_full_name (method, TRUE);
377         char *cil_method_fname = mono_method_full_name (cil_method, TRUE);
378         mono_cfg_set_exception (cfg, MONO_EXCEPTION_METHOD_ACCESS);
379         cfg->exception_message = g_strdup_printf ("Method `%s' is inaccessible from method `%s'\n", cil_method_fname, method_fname);
380         g_free (method_fname);
381         g_free (cil_method_fname);
382 }
383
384 static MONO_NEVER_INLINE void
385 field_access_failure (MonoCompile *cfg, MonoMethod *method, MonoClassField *field)
386 {
387         char *method_fname = mono_method_full_name (method, TRUE);
388         char *field_fname = mono_field_full_name (field);
389         mono_cfg_set_exception (cfg, MONO_EXCEPTION_FIELD_ACCESS);
390         cfg->exception_message = g_strdup_printf ("Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname);
391         g_free (method_fname);
392         g_free (field_fname);
393 }
394
395 static MONO_NEVER_INLINE void
396 inline_failure (MonoCompile *cfg, const char *msg)
397 {
398         if (cfg->verbose_level >= 2)
399                 printf ("inline failed: %s\n", msg);
400         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INLINE_FAILED);
401 }
402
403 static MONO_NEVER_INLINE void
404 gshared_failure (MonoCompile *cfg, int opcode, const char *file, int line)
405 {
406         if (cfg->verbose_level > 2)                                                                                     \
407                 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);
408         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
409 }
410
411 static MONO_NEVER_INLINE void
412 gsharedvt_failure (MonoCompile *cfg, int opcode, const char *file, int line)
413 {
414         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);
415         if (cfg->verbose_level >= 2)
416                 printf ("%s\n", cfg->exception_message);
417         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
418 }
419
420 /*
421  * When using gsharedvt, some instatiations might be verifiable, and some might be not. i.e. 
422  * foo<T> (int i) { ldarg.0; box T; }
423  */
424 #define UNVERIFIED do { \
425         if (cfg->gsharedvt) { \
426                 if (cfg->verbose_level > 2)                                                                     \
427                         printf ("gsharedvt method failed to verify, falling back to instantiation.\n"); \
428                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED); \
429                 goto exception_exit;                                                                                    \
430         }                                                                                                                                       \
431         break_on_unverified ();                                                                                         \
432         goto unverified;                                                                                                        \
433 } while (0)
434
435 #define GET_BBLOCK(cfg,tblock,ip) do {  \
436                 (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
437                 if (!(tblock)) {        \
438                         if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
439             NEW_BBLOCK (cfg, (tblock)); \
440                         (tblock)->cil_code = (ip);      \
441                         ADD_BBLOCK (cfg, (tblock));     \
442                 } \
443         } while (0)
444
445 #if defined(TARGET_X86) || defined(TARGET_AMD64)
446 #define EMIT_NEW_X86_LEA(cfg,dest,sr1,sr2,shift,imm) do { \
447                 MONO_INST_NEW (cfg, dest, OP_X86_LEA); \
448                 (dest)->dreg = alloc_ireg_mp ((cfg)); \
449                 (dest)->sreg1 = (sr1); \
450                 (dest)->sreg2 = (sr2); \
451                 (dest)->inst_imm = (imm); \
452                 (dest)->backend.shift_amount = (shift); \
453                 MONO_ADD_INS ((cfg)->cbb, (dest)); \
454         } while (0)
455 #endif
456
457 /* Emit conversions so both operands of a binary opcode are of the same type */
458 static void
459 add_widen_op (MonoCompile *cfg, MonoInst *ins, MonoInst **arg1_ref, MonoInst **arg2_ref)
460 {
461         MonoInst *arg1 = *arg1_ref;
462         MonoInst *arg2 = *arg2_ref;
463
464         if (cfg->r4fp &&
465                 ((arg1->type == STACK_R4 && arg2->type == STACK_R8) ||
466                  (arg1->type == STACK_R8 && arg2->type == STACK_R4))) {
467                 MonoInst *conv;
468
469                 /* Mixing r4/r8 is allowed by the spec */
470                 if (arg1->type == STACK_R4) {
471                         int dreg = alloc_freg (cfg);
472
473                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg1->dreg);
474                         conv->type = STACK_R8;
475                         ins->sreg1 = dreg;
476                         *arg1_ref = conv;
477                 }
478                 if (arg2->type == STACK_R4) {
479                         int dreg = alloc_freg (cfg);
480
481                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg2->dreg);
482                         conv->type = STACK_R8;
483                         ins->sreg2 = dreg;
484                         *arg2_ref = conv;
485                 }
486         }
487
488 #if SIZEOF_REGISTER == 8
489         /* FIXME: Need to add many more cases */
490         if ((arg1)->type == STACK_PTR && (arg2)->type == STACK_I4) {
491                 MonoInst *widen;
492
493                 int dr = alloc_preg (cfg);
494                 EMIT_NEW_UNALU (cfg, widen, OP_SEXT_I4, dr, (arg2)->dreg);
495                 (ins)->sreg2 = widen->dreg;
496         }
497 #endif
498 }
499
500 #define ADD_BINOP(op) do {      \
501                 MONO_INST_NEW (cfg, ins, (op)); \
502                 sp -= 2;        \
503                 ins->sreg1 = sp [0]->dreg;      \
504                 ins->sreg2 = sp [1]->dreg;      \
505                 type_from_op (cfg, ins, sp [0], sp [1]);        \
506                 CHECK_TYPE (ins);       \
507                 /* Have to insert a widening op */               \
508         add_widen_op (cfg, ins, &sp [0], &sp [1]);               \
509         ins->dreg = alloc_dreg ((cfg), (ins)->type); \
510         MONO_ADD_INS ((cfg)->cbb, (ins)); \
511         *sp++ = mono_decompose_opcode ((cfg), (ins));   \
512         } while (0)
513
514 #define ADD_UNOP(op) do {       \
515                 MONO_INST_NEW (cfg, ins, (op)); \
516                 sp--;   \
517                 ins->sreg1 = sp [0]->dreg;      \
518                 type_from_op (cfg, ins, sp [0], NULL);  \
519                 CHECK_TYPE (ins);       \
520         (ins)->dreg = alloc_dreg ((cfg), (ins)->type); \
521         MONO_ADD_INS ((cfg)->cbb, (ins)); \
522                 *sp++ = mono_decompose_opcode (cfg, ins);       \
523         } while (0)
524
525 #define ADD_BINCOND(next_block) do {    \
526                 MonoInst *cmp;  \
527                 sp -= 2; \
528                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
529                 cmp->sreg1 = sp [0]->dreg;      \
530                 cmp->sreg2 = sp [1]->dreg;      \
531                 type_from_op (cfg, cmp, sp [0], sp [1]);        \
532                 CHECK_TYPE (cmp);       \
533                 add_widen_op (cfg, cmp, &sp [0], &sp [1]);                                              \
534                 type_from_op (cfg, ins, sp [0], sp [1]);                                                        \
535                 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);      \
536                 GET_BBLOCK (cfg, tblock, target);               \
537                 link_bblock (cfg, cfg->cbb, tblock);    \
538                 ins->inst_true_bb = tblock;     \
539                 if ((next_block)) {     \
540                         link_bblock (cfg, cfg->cbb, (next_block));      \
541                         ins->inst_false_bb = (next_block);      \
542                         start_new_bblock = 1;   \
543                 } else {        \
544                         GET_BBLOCK (cfg, tblock, ip);           \
545                         link_bblock (cfg, cfg->cbb, tblock);    \
546                         ins->inst_false_bb = tblock;    \
547                         start_new_bblock = 2;   \
548                 }       \
549                 if (sp != stack_start) {                                                                        \
550                     handle_stack_args (cfg, stack_start, sp - stack_start); \
551                         CHECK_UNVERIFIABLE (cfg); \
552                 } \
553         MONO_ADD_INS (cfg->cbb, cmp); \
554                 MONO_ADD_INS (cfg->cbb, ins);   \
555         } while (0)
556
557 /* *
558  * link_bblock: Links two basic blocks
559  *
560  * links two basic blocks in the control flow graph, the 'from'
561  * argument is the starting block and the 'to' argument is the block
562  * the control flow ends to after 'from'.
563  */
564 static void
565 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
566 {
567         MonoBasicBlock **newa;
568         int i, found;
569
570 #if 0
571         if (from->cil_code) {
572                 if (to->cil_code)
573                         printf ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
574                 else
575                         printf ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
576         } else {
577                 if (to->cil_code)
578                         printf ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
579                 else
580                         printf ("edge from entry to exit\n");
581         }
582 #endif
583
584         found = FALSE;
585         for (i = 0; i < from->out_count; ++i) {
586                 if (to == from->out_bb [i]) {
587                         found = TRUE;
588                         break;
589                 }
590         }
591         if (!found) {
592                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
593                 for (i = 0; i < from->out_count; ++i) {
594                         newa [i] = from->out_bb [i];
595                 }
596                 newa [i] = to;
597                 from->out_count++;
598                 from->out_bb = newa;
599         }
600
601         found = FALSE;
602         for (i = 0; i < to->in_count; ++i) {
603                 if (from == to->in_bb [i]) {
604                         found = TRUE;
605                         break;
606                 }
607         }
608         if (!found) {
609                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
610                 for (i = 0; i < to->in_count; ++i) {
611                         newa [i] = to->in_bb [i];
612                 }
613                 newa [i] = from;
614                 to->in_count++;
615                 to->in_bb = newa;
616         }
617 }
618
619 void
620 mono_link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
621 {
622         link_bblock (cfg, from, to);
623 }
624
625 /**
626  * mono_find_block_region:
627  *
628  *   We mark each basic block with a region ID. We use that to avoid BB
629  *   optimizations when blocks are in different regions.
630  *
631  * Returns:
632  *   A region token that encodes where this region is, and information
633  *   about the clause owner for this block.
634  *
635  *   The region encodes the try/catch/filter clause that owns this block
636  *   as well as the type.  -1 is a special value that represents a block
637  *   that is in none of try/catch/filter.
638  */
639 static int
640 mono_find_block_region (MonoCompile *cfg, int offset)
641 {
642         MonoMethodHeader *header = cfg->header;
643         MonoExceptionClause *clause;
644         int i;
645
646         for (i = 0; i < header->num_clauses; ++i) {
647                 clause = &header->clauses [i];
648                 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
649                     (offset < (clause->handler_offset)))
650                         return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
651                            
652                 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
653                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
654                                 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
655                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
656                                 return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
657                         else
658                                 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
659                 }
660         }
661         for (i = 0; i < header->num_clauses; ++i) {
662                 clause = &header->clauses [i];
663
664                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
665                         return ((i + 1) << 8) | clause->flags;
666         }
667
668         return -1;
669 }
670
671 static GList*
672 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
673 {
674         MonoMethodHeader *header = cfg->header;
675         MonoExceptionClause *clause;
676         int i;
677         GList *res = NULL;
678
679         for (i = 0; i < header->num_clauses; ++i) {
680                 clause = &header->clauses [i];
681                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
682                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
683                         if (clause->flags == type)
684                                 res = g_list_append (res, clause);
685                 }
686         }
687         return res;
688 }
689
690 static void
691 mono_create_spvar_for_region (MonoCompile *cfg, int region)
692 {
693         MonoInst *var;
694
695         var = g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
696         if (var)
697                 return;
698
699         var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
700         /* prevent it from being register allocated */
701         var->flags |= MONO_INST_VOLATILE;
702
703         g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
704 }
705
706 MonoInst *
707 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
708 {
709         return g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
710 }
711
712 static MonoInst*
713 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
714 {
715         MonoInst *var;
716
717         var = g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
718         if (var)
719                 return var;
720
721         var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
722         /* prevent it from being register allocated */
723         var->flags |= MONO_INST_VOLATILE;
724
725         g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
726
727         return var;
728 }
729
730 /*
731  * Returns the type used in the eval stack when @type is loaded.
732  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
733  */
734 void
735 type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
736 {
737         MonoClass *klass;
738
739         type = mini_get_underlying_type (cfg, type);
740         inst->klass = klass = mono_class_from_mono_type (type);
741         if (type->byref) {
742                 inst->type = STACK_MP;
743                 return;
744         }
745
746 handle_enum:
747         switch (type->type) {
748         case MONO_TYPE_VOID:
749                 inst->type = STACK_INV;
750                 return;
751         case MONO_TYPE_I1:
752         case MONO_TYPE_U1:
753         case MONO_TYPE_I2:
754         case MONO_TYPE_U2:
755         case MONO_TYPE_I4:
756         case MONO_TYPE_U4:
757                 inst->type = STACK_I4;
758                 return;
759         case MONO_TYPE_I:
760         case MONO_TYPE_U:
761         case MONO_TYPE_PTR:
762         case MONO_TYPE_FNPTR:
763                 inst->type = STACK_PTR;
764                 return;
765         case MONO_TYPE_CLASS:
766         case MONO_TYPE_STRING:
767         case MONO_TYPE_OBJECT:
768         case MONO_TYPE_SZARRAY:
769         case MONO_TYPE_ARRAY:    
770                 inst->type = STACK_OBJ;
771                 return;
772         case MONO_TYPE_I8:
773         case MONO_TYPE_U8:
774                 inst->type = STACK_I8;
775                 return;
776         case MONO_TYPE_R4:
777                 inst->type = cfg->r4_stack_type;
778                 break;
779         case MONO_TYPE_R8:
780                 inst->type = STACK_R8;
781                 return;
782         case MONO_TYPE_VALUETYPE:
783                 if (type->data.klass->enumtype) {
784                         type = mono_class_enum_basetype (type->data.klass);
785                         goto handle_enum;
786                 } else {
787                         inst->klass = klass;
788                         inst->type = STACK_VTYPE;
789                         return;
790                 }
791         case MONO_TYPE_TYPEDBYREF:
792                 inst->klass = mono_defaults.typed_reference_class;
793                 inst->type = STACK_VTYPE;
794                 return;
795         case MONO_TYPE_GENERICINST:
796                 type = &type->data.generic_class->container_class->byval_arg;
797                 goto handle_enum;
798         case MONO_TYPE_VAR:
799         case MONO_TYPE_MVAR:
800                 g_assert (cfg->generic_sharing_context);
801                 if (mini_is_gsharedvt_type (cfg, type)) {
802                         g_assert (cfg->gsharedvt);
803                         inst->type = STACK_VTYPE;
804                 } else {
805                         type_to_eval_stack_type (cfg, mini_get_underlying_type (cfg, type), inst);
806                 }
807                 return;
808         default:
809                 g_error ("unknown type 0x%02x in eval stack type", type->type);
810         }
811 }
812
813 /*
814  * The following tables are used to quickly validate the IL code in type_from_op ().
815  */
816 static const char
817 bin_num_table [STACK_MAX] [STACK_MAX] = {
818         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
819         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
820         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
821         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
822         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV, STACK_R8},
823         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
824         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
825         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
826         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4}
827 };
828
829 static const char 
830 neg_table [] = {
831         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4
832 };
833
834 /* reduce the size of this table */
835 static const char
836 bin_int_table [STACK_MAX] [STACK_MAX] = {
837         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
838         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
839         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
840         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
841         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
842         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
843         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
844         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
845 };
846
847 static const char
848 bin_comp_table [STACK_MAX] [STACK_MAX] = {
849 /*      Inv i  L  p  F  &  O  vt r4 */
850         {0},
851         {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
852         {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
853         {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
854         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* F, R8 */
855         {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
856         {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
857         {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
858         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* r, r4 */
859 };
860
861 /* reduce the size of this table */
862 static const char
863 shift_table [STACK_MAX] [STACK_MAX] = {
864         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
865         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
866         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
867         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
868         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
869         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
870         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
871         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
872 };
873
874 /*
875  * Tables to map from the non-specific opcode to the matching
876  * type-specific opcode.
877  */
878 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
879 static const guint16
880 binops_op_map [STACK_MAX] = {
881         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
882 };
883
884 /* handles from CEE_NEG to CEE_CONV_U8 */
885 static const guint16
886 unops_op_map [STACK_MAX] = {
887         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
888 };
889
890 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
891 static const guint16
892 ovfops_op_map [STACK_MAX] = {
893         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
894 };
895
896 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
897 static const guint16
898 ovf2ops_op_map [STACK_MAX] = {
899         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
900 };
901
902 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
903 static const guint16
904 ovf3ops_op_map [STACK_MAX] = {
905         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
906 };
907
908 /* handles from CEE_BEQ to CEE_BLT_UN */
909 static const guint16
910 beqops_op_map [STACK_MAX] = {
911         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
912 };
913
914 /* handles from CEE_CEQ to CEE_CLT_UN */
915 static const guint16
916 ceqops_op_map [STACK_MAX] = {
917         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
918 };
919
920 /*
921  * Sets ins->type (the type on the eval stack) according to the
922  * type of the opcode and the arguments to it.
923  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
924  *
925  * FIXME: this function sets ins->type unconditionally in some cases, but
926  * it should set it to invalid for some types (a conv.x on an object)
927  */
928 static void
929 type_from_op (MonoCompile *cfg, MonoInst *ins, MonoInst *src1, MonoInst *src2)
930 {
931         switch (ins->opcode) {
932         /* binops */
933         case CEE_ADD:
934         case CEE_SUB:
935         case CEE_MUL:
936         case CEE_DIV:
937         case CEE_REM:
938                 /* FIXME: check unverifiable args for STACK_MP */
939                 ins->type = bin_num_table [src1->type] [src2->type];
940                 ins->opcode += binops_op_map [ins->type];
941                 break;
942         case CEE_DIV_UN:
943         case CEE_REM_UN:
944         case CEE_AND:
945         case CEE_OR:
946         case CEE_XOR:
947                 ins->type = bin_int_table [src1->type] [src2->type];
948                 ins->opcode += binops_op_map [ins->type];
949                 break;
950         case CEE_SHL:
951         case CEE_SHR:
952         case CEE_SHR_UN:
953                 ins->type = shift_table [src1->type] [src2->type];
954                 ins->opcode += binops_op_map [ins->type];
955                 break;
956         case OP_COMPARE:
957         case OP_LCOMPARE:
958         case OP_ICOMPARE:
959                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
960                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
961                         ins->opcode = OP_LCOMPARE;
962                 else if (src1->type == STACK_R4)
963                         ins->opcode = OP_RCOMPARE;
964                 else if (src1->type == STACK_R8)
965                         ins->opcode = OP_FCOMPARE;
966                 else
967                         ins->opcode = OP_ICOMPARE;
968                 break;
969         case OP_ICOMPARE_IMM:
970                 ins->type = bin_comp_table [src1->type] [src1->type] ? STACK_I4 : STACK_INV;
971                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
972                         ins->opcode = OP_LCOMPARE_IMM;          
973                 break;
974         case CEE_BEQ:
975         case CEE_BGE:
976         case CEE_BGT:
977         case CEE_BLE:
978         case CEE_BLT:
979         case CEE_BNE_UN:
980         case CEE_BGE_UN:
981         case CEE_BGT_UN:
982         case CEE_BLE_UN:
983         case CEE_BLT_UN:
984                 ins->opcode += beqops_op_map [src1->type];
985                 break;
986         case OP_CEQ:
987                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
988                 ins->opcode += ceqops_op_map [src1->type];
989                 break;
990         case OP_CGT:
991         case OP_CGT_UN:
992         case OP_CLT:
993         case OP_CLT_UN:
994                 ins->type = (bin_comp_table [src1->type] [src2->type] & 1) ? STACK_I4: STACK_INV;
995                 ins->opcode += ceqops_op_map [src1->type];
996                 break;
997         /* unops */
998         case CEE_NEG:
999                 ins->type = neg_table [src1->type];
1000                 ins->opcode += unops_op_map [ins->type];
1001                 break;
1002         case CEE_NOT:
1003                 if (src1->type >= STACK_I4 && src1->type <= STACK_PTR)
1004                         ins->type = src1->type;
1005                 else
1006                         ins->type = STACK_INV;
1007                 ins->opcode += unops_op_map [ins->type];
1008                 break;
1009         case CEE_CONV_I1:
1010         case CEE_CONV_I2:
1011         case CEE_CONV_I4:
1012         case CEE_CONV_U4:
1013                 ins->type = STACK_I4;
1014                 ins->opcode += unops_op_map [src1->type];
1015                 break;
1016         case CEE_CONV_R_UN:
1017                 ins->type = STACK_R8;
1018                 switch (src1->type) {
1019                 case STACK_I4:
1020                 case STACK_PTR:
1021                         ins->opcode = OP_ICONV_TO_R_UN;
1022                         break;
1023                 case STACK_I8:
1024                         ins->opcode = OP_LCONV_TO_R_UN; 
1025                         break;
1026                 }
1027                 break;
1028         case CEE_CONV_OVF_I1:
1029         case CEE_CONV_OVF_U1:
1030         case CEE_CONV_OVF_I2:
1031         case CEE_CONV_OVF_U2:
1032         case CEE_CONV_OVF_I4:
1033         case CEE_CONV_OVF_U4:
1034                 ins->type = STACK_I4;
1035                 ins->opcode += ovf3ops_op_map [src1->type];
1036                 break;
1037         case CEE_CONV_OVF_I_UN:
1038         case CEE_CONV_OVF_U_UN:
1039                 ins->type = STACK_PTR;
1040                 ins->opcode += ovf2ops_op_map [src1->type];
1041                 break;
1042         case CEE_CONV_OVF_I1_UN:
1043         case CEE_CONV_OVF_I2_UN:
1044         case CEE_CONV_OVF_I4_UN:
1045         case CEE_CONV_OVF_U1_UN:
1046         case CEE_CONV_OVF_U2_UN:
1047         case CEE_CONV_OVF_U4_UN:
1048                 ins->type = STACK_I4;
1049                 ins->opcode += ovf2ops_op_map [src1->type];
1050                 break;
1051         case CEE_CONV_U:
1052                 ins->type = STACK_PTR;
1053                 switch (src1->type) {
1054                 case STACK_I4:
1055                         ins->opcode = OP_ICONV_TO_U;
1056                         break;
1057                 case STACK_PTR:
1058                 case STACK_MP:
1059 #if SIZEOF_VOID_P == 8
1060                         ins->opcode = OP_LCONV_TO_U;
1061 #else
1062                         ins->opcode = OP_MOVE;
1063 #endif
1064                         break;
1065                 case STACK_I8:
1066                         ins->opcode = OP_LCONV_TO_U;
1067                         break;
1068                 case STACK_R8:
1069                         ins->opcode = OP_FCONV_TO_U;
1070                         break;
1071                 }
1072                 break;
1073         case CEE_CONV_I8:
1074         case CEE_CONV_U8:
1075                 ins->type = STACK_I8;
1076                 ins->opcode += unops_op_map [src1->type];
1077                 break;
1078         case CEE_CONV_OVF_I8:
1079         case CEE_CONV_OVF_U8:
1080                 ins->type = STACK_I8;
1081                 ins->opcode += ovf3ops_op_map [src1->type];
1082                 break;
1083         case CEE_CONV_OVF_U8_UN:
1084         case CEE_CONV_OVF_I8_UN:
1085                 ins->type = STACK_I8;
1086                 ins->opcode += ovf2ops_op_map [src1->type];
1087                 break;
1088         case CEE_CONV_R4:
1089                 ins->type = cfg->r4_stack_type;
1090                 ins->opcode += unops_op_map [src1->type];
1091                 break;
1092         case CEE_CONV_R8:
1093                 ins->type = STACK_R8;
1094                 ins->opcode += unops_op_map [src1->type];
1095                 break;
1096         case OP_CKFINITE:
1097                 ins->type = STACK_R8;           
1098                 break;
1099         case CEE_CONV_U2:
1100         case CEE_CONV_U1:
1101                 ins->type = STACK_I4;
1102                 ins->opcode += ovfops_op_map [src1->type];
1103                 break;
1104         case CEE_CONV_I:
1105         case CEE_CONV_OVF_I:
1106         case CEE_CONV_OVF_U:
1107                 ins->type = STACK_PTR;
1108                 ins->opcode += ovfops_op_map [src1->type];
1109                 break;
1110         case CEE_ADD_OVF:
1111         case CEE_ADD_OVF_UN:
1112         case CEE_MUL_OVF:
1113         case CEE_MUL_OVF_UN:
1114         case CEE_SUB_OVF:
1115         case CEE_SUB_OVF_UN:
1116                 ins->type = bin_num_table [src1->type] [src2->type];
1117                 ins->opcode += ovfops_op_map [src1->type];
1118                 if (ins->type == STACK_R8)
1119                         ins->type = STACK_INV;
1120                 break;
1121         case OP_LOAD_MEMBASE:
1122                 ins->type = STACK_PTR;
1123                 break;
1124         case OP_LOADI1_MEMBASE:
1125         case OP_LOADU1_MEMBASE:
1126         case OP_LOADI2_MEMBASE:
1127         case OP_LOADU2_MEMBASE:
1128         case OP_LOADI4_MEMBASE:
1129         case OP_LOADU4_MEMBASE:
1130                 ins->type = STACK_PTR;
1131                 break;
1132         case OP_LOADI8_MEMBASE:
1133                 ins->type = STACK_I8;
1134                 break;
1135         case OP_LOADR4_MEMBASE:
1136                 ins->type = cfg->r4_stack_type;
1137                 break;
1138         case OP_LOADR8_MEMBASE:
1139                 ins->type = STACK_R8;
1140                 break;
1141         default:
1142                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1143                 break;
1144         }
1145
1146         if (ins->type == STACK_MP)
1147                 ins->klass = mono_defaults.object_class;
1148 }
1149
1150 static const char 
1151 ldind_type [] = {
1152         STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
1153 };
1154
1155 #if 0
1156
1157 static const char
1158 param_table [STACK_MAX] [STACK_MAX] = {
1159         {0},
1160 };
1161
1162 static int
1163 check_values_to_signature (MonoInst *args, MonoType *this, MonoMethodSignature *sig) {
1164         int i;
1165
1166         if (sig->hasthis) {
1167                 switch (args->type) {
1168                 case STACK_I4:
1169                 case STACK_I8:
1170                 case STACK_R8:
1171                 case STACK_VTYPE:
1172                 case STACK_INV:
1173                         return 0;
1174                 }
1175                 args++;
1176         }
1177         for (i = 0; i < sig->param_count; ++i) {
1178                 switch (args [i].type) {
1179                 case STACK_INV:
1180                         return 0;
1181                 case STACK_MP:
1182                         if (!sig->params [i]->byref)
1183                                 return 0;
1184                         continue;
1185                 case STACK_OBJ:
1186                         if (sig->params [i]->byref)
1187                                 return 0;
1188                         switch (sig->params [i]->type) {
1189                         case MONO_TYPE_CLASS:
1190                         case MONO_TYPE_STRING:
1191                         case MONO_TYPE_OBJECT:
1192                         case MONO_TYPE_SZARRAY:
1193                         case MONO_TYPE_ARRAY:
1194                                 break;
1195                         default:
1196                                 return 0;
1197                         }
1198                         continue;
1199                 case STACK_R8:
1200                         if (sig->params [i]->byref)
1201                                 return 0;
1202                         if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1203                                 return 0;
1204                         continue;
1205                 case STACK_PTR:
1206                 case STACK_I4:
1207                 case STACK_I8:
1208                 case STACK_VTYPE:
1209                         break;
1210                 }
1211                 /*if (!param_table [args [i].type] [sig->params [i]->type])
1212                         return 0;*/
1213         }
1214         return 1;
1215 }
1216 #endif
1217
1218 /*
1219  * When we need a pointer to the current domain many times in a method, we
1220  * call mono_domain_get() once and we store the result in a local variable.
1221  * This function returns the variable that represents the MonoDomain*.
1222  */
1223 inline static MonoInst *
1224 mono_get_domainvar (MonoCompile *cfg)
1225 {
1226         if (!cfg->domainvar)
1227                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1228         return cfg->domainvar;
1229 }
1230
1231 /*
1232  * The got_var contains the address of the Global Offset Table when AOT 
1233  * compiling.
1234  */
1235 MonoInst *
1236 mono_get_got_var (MonoCompile *cfg)
1237 {
1238 #ifdef MONO_ARCH_NEED_GOT_VAR
1239         if (!cfg->compile_aot)
1240                 return NULL;
1241         if (!cfg->got_var) {
1242                 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1243         }
1244         return cfg->got_var;
1245 #else
1246         return NULL;
1247 #endif
1248 }
1249
1250 static MonoInst *
1251 mono_get_vtable_var (MonoCompile *cfg)
1252 {
1253         g_assert (cfg->generic_sharing_context);
1254
1255         if (!cfg->rgctx_var) {
1256                 cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1257                 /* force the var to be stack allocated */
1258                 cfg->rgctx_var->flags |= MONO_INST_VOLATILE;
1259         }
1260
1261         return cfg->rgctx_var;
1262 }
1263
1264 static MonoType*
1265 type_from_stack_type (MonoInst *ins) {
1266         switch (ins->type) {
1267         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1268         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1269         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1270         case STACK_R4: return &mono_defaults.single_class->byval_arg;
1271         case STACK_R8: return &mono_defaults.double_class->byval_arg;
1272         case STACK_MP:
1273                 return &ins->klass->this_arg;
1274         case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1275         case STACK_VTYPE: return &ins->klass->byval_arg;
1276         default:
1277                 g_error ("stack type %d to monotype not handled\n", ins->type);
1278         }
1279         return NULL;
1280 }
1281
1282 static G_GNUC_UNUSED int
1283 type_to_stack_type (MonoCompile *cfg, MonoType *t)
1284 {
1285         t = mono_type_get_underlying_type (t);
1286         switch (t->type) {
1287         case MONO_TYPE_I1:
1288         case MONO_TYPE_U1:
1289         case MONO_TYPE_I2:
1290         case MONO_TYPE_U2:
1291         case MONO_TYPE_I4:
1292         case MONO_TYPE_U4:
1293                 return STACK_I4;
1294         case MONO_TYPE_I:
1295         case MONO_TYPE_U:
1296         case MONO_TYPE_PTR:
1297         case MONO_TYPE_FNPTR:
1298                 return STACK_PTR;
1299         case MONO_TYPE_CLASS:
1300         case MONO_TYPE_STRING:
1301         case MONO_TYPE_OBJECT:
1302         case MONO_TYPE_SZARRAY:
1303         case MONO_TYPE_ARRAY:    
1304                 return STACK_OBJ;
1305         case MONO_TYPE_I8:
1306         case MONO_TYPE_U8:
1307                 return STACK_I8;
1308         case MONO_TYPE_R4:
1309                 return cfg->r4_stack_type;
1310         case MONO_TYPE_R8:
1311                 return STACK_R8;
1312         case MONO_TYPE_VALUETYPE:
1313         case MONO_TYPE_TYPEDBYREF:
1314                 return STACK_VTYPE;
1315         case MONO_TYPE_GENERICINST:
1316                 if (mono_type_generic_inst_is_valuetype (t))
1317                         return STACK_VTYPE;
1318                 else
1319                         return STACK_OBJ;
1320                 break;
1321         default:
1322                 g_assert_not_reached ();
1323         }
1324
1325         return -1;
1326 }
1327
1328 static MonoClass*
1329 array_access_to_klass (int opcode)
1330 {
1331         switch (opcode) {
1332         case CEE_LDELEM_U1:
1333                 return mono_defaults.byte_class;
1334         case CEE_LDELEM_U2:
1335                 return mono_defaults.uint16_class;
1336         case CEE_LDELEM_I:
1337         case CEE_STELEM_I:
1338                 return mono_defaults.int_class;
1339         case CEE_LDELEM_I1:
1340         case CEE_STELEM_I1:
1341                 return mono_defaults.sbyte_class;
1342         case CEE_LDELEM_I2:
1343         case CEE_STELEM_I2:
1344                 return mono_defaults.int16_class;
1345         case CEE_LDELEM_I4:
1346         case CEE_STELEM_I4:
1347                 return mono_defaults.int32_class;
1348         case CEE_LDELEM_U4:
1349                 return mono_defaults.uint32_class;
1350         case CEE_LDELEM_I8:
1351         case CEE_STELEM_I8:
1352                 return mono_defaults.int64_class;
1353         case CEE_LDELEM_R4:
1354         case CEE_STELEM_R4:
1355                 return mono_defaults.single_class;
1356         case CEE_LDELEM_R8:
1357         case CEE_STELEM_R8:
1358                 return mono_defaults.double_class;
1359         case CEE_LDELEM_REF:
1360         case CEE_STELEM_REF:
1361                 return mono_defaults.object_class;
1362         default:
1363                 g_assert_not_reached ();
1364         }
1365         return NULL;
1366 }
1367
1368 /*
1369  * We try to share variables when possible
1370  */
1371 static MonoInst *
1372 mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
1373 {
1374         MonoInst *res;
1375         int pos, vnum;
1376
1377         /* inlining can result in deeper stacks */ 
1378         if (slot >= cfg->header->max_stack)
1379                 return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1380
1381         pos = ins->type - 1 + slot * STACK_MAX;
1382
1383         switch (ins->type) {
1384         case STACK_I4:
1385         case STACK_I8:
1386         case STACK_R8:
1387         case STACK_PTR:
1388         case STACK_MP:
1389         case STACK_OBJ:
1390                 if ((vnum = cfg->intvars [pos]))
1391                         return cfg->varinfo [vnum];
1392                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1393                 cfg->intvars [pos] = res->inst_c0;
1394                 break;
1395         default:
1396                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1397         }
1398         return res;
1399 }
1400
1401 static void
1402 mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
1403 {
1404         /* 
1405          * Don't use this if a generic_context is set, since that means AOT can't
1406          * look up the method using just the image+token.
1407          * table == 0 means this is a reference made from a wrapper.
1408          */
1409         if (cfg->compile_aot && !cfg->generic_context && (mono_metadata_token_table (token) > 0)) {
1410                 MonoJumpInfoToken *jump_info_token = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
1411                 jump_info_token->image = image;
1412                 jump_info_token->token = token;
1413                 g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
1414         }
1415 }
1416
1417 /*
1418  * This function is called to handle items that are left on the evaluation stack
1419  * at basic block boundaries. What happens is that we save the values to local variables
1420  * and we reload them later when first entering the target basic block (with the
1421  * handle_loaded_temps () function).
1422  * A single joint point will use the same variables (stored in the array bb->out_stack or
1423  * bb->in_stack, if the basic block is before or after the joint point).
1424  *
1425  * This function needs to be called _before_ emitting the last instruction of
1426  * the bb (i.e. before emitting a branch).
1427  * If the stack merge fails at a join point, cfg->unverifiable is set.
1428  */
1429 static void
1430 handle_stack_args (MonoCompile *cfg, MonoInst **sp, int count)
1431 {
1432         int i, bindex;
1433         MonoBasicBlock *bb = cfg->cbb;
1434         MonoBasicBlock *outb;
1435         MonoInst *inst, **locals;
1436         gboolean found;
1437
1438         if (!count)
1439                 return;
1440         if (cfg->verbose_level > 3)
1441                 printf ("%d item(s) on exit from B%d\n", count, bb->block_num);
1442         if (!bb->out_scount) {
1443                 bb->out_scount = count;
1444                 //printf ("bblock %d has out:", bb->block_num);
1445                 found = FALSE;
1446                 for (i = 0; i < bb->out_count; ++i) {
1447                         outb = bb->out_bb [i];
1448                         /* exception handlers are linked, but they should not be considered for stack args */
1449                         if (outb->flags & BB_EXCEPTION_HANDLER)
1450                                 continue;
1451                         //printf (" %d", outb->block_num);
1452                         if (outb->in_stack) {
1453                                 found = TRUE;
1454                                 bb->out_stack = outb->in_stack;
1455                                 break;
1456                         }
1457                 }
1458                 //printf ("\n");
1459                 if (!found) {
1460                         bb->out_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1461                         for (i = 0; i < count; ++i) {
1462                                 /* 
1463                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
1464                                  * stack slot and if they are of the same type.
1465                                  * This won't cause conflicts since if 'local' is used to 
1466                                  * store one of the values in the in_stack of a bblock, then
1467                                  * the same variable will be used for the same outgoing stack 
1468                                  * slot as well. 
1469                                  * This doesn't work when inlining methods, since the bblocks
1470                                  * in the inlined methods do not inherit their in_stack from
1471                                  * the bblock they are inlined to. See bug #58863 for an
1472                                  * example.
1473                                  */
1474                                 if (cfg->inlined_method)
1475                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1476                                 else
1477                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
1478                         }
1479                 }
1480         }
1481
1482         for (i = 0; i < bb->out_count; ++i) {
1483                 outb = bb->out_bb [i];
1484                 /* exception handlers are linked, but they should not be considered for stack args */
1485                 if (outb->flags & BB_EXCEPTION_HANDLER)
1486                         continue;
1487                 if (outb->in_scount) {
1488                         if (outb->in_scount != bb->out_scount) {
1489                                 cfg->unverifiable = TRUE;
1490                                 return;
1491                         }
1492                         continue; /* check they are the same locals */
1493                 }
1494                 outb->in_scount = count;
1495                 outb->in_stack = bb->out_stack;
1496         }
1497
1498         locals = bb->out_stack;
1499         cfg->cbb = bb;
1500         for (i = 0; i < count; ++i) {
1501                 EMIT_NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
1502                 inst->cil_code = sp [i]->cil_code;
1503                 sp [i] = locals [i];
1504                 if (cfg->verbose_level > 3)
1505                         printf ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
1506         }
1507
1508         /*
1509          * It is possible that the out bblocks already have in_stack assigned, and
1510          * the in_stacks differ. In this case, we will store to all the different 
1511          * in_stacks.
1512          */
1513
1514         found = TRUE;
1515         bindex = 0;
1516         while (found) {
1517                 /* Find a bblock which has a different in_stack */
1518                 found = FALSE;
1519                 while (bindex < bb->out_count) {
1520                         outb = bb->out_bb [bindex];
1521                         /* exception handlers are linked, but they should not be considered for stack args */
1522                         if (outb->flags & BB_EXCEPTION_HANDLER) {
1523                                 bindex++;
1524                                 continue;
1525                         }
1526                         if (outb->in_stack != locals) {
1527                                 for (i = 0; i < count; ++i) {
1528                                         EMIT_NEW_TEMPSTORE (cfg, inst, outb->in_stack [i]->inst_c0, sp [i]);
1529                                         inst->cil_code = sp [i]->cil_code;
1530                                         sp [i] = locals [i];
1531                                         if (cfg->verbose_level > 3)
1532                                                 printf ("storing %d to temp %d\n", i, (int)outb->in_stack [i]->inst_c0);
1533                                 }
1534                                 locals = outb->in_stack;
1535                                 found = TRUE;
1536                                 break;
1537                         }
1538                         bindex ++;
1539                 }
1540         }
1541 }
1542
1543 static void
1544 mini_emit_interface_bitmap_check (MonoCompile *cfg, int intf_bit_reg, int base_reg, int offset, MonoClass *klass)
1545 {
1546         int ibitmap_reg = alloc_preg (cfg);
1547 #ifdef COMPRESSED_INTERFACE_BITMAP
1548         MonoInst *args [2];
1549         MonoInst *res, *ins;
1550         NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, ibitmap_reg, base_reg, offset);
1551         MONO_ADD_INS (cfg->cbb, ins);
1552         args [0] = ins;
1553         if (cfg->compile_aot)
1554                 EMIT_NEW_AOTCONST (cfg, args [1], MONO_PATCH_INFO_IID, klass);
1555         else
1556                 EMIT_NEW_ICONST (cfg, args [1], klass->interface_id);
1557         res = mono_emit_jit_icall (cfg, mono_class_interface_match, args);
1558         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, intf_bit_reg, res->dreg);
1559 #else
1560         int ibitmap_byte_reg = alloc_preg (cfg);
1561
1562         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, base_reg, offset);
1563
1564         if (cfg->compile_aot) {
1565                 int iid_reg = alloc_preg (cfg);
1566                 int shifted_iid_reg = alloc_preg (cfg);
1567                 int ibitmap_byte_address_reg = alloc_preg (cfg);
1568                 int masked_iid_reg = alloc_preg (cfg);
1569                 int iid_one_bit_reg = alloc_preg (cfg);
1570                 int iid_bit_reg = alloc_preg (cfg);
1571                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1572                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, shifted_iid_reg, iid_reg, 3);
1573                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ibitmap_byte_address_reg, ibitmap_reg, shifted_iid_reg);
1574                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, ibitmap_byte_reg, ibitmap_byte_address_reg, 0);
1575                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, masked_iid_reg, iid_reg, 7);
1576                 MONO_EMIT_NEW_ICONST (cfg, iid_one_bit_reg, 1);
1577                 MONO_EMIT_NEW_BIALU (cfg, OP_ISHL, iid_bit_reg, iid_one_bit_reg, masked_iid_reg);
1578                 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, intf_bit_reg, ibitmap_byte_reg, iid_bit_reg);
1579         } else {
1580                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, klass->interface_id >> 3);
1581                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (klass->interface_id & 7));
1582         }
1583 #endif
1584 }
1585
1586 /* 
1587  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoClass
1588  * stored in "klass_reg" implements the interface "klass".
1589  */
1590 static void
1591 mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass_reg, MonoClass *klass)
1592 {
1593         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, interface_bitmap), klass);
1594 }
1595
1596 /* 
1597  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoVTable
1598  * stored in "vtable_reg" implements the interface "klass".
1599  */
1600 static void
1601 mini_emit_load_intf_bit_reg_vtable (MonoCompile *cfg, int intf_bit_reg, int vtable_reg, MonoClass *klass)
1602 {
1603         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, interface_bitmap), klass);
1604 }
1605
1606 /* 
1607  * Emit code which checks whenever the interface id of @klass is smaller than
1608  * than the value given by max_iid_reg.
1609 */
1610 static void
1611 mini_emit_max_iid_check (MonoCompile *cfg, int max_iid_reg, MonoClass *klass,
1612                                                  MonoBasicBlock *false_target)
1613 {
1614         if (cfg->compile_aot) {
1615                 int iid_reg = alloc_preg (cfg);
1616                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1617                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, max_iid_reg, iid_reg);
1618         }
1619         else
1620                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, max_iid_reg, klass->interface_id);
1621         if (false_target)
1622                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1623         else
1624                 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1625 }
1626
1627 /* Same as above, but obtains max_iid from a vtable */
1628 static void
1629 mini_emit_max_iid_check_vtable (MonoCompile *cfg, int vtable_reg, MonoClass *klass,
1630                                                                  MonoBasicBlock *false_target)
1631 {
1632         int max_iid_reg = alloc_preg (cfg);
1633                 
1634         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, max_interface_id));
1635         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1636 }
1637
1638 /* Same as above, but obtains max_iid from a klass */
1639 static void
1640 mini_emit_max_iid_check_class (MonoCompile *cfg, int klass_reg, MonoClass *klass,
1641                                                                  MonoBasicBlock *false_target)
1642 {
1643         int max_iid_reg = alloc_preg (cfg);
1644
1645         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, max_interface_id));
1646         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1647 }
1648
1649 static void
1650 mini_emit_isninst_cast_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_ins, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1651 {
1652         int idepth_reg = alloc_preg (cfg);
1653         int stypes_reg = alloc_preg (cfg);
1654         int stype = alloc_preg (cfg);
1655
1656         mono_class_setup_supertypes (klass);
1657
1658         if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1659                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1660                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1661                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1662         }
1663         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1664         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1665         if (klass_ins) {
1666                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, klass_ins->dreg);
1667         } else if (cfg->compile_aot) {
1668                 int const_reg = alloc_preg (cfg);
1669                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1670                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, const_reg);
1671         } else {
1672                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, stype, klass);
1673         }
1674         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, true_target);
1675 }
1676
1677 static void
1678 mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1679 {
1680         mini_emit_isninst_cast_inst (cfg, klass_reg, klass, NULL, false_target, true_target);
1681 }
1682
1683 static void
1684 mini_emit_iface_cast (MonoCompile *cfg, int vtable_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1685 {
1686         int intf_reg = alloc_preg (cfg);
1687
1688         mini_emit_max_iid_check_vtable (cfg, vtable_reg, klass, false_target);
1689         mini_emit_load_intf_bit_reg_vtable (cfg, intf_reg, vtable_reg, klass);
1690         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_reg, 0);
1691         if (true_target)
1692                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1693         else
1694                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");               
1695 }
1696
1697 /*
1698  * Variant of the above that takes a register to the class, not the vtable.
1699  */
1700 static void
1701 mini_emit_iface_class_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1702 {
1703         int intf_bit_reg = alloc_preg (cfg);
1704
1705         mini_emit_max_iid_check_class (cfg, klass_reg, klass, false_target);
1706         mini_emit_load_intf_bit_reg_class (cfg, intf_bit_reg, klass_reg, klass);
1707         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_bit_reg, 0);
1708         if (true_target)
1709                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1710         else
1711                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
1712 }
1713
1714 static inline void
1715 mini_emit_class_check_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_inst)
1716 {
1717         if (klass_inst) {
1718                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_inst->dreg);
1719         } else if (cfg->compile_aot) {
1720                 int const_reg = alloc_preg (cfg);
1721                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1722                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1723         } else {
1724                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1725         }
1726         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1727 }
1728
1729 static inline void
1730 mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass)
1731 {
1732         mini_emit_class_check_inst (cfg, klass_reg, klass, NULL);
1733 }
1734
1735 static inline void
1736 mini_emit_class_check_branch (MonoCompile *cfg, int klass_reg, MonoClass *klass, int branch_op, MonoBasicBlock *target)
1737 {
1738         if (cfg->compile_aot) {
1739                 int const_reg = alloc_preg (cfg);
1740                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1741                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1742         } else {
1743                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1744         }
1745         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, branch_op, target);
1746 }
1747
1748 static void
1749 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null);
1750         
1751 static void
1752 mini_emit_castclass_inst (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoInst *klass_inst, MonoBasicBlock *object_is_null)
1753 {
1754         if (klass->rank) {
1755                 int rank_reg = alloc_preg (cfg);
1756                 int eclass_reg = alloc_preg (cfg);
1757
1758                 g_assert (!klass_inst);
1759                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, rank));
1760                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
1761                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1762                 //              MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
1763                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
1764                 if (klass->cast_class == mono_defaults.object_class) {
1765                         int parent_reg = alloc_preg (cfg);
1766                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
1767                         mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, object_is_null);
1768                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1769                 } else if (klass->cast_class == mono_defaults.enum_class->parent) {
1770                         mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, object_is_null);
1771                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1772                 } else if (klass->cast_class == mono_defaults.enum_class) {
1773                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1774                 } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1775                         mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, NULL, NULL);
1776                 } else {
1777                         // Pass -1 as obj_reg to skip the check below for arrays of arrays
1778                         mini_emit_castclass (cfg, -1, eclass_reg, klass->cast_class, object_is_null);
1779                 }
1780
1781                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY) && (obj_reg != -1)) {
1782                         /* Check that the object is a vector too */
1783                         int bounds_reg = alloc_preg (cfg);
1784                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
1785                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
1786                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1787                 }
1788         } else {
1789                 int idepth_reg = alloc_preg (cfg);
1790                 int stypes_reg = alloc_preg (cfg);
1791                 int stype = alloc_preg (cfg);
1792
1793                 mono_class_setup_supertypes (klass);
1794
1795                 if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1796                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1797                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1798                         MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1799                 }
1800                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1801                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1802                 mini_emit_class_check_inst (cfg, stype, klass, klass_inst);
1803         }
1804 }
1805
1806 static void
1807 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null)
1808 {
1809         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, NULL, object_is_null);
1810 }
1811
1812 static void 
1813 mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align)
1814 {
1815         int val_reg;
1816
1817         g_assert (val == 0);
1818
1819         if (align == 0)
1820                 align = 4;
1821
1822         if ((size <= SIZEOF_REGISTER) && (size <= align)) {
1823                 switch (size) {
1824                 case 1:
1825                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, destreg, offset, val);
1826                         return;
1827                 case 2:
1828                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI2_MEMBASE_IMM, destreg, offset, val);
1829                         return;
1830                 case 4:
1831                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI4_MEMBASE_IMM, destreg, offset, val);
1832                         return;
1833 #if SIZEOF_REGISTER == 8
1834                 case 8:
1835                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI8_MEMBASE_IMM, destreg, offset, val);
1836                         return;
1837 #endif
1838                 }
1839         }
1840
1841         val_reg = alloc_preg (cfg);
1842
1843         if (SIZEOF_REGISTER == 8)
1844                 MONO_EMIT_NEW_I8CONST (cfg, val_reg, val);
1845         else
1846                 MONO_EMIT_NEW_ICONST (cfg, val_reg, val);
1847
1848         if (align < 4) {
1849                 /* This could be optimized further if neccesary */
1850                 while (size >= 1) {
1851                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1852                         offset += 1;
1853                         size -= 1;
1854                 }
1855                 return;
1856         }       
1857
1858 #if !NO_UNALIGNED_ACCESS
1859         if (SIZEOF_REGISTER == 8) {
1860                 if (offset % 8) {
1861                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1862                         offset += 4;
1863                         size -= 4;
1864                 }
1865                 while (size >= 8) {
1866                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, offset, val_reg);
1867                         offset += 8;
1868                         size -= 8;
1869                 }
1870         }       
1871 #endif
1872
1873         while (size >= 4) {
1874                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1875                 offset += 4;
1876                 size -= 4;
1877         }
1878         while (size >= 2) {
1879                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, val_reg);
1880                 offset += 2;
1881                 size -= 2;
1882         }
1883         while (size >= 1) {
1884                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1885                 offset += 1;
1886                 size -= 1;
1887         }
1888 }
1889
1890 void 
1891 mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align)
1892 {
1893         int cur_reg;
1894
1895         if (align == 0)
1896                 align = 4;
1897
1898         /*FIXME arbitrary hack to avoid unbound code expansion.*/
1899         g_assert (size < 10000);
1900
1901         if (align < 4) {
1902                 /* This could be optimized further if neccesary */
1903                 while (size >= 1) {
1904                         cur_reg = alloc_preg (cfg);
1905                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1906                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1907                         doffset += 1;
1908                         soffset += 1;
1909                         size -= 1;
1910                 }
1911         }
1912
1913 #if !NO_UNALIGNED_ACCESS
1914         if (SIZEOF_REGISTER == 8) {
1915                 while (size >= 8) {
1916                         cur_reg = alloc_preg (cfg);
1917                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI8_MEMBASE, cur_reg, srcreg, soffset);
1918                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, doffset, cur_reg);
1919                         doffset += 8;
1920                         soffset += 8;
1921                         size -= 8;
1922                 }
1923         }       
1924 #endif
1925
1926         while (size >= 4) {
1927                 cur_reg = alloc_preg (cfg);
1928                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, cur_reg, srcreg, soffset);
1929                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, doffset, cur_reg);
1930                 doffset += 4;
1931                 soffset += 4;
1932                 size -= 4;
1933         }
1934         while (size >= 2) {
1935                 cur_reg = alloc_preg (cfg);
1936                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, cur_reg, srcreg, soffset);
1937                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, doffset, cur_reg);
1938                 doffset += 2;
1939                 soffset += 2;
1940                 size -= 2;
1941         }
1942         while (size >= 1) {
1943                 cur_reg = alloc_preg (cfg);
1944                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1945                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1946                 doffset += 1;
1947                 soffset += 1;
1948                 size -= 1;
1949         }
1950 }
1951
1952 static void
1953 emit_tls_set (MonoCompile *cfg, int sreg1, int tls_key)
1954 {
1955         MonoInst *ins, *c;
1956
1957         if (cfg->compile_aot) {
1958                 EMIT_NEW_TLS_OFFSETCONST (cfg, c, tls_key);
1959                 MONO_INST_NEW (cfg, ins, OP_TLS_SET_REG);
1960                 ins->sreg1 = sreg1;
1961                 ins->sreg2 = c->dreg;
1962                 MONO_ADD_INS (cfg->cbb, ins);
1963         } else {
1964                 MONO_INST_NEW (cfg, ins, OP_TLS_SET);
1965                 ins->sreg1 = sreg1;
1966                 ins->inst_offset = mini_get_tls_offset (tls_key);
1967                 MONO_ADD_INS (cfg->cbb, ins);
1968         }
1969 }
1970
1971 /*
1972  * emit_push_lmf:
1973  *
1974  *   Emit IR to push the current LMF onto the LMF stack.
1975  */
1976 static void
1977 emit_push_lmf (MonoCompile *cfg)
1978 {
1979         /*
1980          * Emit IR to push the LMF:
1981          * lmf_addr = <lmf_addr from tls>
1982          * lmf->lmf_addr = lmf_addr
1983          * lmf->prev_lmf = *lmf_addr
1984          * *lmf_addr = lmf
1985          */
1986         int lmf_reg, prev_lmf_reg;
1987         MonoInst *ins, *lmf_ins;
1988
1989         if (!cfg->lmf_ir)
1990                 return;
1991
1992         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
1993                 /* Load current lmf */
1994                 lmf_ins = mono_get_lmf_intrinsic (cfg);
1995                 g_assert (lmf_ins);
1996                 MONO_ADD_INS (cfg->cbb, lmf_ins);
1997                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
1998                 lmf_reg = ins->dreg;
1999                 /* Save previous_lmf */
2000                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), lmf_ins->dreg);
2001                 /* Set new LMF */
2002                 emit_tls_set (cfg, lmf_reg, TLS_KEY_LMF);
2003         } else {
2004                 /*
2005                  * Store lmf_addr in a variable, so it can be allocated to a global register.
2006                  */
2007                 if (!cfg->lmf_addr_var)
2008                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2009
2010 #ifdef HOST_WIN32
2011                 ins = mono_get_jit_tls_intrinsic (cfg);
2012                 if (ins) {
2013                         int jit_tls_dreg = ins->dreg;
2014
2015                         MONO_ADD_INS (cfg->cbb, ins);
2016                         lmf_reg = alloc_preg (cfg);
2017                         EMIT_NEW_BIALU_IMM (cfg, lmf_ins, OP_PADD_IMM, lmf_reg, jit_tls_dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2018                 } else {
2019                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2020                 }
2021 #else
2022                 lmf_ins = mono_get_lmf_addr_intrinsic (cfg);
2023                 if (lmf_ins) {
2024                         MONO_ADD_INS (cfg->cbb, lmf_ins);
2025                 } else {
2026 #ifdef TARGET_IOS
2027                         MonoInst *args [16], *jit_tls_ins, *ins;
2028
2029                         /* Inline mono_get_lmf_addr () */
2030                         /* jit_tls = pthread_getspecific (mono_jit_tls_id); lmf_addr = &jit_tls->lmf; */
2031
2032                         /* Load mono_jit_tls_id */
2033                         EMIT_NEW_AOTCONST (cfg, args [0], MONO_PATCH_INFO_JIT_TLS_ID, NULL);
2034                         /* call pthread_getspecific () */
2035                         jit_tls_ins = mono_emit_jit_icall (cfg, pthread_getspecific, args);
2036                         /* lmf_addr = &jit_tls->lmf */
2037                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, cfg->lmf_addr_var->dreg, jit_tls_ins->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2038                         lmf_ins = ins;
2039 #else
2040                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2041 #endif
2042                 }
2043 #endif
2044                 lmf_ins->dreg = cfg->lmf_addr_var->dreg;
2045
2046                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2047                 lmf_reg = ins->dreg;
2048
2049                 prev_lmf_reg = alloc_preg (cfg);
2050                 /* Save previous_lmf */
2051                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, cfg->lmf_addr_var->dreg, 0);
2052                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), prev_lmf_reg);
2053                 /* Set new lmf */
2054                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, cfg->lmf_addr_var->dreg, 0, lmf_reg);
2055         }
2056 }
2057
2058 /*
2059  * emit_pop_lmf:
2060  *
2061  *   Emit IR to pop the current LMF from the LMF stack.
2062  */
2063 static void
2064 emit_pop_lmf (MonoCompile *cfg)
2065 {
2066         int lmf_reg, lmf_addr_reg, prev_lmf_reg;
2067         MonoInst *ins;
2068
2069         if (!cfg->lmf_ir)
2070                 return;
2071
2072         EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2073         lmf_reg = ins->dreg;
2074
2075         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
2076                 /* Load previous_lmf */
2077                 prev_lmf_reg = alloc_preg (cfg);
2078                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2079                 /* Set new LMF */
2080                 emit_tls_set (cfg, prev_lmf_reg, TLS_KEY_LMF);
2081         } else {
2082                 /*
2083                  * Emit IR to pop the LMF:
2084                  * *(lmf->lmf_addr) = lmf->prev_lmf
2085                  */
2086                 /* This could be called before emit_push_lmf () */
2087                 if (!cfg->lmf_addr_var)
2088                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2089                 lmf_addr_reg = cfg->lmf_addr_var->dreg;
2090
2091                 prev_lmf_reg = alloc_preg (cfg);
2092                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2093                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_addr_reg, 0, prev_lmf_reg);
2094         }
2095 }
2096
2097 static void
2098 emit_instrumentation_call (MonoCompile *cfg, void *func)
2099 {
2100         MonoInst *iargs [1];
2101
2102         /*
2103          * Avoid instrumenting inlined methods since it can
2104          * distort profiling results.
2105          */
2106         if (cfg->method != cfg->current_method)
2107                 return;
2108
2109         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
2110                 EMIT_NEW_METHODCONST (cfg, iargs [0], cfg->method);
2111                 mono_emit_jit_icall (cfg, func, iargs);
2112         }
2113 }
2114
2115 static int
2116 ret_type_to_call_opcode (MonoCompile *cfg, MonoType *type, int calli, int virt, MonoGenericSharingContext *gsctx)
2117 {
2118 handle_enum:
2119         type = mini_get_underlying_type (cfg, type);
2120         switch (type->type) {
2121         case MONO_TYPE_VOID:
2122                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALL_MEMBASE: OP_VOIDCALL;
2123         case MONO_TYPE_I1:
2124         case MONO_TYPE_U1:
2125         case MONO_TYPE_I2:
2126         case MONO_TYPE_U2:
2127         case MONO_TYPE_I4:
2128         case MONO_TYPE_U4:
2129                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2130         case MONO_TYPE_I:
2131         case MONO_TYPE_U:
2132         case MONO_TYPE_PTR:
2133         case MONO_TYPE_FNPTR:
2134                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2135         case MONO_TYPE_CLASS:
2136         case MONO_TYPE_STRING:
2137         case MONO_TYPE_OBJECT:
2138         case MONO_TYPE_SZARRAY:
2139         case MONO_TYPE_ARRAY:    
2140                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2141         case MONO_TYPE_I8:
2142         case MONO_TYPE_U8:
2143                 return calli? OP_LCALL_REG: virt? OP_LCALL_MEMBASE: OP_LCALL;
2144         case MONO_TYPE_R4:
2145                 if (cfg->r4fp)
2146                         return calli? OP_RCALL_REG: virt? OP_RCALL_MEMBASE: OP_RCALL;
2147                 else
2148                         return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2149         case MONO_TYPE_R8:
2150                 return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2151         case MONO_TYPE_VALUETYPE:
2152                 if (type->data.klass->enumtype) {
2153                         type = mono_class_enum_basetype (type->data.klass);
2154                         goto handle_enum;
2155                 } else
2156                         return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2157         case MONO_TYPE_TYPEDBYREF:
2158                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2159         case MONO_TYPE_GENERICINST:
2160                 type = &type->data.generic_class->container_class->byval_arg;
2161                 goto handle_enum;
2162         case MONO_TYPE_VAR:
2163         case MONO_TYPE_MVAR:
2164                 /* gsharedvt */
2165                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2166         default:
2167                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
2168         }
2169         return -1;
2170 }
2171
2172 /*
2173  * target_type_is_incompatible:
2174  * @cfg: MonoCompile context
2175  *
2176  * Check that the item @arg on the evaluation stack can be stored
2177  * in the target type (can be a local, or field, etc).
2178  * The cfg arg can be used to check if we need verification or just
2179  * validity checks.
2180  *
2181  * Returns: non-0 value if arg can't be stored on a target.
2182  */
2183 static int
2184 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
2185 {
2186         MonoType *simple_type;
2187         MonoClass *klass;
2188
2189         if (target->byref) {
2190                 /* FIXME: check that the pointed to types match */
2191                 if (arg->type == STACK_MP)
2192                         return arg->klass != mono_class_from_mono_type (target);
2193                 if (arg->type == STACK_PTR)
2194                         return 0;
2195                 return 1;
2196         }
2197
2198         simple_type = mini_get_underlying_type (cfg, target);
2199         switch (simple_type->type) {
2200         case MONO_TYPE_VOID:
2201                 return 1;
2202         case MONO_TYPE_I1:
2203         case MONO_TYPE_U1:
2204         case MONO_TYPE_I2:
2205         case MONO_TYPE_U2:
2206         case MONO_TYPE_I4:
2207         case MONO_TYPE_U4:
2208                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2209                         return 1;
2210                 return 0;
2211         case MONO_TYPE_PTR:
2212                 /* STACK_MP is needed when setting pinned locals */
2213                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2214                         return 1;
2215                 return 0;
2216         case MONO_TYPE_I:
2217         case MONO_TYPE_U:
2218         case MONO_TYPE_FNPTR:
2219                 /* 
2220                  * Some opcodes like ldloca returns 'transient pointers' which can be stored in
2221                  * in native int. (#688008).
2222                  */
2223                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2224                         return 1;
2225                 return 0;
2226         case MONO_TYPE_CLASS:
2227         case MONO_TYPE_STRING:
2228         case MONO_TYPE_OBJECT:
2229         case MONO_TYPE_SZARRAY:
2230         case MONO_TYPE_ARRAY:    
2231                 if (arg->type != STACK_OBJ)
2232                         return 1;
2233                 /* FIXME: check type compatibility */
2234                 return 0;
2235         case MONO_TYPE_I8:
2236         case MONO_TYPE_U8:
2237                 if (arg->type != STACK_I8)
2238                         return 1;
2239                 return 0;
2240         case MONO_TYPE_R4:
2241                 if (arg->type != cfg->r4_stack_type)
2242                         return 1;
2243                 return 0;
2244         case MONO_TYPE_R8:
2245                 if (arg->type != STACK_R8)
2246                         return 1;
2247                 return 0;
2248         case MONO_TYPE_VALUETYPE:
2249                 if (arg->type != STACK_VTYPE)
2250                         return 1;
2251                 klass = mono_class_from_mono_type (simple_type);
2252                 if (klass != arg->klass)
2253                         return 1;
2254                 return 0;
2255         case MONO_TYPE_TYPEDBYREF:
2256                 if (arg->type != STACK_VTYPE)
2257                         return 1;
2258                 klass = mono_class_from_mono_type (simple_type);
2259                 if (klass != arg->klass)
2260                         return 1;
2261                 return 0;
2262         case MONO_TYPE_GENERICINST:
2263                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
2264                         if (arg->type != STACK_VTYPE)
2265                                 return 1;
2266                         klass = mono_class_from_mono_type (simple_type);
2267                         /* The second cases is needed when doing partial sharing */
2268                         if (klass != arg->klass && mono_class_from_mono_type (target) != arg->klass)
2269                                 return 1;
2270                         return 0;
2271                 } else {
2272                         if (arg->type != STACK_OBJ)
2273                                 return 1;
2274                         /* FIXME: check type compatibility */
2275                         return 0;
2276                 }
2277         case MONO_TYPE_VAR:
2278         case MONO_TYPE_MVAR:
2279                 g_assert (cfg->generic_sharing_context);
2280                 if (mini_type_var_is_vt (cfg, simple_type)) {
2281                         if (arg->type != STACK_VTYPE)
2282                                 return 1;
2283                 } else {
2284                         if (arg->type != STACK_OBJ)
2285                                 return 1;
2286                 }
2287                 return 0;
2288         default:
2289                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
2290         }
2291         return 1;
2292 }
2293
2294 /*
2295  * Prepare arguments for passing to a function call.
2296  * Return a non-zero value if the arguments can't be passed to the given
2297  * signature.
2298  * The type checks are not yet complete and some conversions may need
2299  * casts on 32 or 64 bit architectures.
2300  *
2301  * FIXME: implement this using target_type_is_incompatible ()
2302  */
2303 static int
2304 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2305 {
2306         MonoType *simple_type;
2307         int i;
2308
2309         if (sig->hasthis) {
2310                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2311                         return 1;
2312                 args++;
2313         }
2314         for (i = 0; i < sig->param_count; ++i) {
2315                 if (sig->params [i]->byref) {
2316                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2317                                 return 1;
2318                         continue;
2319                 }
2320                 simple_type = mini_get_underlying_type (cfg, sig->params [i]);
2321 handle_enum:
2322                 switch (simple_type->type) {
2323                 case MONO_TYPE_VOID:
2324                         return 1;
2325                         continue;
2326                 case MONO_TYPE_I1:
2327                 case MONO_TYPE_U1:
2328                 case MONO_TYPE_I2:
2329                 case MONO_TYPE_U2:
2330                 case MONO_TYPE_I4:
2331                 case MONO_TYPE_U4:
2332                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2333                                 return 1;
2334                         continue;
2335                 case MONO_TYPE_I:
2336                 case MONO_TYPE_U:
2337                 case MONO_TYPE_PTR:
2338                 case MONO_TYPE_FNPTR:
2339                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2340                                 return 1;
2341                         continue;
2342                 case MONO_TYPE_CLASS:
2343                 case MONO_TYPE_STRING:
2344                 case MONO_TYPE_OBJECT:
2345                 case MONO_TYPE_SZARRAY:
2346                 case MONO_TYPE_ARRAY:    
2347                         if (args [i]->type != STACK_OBJ)
2348                                 return 1;
2349                         continue;
2350                 case MONO_TYPE_I8:
2351                 case MONO_TYPE_U8:
2352                         if (args [i]->type != STACK_I8)
2353                                 return 1;
2354                         continue;
2355                 case MONO_TYPE_R4:
2356                         if (args [i]->type != cfg->r4_stack_type)
2357                                 return 1;
2358                         continue;
2359                 case MONO_TYPE_R8:
2360                         if (args [i]->type != STACK_R8)
2361                                 return 1;
2362                         continue;
2363                 case MONO_TYPE_VALUETYPE:
2364                         if (simple_type->data.klass->enumtype) {
2365                                 simple_type = mono_class_enum_basetype (simple_type->data.klass);
2366                                 goto handle_enum;
2367                         }
2368                         if (args [i]->type != STACK_VTYPE)
2369                                 return 1;
2370                         continue;
2371                 case MONO_TYPE_TYPEDBYREF:
2372                         if (args [i]->type != STACK_VTYPE)
2373                                 return 1;
2374                         continue;
2375                 case MONO_TYPE_GENERICINST:
2376                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2377                         goto handle_enum;
2378                 case MONO_TYPE_VAR:
2379                 case MONO_TYPE_MVAR:
2380                         /* gsharedvt */
2381                         if (args [i]->type != STACK_VTYPE)
2382                                 return 1;
2383                         continue;
2384                 default:
2385                         g_error ("unknown type 0x%02x in check_call_signature",
2386                                  simple_type->type);
2387                 }
2388         }
2389         return 0;
2390 }
2391
2392 static int
2393 callvirt_to_call (int opcode)
2394 {
2395         switch (opcode) {
2396         case OP_CALL_MEMBASE:
2397                 return OP_CALL;
2398         case OP_VOIDCALL_MEMBASE:
2399                 return OP_VOIDCALL;
2400         case OP_FCALL_MEMBASE:
2401                 return OP_FCALL;
2402         case OP_RCALL_MEMBASE:
2403                 return OP_RCALL;
2404         case OP_VCALL_MEMBASE:
2405                 return OP_VCALL;
2406         case OP_LCALL_MEMBASE:
2407                 return OP_LCALL;
2408         default:
2409                 g_assert_not_reached ();
2410         }
2411
2412         return -1;
2413 }
2414
2415 /* Either METHOD or IMT_ARG needs to be set */
2416 static void
2417 emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoMethod *method, MonoInst *imt_arg)
2418 {
2419         int method_reg;
2420
2421         if (COMPILE_LLVM (cfg)) {
2422                 method_reg = alloc_preg (cfg);
2423
2424                 if (imt_arg) {
2425                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2426                 } else if (cfg->compile_aot) {
2427                         MONO_EMIT_NEW_AOTCONST (cfg, method_reg, method, MONO_PATCH_INFO_METHODCONST);
2428                 } else {
2429                         MonoInst *ins;
2430                         MONO_INST_NEW (cfg, ins, OP_PCONST);
2431                         ins->inst_p0 = method;
2432                         ins->dreg = method_reg;
2433                         MONO_ADD_INS (cfg->cbb, ins);
2434                 }
2435
2436 #ifdef ENABLE_LLVM
2437                 call->imt_arg_reg = method_reg;
2438 #endif
2439         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2440                 return;
2441         }
2442
2443         method_reg = alloc_preg (cfg);
2444
2445         if (imt_arg) {
2446                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2447         } else if (cfg->compile_aot) {
2448                 MONO_EMIT_NEW_AOTCONST (cfg, method_reg, method, MONO_PATCH_INFO_METHODCONST);
2449         } else {
2450                 MonoInst *ins;
2451                 MONO_INST_NEW (cfg, ins, OP_PCONST);
2452                 ins->inst_p0 = method;
2453                 ins->dreg = method_reg;
2454                 MONO_ADD_INS (cfg->cbb, ins);
2455         }
2456
2457         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2458 }
2459
2460 static MonoJumpInfo *
2461 mono_patch_info_new (MonoMemPool *mp, int ip, MonoJumpInfoType type, gconstpointer target)
2462 {
2463         MonoJumpInfo *ji = mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
2464
2465         ji->ip.i = ip;
2466         ji->type = type;
2467         ji->data.target = target;
2468
2469         return ji;
2470 }
2471
2472 static int
2473 mini_class_check_context_used (MonoCompile *cfg, MonoClass *klass)
2474 {
2475         if (cfg->generic_sharing_context)
2476                 return mono_class_check_context_used (klass);
2477         else
2478                 return 0;
2479 }
2480
2481 static int
2482 mini_method_check_context_used (MonoCompile *cfg, MonoMethod *method)
2483 {
2484         if (cfg->generic_sharing_context)
2485                 return mono_method_check_context_used (method);
2486         else
2487                 return 0;
2488 }
2489
2490 /*
2491  * check_method_sharing:
2492  *
2493  *   Check whenever the vtable or an mrgctx needs to be passed when calling CMETHOD.
2494  */
2495 static void
2496 check_method_sharing (MonoCompile *cfg, MonoMethod *cmethod, gboolean *out_pass_vtable, gboolean *out_pass_mrgctx)
2497 {
2498         gboolean pass_vtable = FALSE;
2499         gboolean pass_mrgctx = FALSE;
2500
2501         if (((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
2502                 (cmethod->klass->generic_class || cmethod->klass->generic_container)) {
2503                 gboolean sharable = FALSE;
2504
2505                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE))
2506                         sharable = TRUE;
2507
2508                 /*
2509                  * Pass vtable iff target method might
2510                  * be shared, which means that sharing
2511                  * is enabled for its class and its
2512                  * context is sharable (and it's not a
2513                  * generic method).
2514                  */
2515                 if (sharable && !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
2516                         pass_vtable = TRUE;
2517         }
2518
2519         if (mini_method_get_context (cmethod) &&
2520                 mini_method_get_context (cmethod)->method_inst) {
2521                 g_assert (!pass_vtable);
2522
2523                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE)) {
2524                         pass_mrgctx = TRUE;
2525                 } else {
2526                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, mono_method_signature (cmethod)))
2527                                 pass_mrgctx = TRUE;
2528                 }
2529         }
2530
2531         if (out_pass_vtable)
2532                 *out_pass_vtable = pass_vtable;
2533         if (out_pass_mrgctx)
2534                 *out_pass_mrgctx = pass_mrgctx;
2535 }
2536
2537 inline static MonoCallInst *
2538 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
2539                                          MonoInst **args, int calli, int virtual, int tail, int rgctx, int unbox_trampoline)
2540 {
2541         MonoType *sig_ret;
2542         MonoCallInst *call;
2543 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2544         int i;
2545 #endif
2546
2547         if (tail) {
2548                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
2549
2550                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
2551         } else
2552                 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (cfg, sig->ret, calli, virtual, cfg->generic_sharing_context));
2553
2554         call->args = args;
2555         call->signature = sig;
2556         call->rgctx_reg = rgctx;
2557         sig_ret = mini_get_underlying_type (cfg, sig->ret);
2558
2559         type_to_eval_stack_type ((cfg), sig_ret, &call->inst);
2560
2561         if (tail) {
2562                 if (mini_type_is_vtype (cfg, sig_ret)) {
2563                         call->vret_var = cfg->vret_addr;
2564                         //g_assert_not_reached ();
2565                 }
2566         } else if (mini_type_is_vtype (cfg, sig_ret)) {
2567                 MonoInst *temp = mono_compile_create_var (cfg, sig_ret, OP_LOCAL);
2568                 MonoInst *loada;
2569
2570                 temp->backend.is_pinvoke = sig->pinvoke;
2571
2572                 /*
2573                  * We use a new opcode OP_OUTARG_VTRETADDR instead of LDADDR for emitting the
2574                  * address of return value to increase optimization opportunities.
2575                  * Before vtype decomposition, the dreg of the call ins itself represents the
2576                  * fact the call modifies the return value. After decomposition, the call will
2577                  * be transformed into one of the OP_VOIDCALL opcodes, and the VTRETADDR opcode
2578                  * will be transformed into an LDADDR.
2579                  */
2580                 MONO_INST_NEW (cfg, loada, OP_OUTARG_VTRETADDR);
2581                 loada->dreg = alloc_preg (cfg);
2582                 loada->inst_p0 = temp;
2583                 /* We reference the call too since call->dreg could change during optimization */
2584                 loada->inst_p1 = call;
2585                 MONO_ADD_INS (cfg->cbb, loada);
2586
2587                 call->inst.dreg = temp->dreg;
2588
2589                 call->vret_var = loada;
2590         } else if (!MONO_TYPE_IS_VOID (sig_ret))
2591                 call->inst.dreg = alloc_dreg (cfg, call->inst.type);
2592
2593 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2594         if (COMPILE_SOFT_FLOAT (cfg)) {
2595                 /* 
2596                  * If the call has a float argument, we would need to do an r8->r4 conversion using 
2597                  * an icall, but that cannot be done during the call sequence since it would clobber
2598                  * the call registers + the stack. So we do it before emitting the call.
2599                  */
2600                 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2601                         MonoType *t;
2602                         MonoInst *in = call->args [i];
2603
2604                         if (i >= sig->hasthis)
2605                                 t = sig->params [i - sig->hasthis];
2606                         else
2607                                 t = &mono_defaults.int_class->byval_arg;
2608                         t = mono_type_get_underlying_type (t);
2609
2610                         if (!t->byref && t->type == MONO_TYPE_R4) {
2611                                 MonoInst *iargs [1];
2612                                 MonoInst *conv;
2613
2614                                 iargs [0] = in;
2615                                 conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
2616
2617                                 /* The result will be in an int vreg */
2618                                 call->args [i] = conv;
2619                         }
2620                 }
2621         }
2622 #endif
2623
2624         call->need_unbox_trampoline = unbox_trampoline;
2625
2626 #ifdef ENABLE_LLVM
2627         if (COMPILE_LLVM (cfg))
2628                 mono_llvm_emit_call (cfg, call);
2629         else
2630                 mono_arch_emit_call (cfg, call);
2631 #else
2632         mono_arch_emit_call (cfg, call);
2633 #endif
2634
2635         cfg->param_area = MAX (cfg->param_area, call->stack_usage);
2636         cfg->flags |= MONO_CFG_HAS_CALLS;
2637         
2638         return call;
2639 }
2640
2641 static void
2642 set_rgctx_arg (MonoCompile *cfg, MonoCallInst *call, int rgctx_reg, MonoInst *rgctx_arg)
2643 {
2644 #ifdef MONO_ARCH_RGCTX_REG
2645         mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
2646         cfg->uses_rgctx_reg = TRUE;
2647         call->rgctx_reg = TRUE;
2648 #ifdef ENABLE_LLVM
2649         call->rgctx_arg_reg = rgctx_reg;
2650 #endif
2651 #else
2652         NOT_IMPLEMENTED;
2653 #endif
2654 }       
2655
2656 inline static MonoInst*
2657 mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg)
2658 {
2659         MonoCallInst *call;
2660         MonoInst *ins;
2661         int rgctx_reg = -1;
2662         gboolean check_sp = FALSE;
2663
2664         if (cfg->check_pinvoke_callconv && cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
2665                 WrapperInfo *info = mono_marshal_get_wrapper_info (cfg->method);
2666
2667                 if (info && info->subtype == WRAPPER_SUBTYPE_PINVOKE)
2668                         check_sp = TRUE;
2669         }
2670
2671         if (rgctx_arg) {
2672                 rgctx_reg = mono_alloc_preg (cfg);
2673                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2674         }
2675
2676         if (check_sp) {
2677                 if (!cfg->stack_inbalance_var)
2678                         cfg->stack_inbalance_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2679
2680                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2681                 ins->dreg = cfg->stack_inbalance_var->dreg;
2682                 MONO_ADD_INS (cfg->cbb, ins);
2683         }
2684
2685         call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE, FALSE);
2686
2687         call->inst.sreg1 = addr->dreg;
2688
2689         if (imt_arg)
2690                 emit_imt_argument (cfg, call, NULL, imt_arg);
2691
2692         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2693
2694         if (check_sp) {
2695                 int sp_reg;
2696
2697                 sp_reg = mono_alloc_preg (cfg);
2698
2699                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2700                 ins->dreg = sp_reg;
2701                 MONO_ADD_INS (cfg->cbb, ins);
2702
2703                 /* Restore the stack so we don't crash when throwing the exception */
2704                 MONO_INST_NEW (cfg, ins, OP_SET_SP);
2705                 ins->sreg1 = cfg->stack_inbalance_var->dreg;
2706                 MONO_ADD_INS (cfg->cbb, ins);
2707
2708                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, cfg->stack_inbalance_var->dreg, sp_reg);
2709                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ExecutionEngineException");
2710         }
2711
2712         if (rgctx_arg)
2713                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2714
2715         return (MonoInst*)call;
2716 }
2717
2718 static MonoInst*
2719 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2720
2721 static MonoInst*
2722 emit_get_rgctx_method (MonoCompile *cfg, int context_used, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type);
2723 static MonoInst*
2724 emit_get_rgctx_klass (MonoCompile *cfg, int context_used, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2725
2726 static MonoInst*
2727 mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig, gboolean tail,
2728                                                         MonoInst **args, MonoInst *this, MonoInst *imt_arg, MonoInst *rgctx_arg)
2729 {
2730 #ifndef DISABLE_REMOTING
2731         gboolean might_be_remote = FALSE;
2732 #endif
2733         gboolean virtual = this != NULL;
2734         gboolean enable_for_aot = TRUE;
2735         int context_used;
2736         MonoCallInst *call;
2737         int rgctx_reg = 0;
2738         gboolean need_unbox_trampoline;
2739
2740         if (!sig)
2741                 sig = mono_method_signature (method);
2742
2743         if (rgctx_arg) {
2744                 rgctx_reg = mono_alloc_preg (cfg);
2745                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2746         }
2747
2748         if (method->string_ctor) {
2749                 /* Create the real signature */
2750                 /* FIXME: Cache these */
2751                 MonoMethodSignature *ctor_sig = mono_metadata_signature_dup_mempool (cfg->mempool, sig);
2752                 ctor_sig->ret = &mono_defaults.string_class->byval_arg;
2753
2754                 sig = ctor_sig;
2755         }
2756
2757         context_used = mini_method_check_context_used (cfg, method);
2758
2759 #ifndef DISABLE_REMOTING
2760         might_be_remote = this && sig->hasthis &&
2761                 (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) &&
2762                 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && (!MONO_CHECK_THIS (this) || context_used);
2763
2764         if (might_be_remote && context_used) {
2765                 MonoInst *addr;
2766
2767                 g_assert (cfg->generic_sharing_context);
2768
2769                 addr = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK);
2770
2771                 return mono_emit_calli (cfg, sig, args, addr, NULL, NULL);
2772         }
2773 #endif
2774
2775         need_unbox_trampoline = method->klass == mono_defaults.object_class || (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
2776
2777         call = mono_emit_call_args (cfg, sig, args, FALSE, virtual, tail, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline);
2778
2779 #ifndef DISABLE_REMOTING
2780         if (might_be_remote)
2781                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2782         else
2783 #endif
2784                 call->method = method;
2785         call->inst.flags |= MONO_INST_HAS_METHOD;
2786         call->inst.inst_left = this;
2787         call->tail_call = tail;
2788
2789         if (virtual) {
2790                 int vtable_reg, slot_reg, this_reg;
2791                 int offset;
2792
2793                 this_reg = this->dreg;
2794
2795                 if ((method->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (method->name, "Invoke")) {
2796                         MonoInst *dummy_use;
2797
2798                         MONO_EMIT_NULL_CHECK (cfg, this_reg);
2799
2800                         /* Make a call to delegate->invoke_impl */
2801                         call->inst.inst_basereg = this_reg;
2802                         call->inst.inst_offset = MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl);
2803                         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2804
2805                         /* We must emit a dummy use here because the delegate trampoline will
2806                         replace the 'this' argument with the delegate target making this activation
2807                         no longer a root for the delegate.
2808                         This is an issue for delegates that target collectible code such as dynamic
2809                         methods of GC'able assemblies.
2810
2811                         For a test case look into #667921.
2812
2813                         FIXME: a dummy use is not the best way to do it as the local register allocator
2814                         will put it on a caller save register and spil it around the call. 
2815                         Ideally, we would either put it on a callee save register or only do the store part.  
2816                          */
2817                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, args [0]);
2818
2819                         return (MonoInst*)call;
2820                 }
2821
2822                 if ((!cfg->compile_aot || enable_for_aot) && 
2823                         (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || 
2824                          (MONO_METHOD_IS_FINAL (method) &&
2825                           method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)) &&
2826                         !(mono_class_is_marshalbyref (method->klass) && context_used)) {
2827                         /* 
2828                          * the method is not virtual, we just need to ensure this is not null
2829                          * and then we can call the method directly.
2830                          */
2831 #ifndef DISABLE_REMOTING
2832                         if (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) {
2833                                 /* 
2834                                  * The check above ensures method is not gshared, this is needed since
2835                                  * gshared methods can't have wrappers.
2836                                  */
2837                                 method = call->method = mono_marshal_get_remoting_invoke_with_check (method);
2838                         }
2839 #endif
2840
2841                         if (!method->string_ctor)
2842                                 MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2843
2844                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2845                 } else if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && MONO_METHOD_IS_FINAL (method)) {
2846                         /*
2847                          * the method is virtual, but we can statically dispatch since either
2848                          * it's class or the method itself are sealed.
2849                          * But first we need to ensure it's not a null reference.
2850                          */
2851                         MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2852
2853                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2854                 } else {
2855                         vtable_reg = alloc_preg (cfg);
2856                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2857                         if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2858                                 guint32 imt_slot = mono_method_get_imt_slot (method);
2859                                 emit_imt_argument (cfg, call, call->method, imt_arg);
2860                                 slot_reg = vtable_reg;
2861                                 offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
2862                         } else {
2863                                 slot_reg = vtable_reg;
2864                                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) +
2865                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
2866                                 if (imt_arg) {
2867                                         g_assert (mono_method_signature (method)->generic_param_count);
2868                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2869                                 }
2870                         }
2871
2872                         call->inst.sreg1 = slot_reg;
2873                         call->inst.inst_offset = offset;
2874                         call->virtual = TRUE;
2875                 }
2876         }
2877
2878         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2879
2880         if (rgctx_arg)
2881                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2882
2883         return (MonoInst*)call;
2884 }
2885
2886 MonoInst*
2887 mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoInst **args, MonoInst *this)
2888 {
2889         return mono_emit_method_call_full (cfg, method, mono_method_signature (method), FALSE, args, this, NULL, NULL);
2890 }
2891
2892 MonoInst*
2893 mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig,
2894                                            MonoInst **args)
2895 {
2896         MonoCallInst *call;
2897
2898         g_assert (sig);
2899
2900         call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE, FALSE, FALSE);
2901         call->fptr = func;
2902
2903         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2904
2905         return (MonoInst*)call;
2906 }
2907
2908 MonoInst*
2909 mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args)
2910 {
2911         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2912
2913         g_assert (info);
2914
2915         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2916 }
2917
2918 /*
2919  * mono_emit_abs_call:
2920  *
2921  *   Emit a call to the runtime function described by PATCH_TYPE and DATA.
2922  */
2923 inline static MonoInst*
2924 mono_emit_abs_call (MonoCompile *cfg, MonoJumpInfoType patch_type, gconstpointer data, 
2925                                         MonoMethodSignature *sig, MonoInst **args)
2926 {
2927         MonoJumpInfo *ji = mono_patch_info_new (cfg->mempool, 0, patch_type, data);
2928         MonoInst *ins;
2929
2930         /* 
2931          * We pass ji as the call address, the PATCH_INFO_ABS resolving code will
2932          * handle it.
2933          */
2934         if (cfg->abs_patches == NULL)
2935                 cfg->abs_patches = g_hash_table_new (NULL, NULL);
2936         g_hash_table_insert (cfg->abs_patches, ji, ji);
2937         ins = mono_emit_native_call (cfg, ji, sig, args);
2938         ((MonoCallInst*)ins)->fptr_is_patch = TRUE;
2939         return ins;
2940 }
2941
2942 static gboolean
2943 direct_icalls_enabled (MonoCompile *cfg)
2944 {
2945         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
2946 #ifdef TARGET_AMD64
2947         if (cfg->compile_llvm)
2948                 return FALSE;
2949 #endif
2950         if (cfg->gen_sdb_seq_points || cfg->disable_direct_icalls)
2951                 return FALSE;
2952         return TRUE;
2953 }
2954
2955 MonoInst*
2956 mono_emit_jit_icall_by_info (MonoCompile *cfg, MonoJitICallInfo *info, MonoInst **args)
2957 {
2958         /*
2959          * Call the jit icall without a wrapper if possible.
2960          * The wrapper is needed for the following reasons:
2961          * - to handle exceptions thrown using mono_raise_exceptions () from the
2962          *   icall function. The EH code needs the lmf frame pushed by the
2963          *   wrapper to be able to unwind back to managed code.
2964          * - to be able to do stack walks for asynchronously suspended
2965          *   threads when debugging.
2966          */
2967         if (info->no_raise && direct_icalls_enabled (cfg)) {
2968                 char *name;
2969                 int costs;
2970
2971                 if (!info->wrapper_method) {
2972                         name = g_strdup_printf ("__icall_wrapper_%s", info->name);
2973                         info->wrapper_method = mono_marshal_get_icall_wrapper (info->sig, name, info->func, TRUE);
2974                         g_free (name);
2975                         mono_memory_barrier ();
2976                 }
2977
2978                 /*
2979                  * Inline the wrapper method, which is basically a call to the C icall, and
2980                  * an exception check.
2981                  */
2982                 costs = inline_method (cfg, info->wrapper_method, NULL,
2983                                                            args, NULL, cfg->real_offset, TRUE);
2984                 g_assert (costs > 0);
2985                 g_assert (!MONO_TYPE_IS_VOID (info->sig->ret));
2986
2987                 return args [0];
2988         } else {
2989                 return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2990         }
2991 }
2992  
2993 static MonoInst*
2994 mono_emit_widen_call_res (MonoCompile *cfg, MonoInst *ins, MonoMethodSignature *fsig)
2995 {
2996         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
2997                 if ((fsig->pinvoke || LLVM_ENABLED) && !fsig->ret->byref) {
2998                         int widen_op = -1;
2999
3000                         /* 
3001                          * Native code might return non register sized integers 
3002                          * without initializing the upper bits.
3003                          */
3004                         switch (mono_type_to_load_membase (cfg, fsig->ret)) {
3005                         case OP_LOADI1_MEMBASE:
3006                                 widen_op = OP_ICONV_TO_I1;
3007                                 break;
3008                         case OP_LOADU1_MEMBASE:
3009                                 widen_op = OP_ICONV_TO_U1;
3010                                 break;
3011                         case OP_LOADI2_MEMBASE:
3012                                 widen_op = OP_ICONV_TO_I2;
3013                                 break;
3014                         case OP_LOADU2_MEMBASE:
3015                                 widen_op = OP_ICONV_TO_U2;
3016                                 break;
3017                         default:
3018                                 break;
3019                         }
3020
3021                         if (widen_op != -1) {
3022                                 int dreg = alloc_preg (cfg);
3023                                 MonoInst *widen;
3024
3025                                 EMIT_NEW_UNALU (cfg, widen, widen_op, dreg, ins->dreg);
3026                                 widen->type = ins->type;
3027                                 ins = widen;
3028                         }
3029                 }
3030         }
3031
3032         return ins;
3033 }
3034
3035 static MonoMethod*
3036 get_memcpy_method (void)
3037 {
3038         static MonoMethod *memcpy_method = NULL;
3039         if (!memcpy_method) {
3040                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
3041                 if (!memcpy_method)
3042                         g_error ("Old corlib found. Install a new one");
3043         }
3044         return memcpy_method;
3045 }
3046
3047 static void
3048 create_write_barrier_bitmap (MonoCompile *cfg, MonoClass *klass, unsigned *wb_bitmap, int offset)
3049 {
3050         MonoClassField *field;
3051         gpointer iter = NULL;
3052
3053         while ((field = mono_class_get_fields (klass, &iter))) {
3054                 int foffset;
3055
3056                 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3057                         continue;
3058                 foffset = klass->valuetype ? field->offset - sizeof (MonoObject): field->offset;
3059                 if (mini_type_is_reference (cfg, mono_field_get_type (field))) {
3060                         g_assert ((foffset % SIZEOF_VOID_P) == 0);
3061                         *wb_bitmap |= 1 << ((offset + foffset) / SIZEOF_VOID_P);
3062                 } else {
3063                         MonoClass *field_class = mono_class_from_mono_type (field->type);
3064                         if (field_class->has_references)
3065                                 create_write_barrier_bitmap (cfg, field_class, wb_bitmap, offset + foffset);
3066                 }
3067         }
3068 }
3069
3070 static void
3071 emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value)
3072 {
3073         int card_table_shift_bits;
3074         gpointer card_table_mask;
3075         guint8 *card_table;
3076         MonoInst *dummy_use;
3077         int nursery_shift_bits;
3078         size_t nursery_size;
3079         gboolean has_card_table_wb = FALSE;
3080
3081         if (!cfg->gen_write_barriers)
3082                 return;
3083
3084         card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
3085
3086         mono_gc_get_nursery (&nursery_shift_bits, &nursery_size);
3087
3088 #ifdef MONO_ARCH_HAVE_CARD_TABLE_WBARRIER
3089         has_card_table_wb = TRUE;
3090 #endif
3091
3092         if (has_card_table_wb && !cfg->compile_aot && card_table && nursery_shift_bits > 0 && !COMPILE_LLVM (cfg)) {
3093                 MonoInst *wbarrier;
3094
3095                 MONO_INST_NEW (cfg, wbarrier, OP_CARD_TABLE_WBARRIER);
3096                 wbarrier->sreg1 = ptr->dreg;
3097                 wbarrier->sreg2 = value->dreg;
3098                 MONO_ADD_INS (cfg->cbb, wbarrier);
3099         } else if (card_table && !cfg->compile_aot && !mono_gc_card_table_nursery_check ()) {
3100                 int offset_reg = alloc_preg (cfg);
3101                 int card_reg  = alloc_preg (cfg);
3102                 MonoInst *ins;
3103
3104                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, offset_reg, ptr->dreg, card_table_shift_bits);
3105                 if (card_table_mask)
3106                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, offset_reg, offset_reg, card_table_mask);
3107
3108                 /*We can't use PADD_IMM since the cardtable might end up in high addresses and amd64 doesn't support
3109                  * IMM's larger than 32bits.
3110                  */
3111                 if (cfg->compile_aot) {
3112                         MONO_EMIT_NEW_AOTCONST (cfg, card_reg, NULL, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR);
3113                 } else {
3114                         MONO_INST_NEW (cfg, ins, OP_PCONST);
3115                         ins->inst_p0 = card_table;
3116                         ins->dreg = card_reg;
3117                         MONO_ADD_INS (cfg->cbb, ins);
3118                 }
3119
3120                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, offset_reg, offset_reg, card_reg);
3121                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, offset_reg, 0, 1);
3122         } else {
3123                 MonoMethod *write_barrier = mono_gc_get_write_barrier ();
3124                 mono_emit_method_call (cfg, write_barrier, &ptr, NULL);
3125         }
3126
3127         EMIT_NEW_DUMMY_USE (cfg, dummy_use, value);
3128 }
3129
3130 static gboolean
3131 mono_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align)
3132 {
3133         int dest_ptr_reg, tmp_reg, destreg, srcreg, offset;
3134         unsigned need_wb = 0;
3135
3136         if (align == 0)
3137                 align = 4;
3138
3139         /*types with references can't have alignment smaller than sizeof(void*) */
3140         if (align < SIZEOF_VOID_P)
3141                 return FALSE;
3142
3143         /*This value cannot be bigger than 32 due to the way we calculate the required wb bitmap.*/
3144         if (size > 32 * SIZEOF_VOID_P)
3145                 return FALSE;
3146
3147         create_write_barrier_bitmap (cfg, klass, &need_wb, 0);
3148
3149         /* We don't unroll more than 5 stores to avoid code bloat. */
3150         if (size > 5 * SIZEOF_VOID_P) {
3151                 /*This is harmless and simplify mono_gc_wbarrier_value_copy_bitmap */
3152                 size += (SIZEOF_VOID_P - 1);
3153                 size &= ~(SIZEOF_VOID_P - 1);
3154
3155                 EMIT_NEW_ICONST (cfg, iargs [2], size);
3156                 EMIT_NEW_ICONST (cfg, iargs [3], need_wb);
3157                 mono_emit_jit_icall (cfg, mono_gc_wbarrier_value_copy_bitmap, iargs);
3158                 return TRUE;
3159         }
3160
3161         destreg = iargs [0]->dreg;
3162         srcreg = iargs [1]->dreg;
3163         offset = 0;
3164
3165         dest_ptr_reg = alloc_preg (cfg);
3166         tmp_reg = alloc_preg (cfg);
3167
3168         /*tmp = dreg*/
3169         EMIT_NEW_UNALU (cfg, iargs [0], OP_MOVE, dest_ptr_reg, destreg);
3170
3171         while (size >= SIZEOF_VOID_P) {
3172                 MonoInst *load_inst;
3173                 MONO_INST_NEW (cfg, load_inst, OP_LOAD_MEMBASE);
3174                 load_inst->dreg = tmp_reg;
3175                 load_inst->inst_basereg = srcreg;
3176                 load_inst->inst_offset = offset;
3177                 MONO_ADD_INS (cfg->cbb, load_inst);
3178
3179                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, dest_ptr_reg, 0, tmp_reg);
3180
3181                 if (need_wb & 0x1)
3182                         emit_write_barrier (cfg, iargs [0], load_inst);
3183
3184                 offset += SIZEOF_VOID_P;
3185                 size -= SIZEOF_VOID_P;
3186                 need_wb >>= 1;
3187
3188                 /*tmp += sizeof (void*)*/
3189                 if (size >= SIZEOF_VOID_P) {
3190                         NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dest_ptr_reg, dest_ptr_reg, SIZEOF_VOID_P);
3191                         MONO_ADD_INS (cfg->cbb, iargs [0]);
3192                 }
3193         }
3194
3195         /* Those cannot be references since size < sizeof (void*) */
3196         while (size >= 4) {
3197                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tmp_reg, srcreg, offset);
3198                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, tmp_reg);
3199                 offset += 4;
3200                 size -= 4;
3201         }
3202
3203         while (size >= 2) {
3204                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmp_reg, srcreg, offset);
3205                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, tmp_reg);
3206                 offset += 2;
3207                 size -= 2;
3208         }
3209
3210         while (size >= 1) {
3211                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmp_reg, srcreg, offset);
3212                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, tmp_reg);
3213                 offset += 1;
3214                 size -= 1;
3215         }
3216
3217         return TRUE;
3218 }
3219
3220 /*
3221  * Emit code to copy a valuetype of type @klass whose address is stored in
3222  * @src->dreg to memory whose address is stored at @dest->dreg.
3223  */
3224 void
3225 mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native)
3226 {
3227         MonoInst *iargs [4];
3228         int n;
3229         guint32 align = 0;
3230         MonoMethod *memcpy_method;
3231         MonoInst *size_ins = NULL;
3232         MonoInst *memcpy_ins = NULL;
3233
3234         g_assert (klass);
3235         if (cfg->generic_sharing_context)
3236                 klass = mono_class_from_mono_type (mini_get_underlying_type (cfg, &klass->byval_arg));
3237
3238         /*
3239          * This check breaks with spilled vars... need to handle it during verification anyway.
3240          * g_assert (klass && klass == src->klass && klass == dest->klass);
3241          */
3242
3243         if (mini_is_gsharedvt_klass (cfg, klass)) {
3244                 g_assert (!native);
3245                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3246                 memcpy_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_MEMCPY);
3247         }
3248
3249         if (native)
3250                 n = mono_class_native_size (klass, &align);
3251         else
3252                 n = mono_class_value_size (klass, &align);
3253
3254         /* if native is true there should be no references in the struct */
3255         if (cfg->gen_write_barriers && (klass->has_references || size_ins) && !native) {
3256                 /* Avoid barriers when storing to the stack */
3257                 if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) ||
3258                           (dest->opcode == OP_LDADDR))) {
3259                         int context_used;
3260
3261                         iargs [0] = dest;
3262                         iargs [1] = src;
3263
3264                         context_used = mini_class_check_context_used (cfg, klass);
3265
3266                         /* It's ok to intrinsify under gsharing since shared code types are layout stable. */
3267                         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && mono_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
3268                                 return;
3269                         } else if (context_used) {
3270                                 iargs [2] = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3271                         }  else {
3272                                 if (cfg->compile_aot) {
3273                                         EMIT_NEW_CLASSCONST (cfg, iargs [2], klass);
3274                                 } else {
3275                                         EMIT_NEW_PCONST (cfg, iargs [2], klass);
3276                                         mono_class_compute_gc_descriptor (klass);
3277                                 }
3278                         }
3279
3280                         if (size_ins)
3281                                 mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs);
3282                         else
3283                                 mono_emit_jit_icall (cfg, mono_value_copy, iargs);
3284                         return;
3285                 }
3286         }
3287
3288         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 8) {
3289                 /* FIXME: Optimize the case when src/dest is OP_LDADDR */
3290                 mini_emit_memcpy (cfg, dest->dreg, 0, src->dreg, 0, n, align);
3291         } else {
3292                 iargs [0] = dest;
3293                 iargs [1] = src;
3294                 if (size_ins)
3295                         iargs [2] = size_ins;
3296                 else
3297                         EMIT_NEW_ICONST (cfg, iargs [2], n);
3298                 
3299                 memcpy_method = get_memcpy_method ();
3300                 if (memcpy_ins)
3301                         mono_emit_calli (cfg, mono_method_signature (memcpy_method), iargs, memcpy_ins, NULL, NULL);
3302                 else
3303                         mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
3304         }
3305 }
3306
3307 static MonoMethod*
3308 get_memset_method (void)
3309 {
3310         static MonoMethod *memset_method = NULL;
3311         if (!memset_method) {
3312                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
3313                 if (!memset_method)
3314                         g_error ("Old corlib found. Install a new one");
3315         }
3316         return memset_method;
3317 }
3318
3319 void
3320 mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass)
3321 {
3322         MonoInst *iargs [3];
3323         int n;
3324         guint32 align;
3325         MonoMethod *memset_method;
3326         MonoInst *size_ins = NULL;
3327         MonoInst *bzero_ins = NULL;
3328         static MonoMethod *bzero_method;
3329
3330         /* FIXME: Optimize this for the case when dest is an LDADDR */
3331         mono_class_init (klass);
3332         if (mini_is_gsharedvt_klass (cfg, klass)) {
3333                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3334                 bzero_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_BZERO);
3335                 if (!bzero_method)
3336                         bzero_method = mono_class_get_method_from_name (mono_defaults.string_class, "bzero_aligned_1", 2);
3337                 g_assert (bzero_method);
3338                 iargs [0] = dest;
3339                 iargs [1] = size_ins;
3340                 mono_emit_calli (cfg, mono_method_signature (bzero_method), iargs, bzero_ins, NULL, NULL);
3341                 return;
3342         }
3343
3344         n = mono_class_value_size (klass, &align);
3345
3346         if (n <= sizeof (gpointer) * 8) {
3347                 mini_emit_memset (cfg, dest->dreg, 0, n, 0, align);
3348         }
3349         else {
3350                 memset_method = get_memset_method ();
3351                 iargs [0] = dest;
3352                 EMIT_NEW_ICONST (cfg, iargs [1], 0);
3353                 EMIT_NEW_ICONST (cfg, iargs [2], n);
3354                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
3355         }
3356 }
3357
3358 /*
3359  * emit_get_rgctx:
3360  *
3361  *   Emit IR to return either the this pointer for instance method,
3362  * or the mrgctx for static methods.
3363  */
3364 static MonoInst*
3365 emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used)
3366 {
3367         MonoInst *this = NULL;
3368
3369         g_assert (cfg->generic_sharing_context);
3370
3371         if (!(method->flags & METHOD_ATTRIBUTE_STATIC) &&
3372                         !(context_used & MONO_GENERIC_CONTEXT_USED_METHOD) &&
3373                         !method->klass->valuetype)
3374                 EMIT_NEW_ARGLOAD (cfg, this, 0);
3375
3376         if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
3377                 MonoInst *mrgctx_loc, *mrgctx_var;
3378
3379                 g_assert (!this);
3380                 g_assert (method->is_inflated && mono_method_get_context (method)->method_inst);
3381
3382                 mrgctx_loc = mono_get_vtable_var (cfg);
3383                 EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
3384
3385                 return mrgctx_var;
3386         } else if (method->flags & METHOD_ATTRIBUTE_STATIC || method->klass->valuetype) {
3387                 MonoInst *vtable_loc, *vtable_var;
3388
3389                 g_assert (!this);
3390
3391                 vtable_loc = mono_get_vtable_var (cfg);
3392                 EMIT_NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
3393
3394                 if (method->is_inflated && mono_method_get_context (method)->method_inst) {
3395                         MonoInst *mrgctx_var = vtable_var;
3396                         int vtable_reg;
3397
3398                         vtable_reg = alloc_preg (cfg);
3399                         EMIT_NEW_LOAD_MEMBASE (cfg, vtable_var, OP_LOAD_MEMBASE, vtable_reg, mrgctx_var->dreg, MONO_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, class_vtable));
3400                         vtable_var->type = STACK_PTR;
3401                 }
3402
3403                 return vtable_var;
3404         } else {
3405                 MonoInst *ins;
3406                 int vtable_reg;
3407         
3408                 vtable_reg = alloc_preg (cfg);
3409                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, vtable_reg, this->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3410                 return ins;
3411         }
3412 }
3413
3414 static MonoJumpInfoRgctxEntry *
3415 mono_patch_info_rgctx_entry_new (MonoMemPool *mp, MonoMethod *method, gboolean in_mrgctx, MonoJumpInfoType patch_type, gconstpointer patch_data, MonoRgctxInfoType info_type)
3416 {
3417         MonoJumpInfoRgctxEntry *res = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoRgctxEntry));
3418         res->method = method;
3419         res->in_mrgctx = in_mrgctx;
3420         res->data = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
3421         res->data->type = patch_type;
3422         res->data->data.target = patch_data;
3423         res->info_type = info_type;
3424
3425         return res;
3426 }
3427
3428 /*
3429  * emit_rgctx_fetch:
3430  *
3431  *   Emit IR to load the value of the rgctx entry ENTRY from the rgctx
3432  * given by RGCTX.
3433  */
3434 static inline MonoInst*
3435 emit_rgctx_fetch (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3436 {
3437         /* Inline version, not currently used */
3438         // FIXME: This can be called from mono_decompose_vtype_opts (), which can't create new bblocks
3439 #if 0
3440         int i, slot, depth, index, rgctx_reg, val_reg, res_reg;
3441         gboolean mrgctx;
3442         MonoBasicBlock *is_null_bb, *end_bb;
3443         MonoInst *res, *ins, *call;
3444         MonoInst *args[16];
3445
3446         slot = mini_get_rgctx_entry_slot (entry);
3447
3448         mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot);
3449         index = MONO_RGCTX_SLOT_INDEX (slot);
3450         if (mrgctx)
3451                 index += MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
3452         for (depth = 0; ; ++depth) {
3453                 int size = mono_class_rgctx_get_array_size (depth, mrgctx);
3454
3455                 if (index < size - 1)
3456                         break;
3457                 index -= size - 1;
3458         }
3459
3460         NEW_BBLOCK (cfg, end_bb);
3461         NEW_BBLOCK (cfg, is_null_bb);
3462
3463         if (mrgctx) {
3464                 rgctx_reg = rgctx->dreg;
3465         } else {
3466                 rgctx_reg = alloc_preg (cfg);
3467
3468                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, rgctx_reg, rgctx->dreg, MONO_STRUCT_OFFSET (MonoVTable, runtime_generic_context));
3469                 // FIXME: Avoid this check by allocating the table when the vtable is created etc.
3470                 NEW_BBLOCK (cfg, is_null_bb);
3471
3472                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3473                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3474         }
3475
3476         for (i = 0; i < depth; ++i) {
3477                 int array_reg = alloc_preg (cfg);
3478
3479                 /* load ptr to next array */
3480                 if (mrgctx && i == 0)
3481                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT);
3482                 else
3483                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, 0);
3484                 rgctx_reg = array_reg;
3485                 /* is the ptr null? */
3486                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3487                 /* if yes, jump to actual trampoline */
3488                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3489         }
3490
3491         /* fetch slot */
3492         val_reg = alloc_preg (cfg);
3493         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, val_reg, rgctx_reg, (index + 1) * sizeof (gpointer));
3494         /* is the slot null? */
3495         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, val_reg, 0);
3496         /* if yes, jump to actual trampoline */
3497         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3498
3499         /* Fastpath */
3500         res_reg = alloc_preg (cfg);
3501         MONO_INST_NEW (cfg, ins, OP_MOVE);
3502         ins->dreg = res_reg;
3503         ins->sreg1 = val_reg;
3504         MONO_ADD_INS (cfg->cbb, ins);
3505         res = ins;
3506         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3507
3508         /* Slowpath */
3509         MONO_START_BB (cfg, is_null_bb);
3510         args [0] = rgctx;
3511         EMIT_NEW_ICONST (cfg, args [1], index);
3512         if (mrgctx)
3513                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3514         else
3515                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3516         MONO_INST_NEW (cfg, ins, OP_MOVE);
3517         ins->dreg = res_reg;
3518         ins->sreg1 = call->dreg;
3519         MONO_ADD_INS (cfg->cbb, ins);
3520         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3521
3522         MONO_START_BB (cfg, end_bb);
3523
3524         return res;
3525 #else
3526         return mono_emit_abs_call (cfg, MONO_PATCH_INFO_RGCTX_FETCH, entry, helper_sig_rgctx_lazy_fetch_trampoline, &rgctx);
3527 #endif
3528 }
3529
3530 static MonoInst*
3531 emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
3532                                           MonoClass *klass, MonoRgctxInfoType rgctx_type)
3533 {
3534         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);
3535         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3536
3537         return emit_rgctx_fetch (cfg, rgctx, entry);
3538 }
3539
3540 static MonoInst*
3541 emit_get_rgctx_sig (MonoCompile *cfg, int context_used,
3542                                         MonoMethodSignature *sig, MonoRgctxInfoType rgctx_type)
3543 {
3544         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);
3545         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3546
3547         return emit_rgctx_fetch (cfg, rgctx, entry);
3548 }
3549
3550 static MonoInst*
3551 emit_get_rgctx_gsharedvt_call (MonoCompile *cfg, int context_used,
3552                                                            MonoMethodSignature *sig, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3553 {
3554         MonoJumpInfoGSharedVtCall *call_info;
3555         MonoJumpInfoRgctxEntry *entry;
3556         MonoInst *rgctx;
3557
3558         call_info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoGSharedVtCall));
3559         call_info->sig = sig;
3560         call_info->method = cmethod;
3561
3562         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);
3563         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3564
3565         return emit_rgctx_fetch (cfg, rgctx, entry);
3566 }
3567
3568 /*
3569  * emit_get_rgctx_virt_method:
3570  *
3571  *   Return data for method VIRT_METHOD for a receiver of type KLASS.
3572  */
3573 static MonoInst*
3574 emit_get_rgctx_virt_method (MonoCompile *cfg, int context_used,
3575                                                         MonoClass *klass, MonoMethod *virt_method, MonoRgctxInfoType rgctx_type)
3576 {
3577         MonoJumpInfoVirtMethod *info;
3578         MonoJumpInfoRgctxEntry *entry;
3579         MonoInst *rgctx;
3580
3581         info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoVirtMethod));
3582         info->klass = klass;
3583         info->method = virt_method;
3584
3585         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);
3586         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3587
3588         return emit_rgctx_fetch (cfg, rgctx, entry);
3589 }
3590
3591 static MonoInst*
3592 emit_get_rgctx_gsharedvt_method (MonoCompile *cfg, int context_used,
3593                                                                  MonoMethod *cmethod, MonoGSharedVtMethodInfo *info)
3594 {
3595         MonoJumpInfoRgctxEntry *entry;
3596         MonoInst *rgctx;
3597
3598         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);
3599         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3600
3601         return emit_rgctx_fetch (cfg, rgctx, entry);
3602 }
3603
3604 /*
3605  * emit_get_rgctx_method:
3606  *
3607  *   Emit IR to load the property RGCTX_TYPE of CMETHOD. If context_used is 0, emit
3608  * normal constants, else emit a load from the rgctx.
3609  */
3610 static MonoInst*
3611 emit_get_rgctx_method (MonoCompile *cfg, int context_used,
3612                                            MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3613 {
3614         if (!context_used) {
3615                 MonoInst *ins;
3616
3617                 switch (rgctx_type) {
3618                 case MONO_RGCTX_INFO_METHOD:
3619                         EMIT_NEW_METHODCONST (cfg, ins, cmethod);
3620                         return ins;
3621                 case MONO_RGCTX_INFO_METHOD_RGCTX:
3622                         EMIT_NEW_METHOD_RGCTX_CONST (cfg, ins, cmethod);
3623                         return ins;
3624                 default:
3625                         g_assert_not_reached ();
3626                 }
3627         } else {
3628                 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);
3629                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3630
3631                 return emit_rgctx_fetch (cfg, rgctx, entry);
3632         }
3633 }
3634
3635 static MonoInst*
3636 emit_get_rgctx_field (MonoCompile *cfg, int context_used,
3637                                           MonoClassField *field, MonoRgctxInfoType rgctx_type)
3638 {
3639         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);
3640         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3641
3642         return emit_rgctx_fetch (cfg, rgctx, entry);
3643 }
3644
3645 static int
3646 get_gsharedvt_info_slot (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3647 {
3648         MonoGSharedVtMethodInfo *info = cfg->gsharedvt_info;
3649         MonoRuntimeGenericContextInfoTemplate *template;
3650         int i, idx;
3651
3652         g_assert (info);
3653
3654         for (i = 0; i < info->num_entries; ++i) {
3655                 MonoRuntimeGenericContextInfoTemplate *otemplate = &info->entries [i];
3656
3657                 if (otemplate->info_type == rgctx_type && otemplate->data == data && rgctx_type != MONO_RGCTX_INFO_LOCAL_OFFSET)
3658                         return i;
3659         }
3660
3661         if (info->num_entries == info->count_entries) {
3662                 MonoRuntimeGenericContextInfoTemplate *new_entries;
3663                 int new_count_entries = info->count_entries ? info->count_entries * 2 : 16;
3664
3665                 new_entries = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * new_count_entries);
3666
3667                 memcpy (new_entries, info->entries, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
3668                 info->entries = new_entries;
3669                 info->count_entries = new_count_entries;
3670         }
3671
3672         idx = info->num_entries;
3673         template = &info->entries [idx];
3674         template->info_type = rgctx_type;
3675         template->data = data;
3676
3677         info->num_entries ++;
3678
3679         return idx;
3680 }
3681
3682 /*
3683  * emit_get_gsharedvt_info:
3684  *
3685  *   This is similar to emit_get_rgctx_.., but loads the data from the gsharedvt info var instead of calling an rgctx fetch trampoline.
3686  */
3687 static MonoInst*
3688 emit_get_gsharedvt_info (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3689 {
3690         MonoInst *ins;
3691         int idx, dreg;
3692
3693         idx = get_gsharedvt_info_slot (cfg, data, rgctx_type);
3694         /* Load info->entries [idx] */
3695         dreg = alloc_preg (cfg);
3696         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, cfg->gsharedvt_info_var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
3697
3698         return ins;
3699 }
3700
3701 static MonoInst*
3702 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type)
3703 {
3704         return emit_get_gsharedvt_info (cfg, &klass->byval_arg, rgctx_type);
3705 }
3706
3707 /*
3708  * On return the caller must check @klass for load errors.
3709  */
3710 static void
3711 emit_generic_class_init (MonoCompile *cfg, MonoClass *klass)
3712 {
3713         MonoInst *vtable_arg;
3714         int context_used;
3715         gboolean use_op_generic_class_init = FALSE;
3716
3717         context_used = mini_class_check_context_used (cfg, klass);
3718
3719         if (context_used) {
3720                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
3721                                                                                    klass, MONO_RGCTX_INFO_VTABLE);
3722         } else {
3723                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3724
3725                 if (!vtable)
3726                         return;
3727                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
3728         }
3729
3730 #ifdef MONO_ARCH_HAVE_OP_GENERIC_CLASS_INIT
3731         if (!COMPILE_LLVM (cfg))
3732                 use_op_generic_class_init = TRUE;
3733 #endif
3734
3735         if (use_op_generic_class_init) {
3736                 MonoInst *ins;
3737
3738                 /*
3739                  * Using an opcode instead of emitting IR here allows the hiding of the call inside the opcode,
3740                  * so this doesn't have to clobber any regs and it doesn't break basic blocks.
3741                  */
3742                 MONO_INST_NEW (cfg, ins, OP_GENERIC_CLASS_INIT);
3743                 ins->sreg1 = vtable_arg->dreg;
3744                 MONO_ADD_INS (cfg->cbb, ins);
3745         } else {
3746                 static int byte_offset = -1;
3747                 static guint8 bitmask;
3748                 int bits_reg, inited_reg;
3749                 MonoBasicBlock *inited_bb;
3750                 MonoInst *args [16];
3751
3752                 if (byte_offset < 0)
3753                         mono_marshal_find_bitfield_offset (MonoVTable, initialized, &byte_offset, &bitmask);
3754
3755                 bits_reg = alloc_ireg (cfg);
3756                 inited_reg = alloc_ireg (cfg);
3757
3758                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, bits_reg, vtable_arg->dreg, byte_offset);
3759                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, inited_reg, bits_reg, bitmask);
3760
3761                 NEW_BBLOCK (cfg, inited_bb);
3762
3763                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, inited_reg, 0);
3764                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, inited_bb);
3765
3766                 args [0] = vtable_arg;
3767                 mono_emit_jit_icall (cfg, mono_generic_class_init, args);
3768
3769                 MONO_START_BB (cfg, inited_bb);
3770         }
3771 }
3772
3773
3774 static void
3775 emit_class_init (MonoCompile *cfg, MonoClass *klass)
3776 {
3777         /* This could be used as a fallback if needed */
3778         if (cfg->compile_aot) {
3779                 /* With the overhead of plt entries, the inline version is comparable in size/speed */
3780                 emit_generic_class_init (cfg, klass);
3781                 return;
3782         }
3783
3784         mono_emit_abs_call (cfg, MONO_PATCH_INFO_CLASS_INIT, klass, helper_sig_class_init_trampoline, NULL);
3785 }
3786
3787 static void
3788 emit_seq_point (MonoCompile *cfg, MonoMethod *method, guint8* ip, gboolean intr_loc, gboolean nonempty_stack)
3789 {
3790         MonoInst *ins;
3791
3792         if (cfg->gen_seq_points && cfg->method == method) {
3793                 NEW_SEQ_POINT (cfg, ins, ip - cfg->header->code, intr_loc);
3794                 if (nonempty_stack)
3795                         ins->flags |= MONO_INST_NONEMPTY_STACK;
3796                 MONO_ADD_INS (cfg->cbb, ins);
3797         }
3798 }
3799
3800 static void
3801 save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean null_check)
3802 {
3803         if (mini_get_debug_options ()->better_cast_details) {
3804                 int vtable_reg = alloc_preg (cfg);
3805                 int klass_reg = alloc_preg (cfg);
3806                 MonoBasicBlock *is_null_bb = NULL;
3807                 MonoInst *tls_get;
3808                 int to_klass_reg, context_used;
3809
3810                 if (null_check) {
3811                         NEW_BBLOCK (cfg, is_null_bb);
3812
3813                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3814                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3815                 }
3816
3817                 tls_get = mono_get_jit_tls_intrinsic (cfg);
3818                 if (!tls_get) {
3819                         fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
3820                         exit (1);
3821                 }
3822
3823                 MONO_ADD_INS (cfg->cbb, tls_get);
3824                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3825                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3826
3827                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg);
3828
3829                 context_used = mini_class_check_context_used (cfg, klass);
3830                 if (context_used) {
3831                         MonoInst *class_ins;
3832
3833                         class_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3834                         to_klass_reg = class_ins->dreg;
3835                 } else {
3836                         to_klass_reg = alloc_preg (cfg);
3837                         MONO_EMIT_NEW_CLASSCONST (cfg, to_klass_reg, klass);
3838                 }
3839                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg);
3840
3841                 if (null_check)
3842                         MONO_START_BB (cfg, is_null_bb);
3843         }
3844 }
3845
3846 static void
3847 reset_cast_details (MonoCompile *cfg)
3848 {
3849         /* Reset the variables holding the cast details */
3850         if (mini_get_debug_options ()->better_cast_details) {
3851                 MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
3852
3853                 MONO_ADD_INS (cfg->cbb, tls_get);
3854                 /* It is enough to reset the from field */
3855                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0);
3856         }
3857 }
3858
3859 /*
3860  * On return the caller must check @array_class for load errors
3861  */
3862 static void
3863 mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_class)
3864 {
3865         int vtable_reg = alloc_preg (cfg);
3866         int context_used;
3867
3868         context_used = mini_class_check_context_used (cfg, array_class);
3869
3870         save_cast_details (cfg, array_class, obj->dreg, FALSE);
3871
3872         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3873
3874         if (cfg->opt & MONO_OPT_SHARED) {
3875                 int class_reg = alloc_preg (cfg);
3876                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, class_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3877                 if (cfg->compile_aot) {
3878                         int klass_reg = alloc_preg (cfg);
3879                         MONO_EMIT_NEW_CLASSCONST (cfg, klass_reg, array_class);
3880                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, class_reg, klass_reg);
3881                 } else {
3882                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, class_reg, array_class);
3883                 }
3884         } else if (context_used) {
3885                 MonoInst *vtable_ins;
3886
3887                 vtable_ins = emit_get_rgctx_klass (cfg, context_used, array_class, MONO_RGCTX_INFO_VTABLE);
3888                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vtable_ins->dreg);
3889         } else {
3890                 if (cfg->compile_aot) {
3891                         int vt_reg;
3892                         MonoVTable *vtable;
3893
3894                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3895                                 return;
3896                         vt_reg = alloc_preg (cfg);
3897                         MONO_EMIT_NEW_VTABLECONST (cfg, vt_reg, vtable);
3898                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vt_reg);
3899                 } else {
3900                         MonoVTable *vtable;
3901                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3902                                 return;
3903                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vtable);
3904                 }
3905         }
3906         
3907         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException");
3908
3909         reset_cast_details (cfg);
3910 }
3911
3912 /**
3913  * Handles unbox of a Nullable<T>. If context_used is non zero, then shared 
3914  * generic code is generated.
3915  */
3916 static MonoInst*
3917 handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int context_used)
3918 {
3919         MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
3920
3921         if (context_used) {
3922                 MonoInst *rgctx, *addr;
3923
3924                 /* FIXME: What if the class is shared?  We might not
3925                    have to get the address of the method from the
3926                    RGCTX. */
3927                 addr = emit_get_rgctx_method (cfg, context_used, method,
3928                                                                           MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
3929
3930                 rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3931
3932                 return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
3933         } else {
3934                 gboolean pass_vtable, pass_mrgctx;
3935                 MonoInst *rgctx_arg = NULL;
3936
3937                 check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
3938                 g_assert (!pass_mrgctx);
3939
3940                 if (pass_vtable) {
3941                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
3942
3943                         g_assert (vtable);
3944                         EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
3945                 }
3946
3947                 return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
3948         }
3949 }
3950
3951 static MonoInst*
3952 handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_used)
3953 {
3954         MonoInst *add;
3955         int obj_reg;
3956         int vtable_reg = alloc_dreg (cfg ,STACK_PTR);
3957         int klass_reg = alloc_dreg (cfg ,STACK_PTR);
3958         int eclass_reg = alloc_dreg (cfg ,STACK_PTR);
3959         int rank_reg = alloc_dreg (cfg ,STACK_I4);
3960
3961         obj_reg = sp [0]->dreg;
3962         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3963         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
3964
3965         /* FIXME: generics */
3966         g_assert (klass->rank == 0);
3967                         
3968         // Check rank == 0
3969         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, 0);
3970         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3971
3972         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3973         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, element_class));
3974
3975         if (context_used) {
3976                 MonoInst *element_class;
3977
3978                 /* This assertion is from the unboxcast insn */
3979                 g_assert (klass->rank == 0);
3980
3981                 element_class = emit_get_rgctx_klass (cfg, context_used,
3982                                 klass, MONO_RGCTX_INFO_ELEMENT_KLASS);
3983
3984                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, eclass_reg, element_class->dreg);
3985                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3986         } else {
3987                 save_cast_details (cfg, klass->element_class, obj_reg, FALSE);
3988                 mini_emit_class_check (cfg, eclass_reg, klass->element_class);
3989                 reset_cast_details (cfg);
3990         }
3991
3992         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), obj_reg, sizeof (MonoObject));
3993         MONO_ADD_INS (cfg->cbb, add);
3994         add->type = STACK_MP;
3995         add->klass = klass;
3996
3997         return add;
3998 }
3999
4000 static MonoInst*
4001 handle_unbox_gsharedvt (MonoCompile *cfg, MonoClass *klass, MonoInst *obj)
4002 {
4003         MonoInst *addr, *klass_inst, *is_ref, *args[16];
4004         MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4005         MonoInst *ins;
4006         int dreg, addr_reg;
4007
4008         klass_inst = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_KLASS);
4009
4010         /* obj */
4011         args [0] = obj;
4012
4013         /* klass */
4014         args [1] = klass_inst;
4015
4016         /* CASTCLASS */
4017         obj = mono_emit_jit_icall (cfg, mono_object_castclass_unbox, args);
4018
4019         NEW_BBLOCK (cfg, is_ref_bb);
4020         NEW_BBLOCK (cfg, is_nullable_bb);
4021         NEW_BBLOCK (cfg, end_bb);
4022         is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4023         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 1);
4024         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4025
4026         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 2);
4027         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4028
4029         /* This will contain either the address of the unboxed vtype, or an address of the temporary where the ref is stored */
4030         addr_reg = alloc_dreg (cfg, STACK_MP);
4031
4032         /* Non-ref case */
4033         /* UNBOX */
4034         NEW_BIALU_IMM (cfg, addr, OP_ADD_IMM, addr_reg, obj->dreg, sizeof (MonoObject));
4035         MONO_ADD_INS (cfg->cbb, addr);
4036
4037         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4038
4039         /* Ref case */
4040         MONO_START_BB (cfg, is_ref_bb);
4041
4042         /* Save the ref to a temporary */
4043         dreg = alloc_ireg (cfg);
4044         EMIT_NEW_VARLOADA_VREG (cfg, addr, dreg, &klass->byval_arg);
4045         addr->dreg = addr_reg;
4046         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, obj->dreg);
4047         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4048
4049         /* Nullable case */
4050         MONO_START_BB (cfg, is_nullable_bb);
4051
4052         {
4053                 MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX);
4054                 MonoInst *unbox_call;
4055                 MonoMethodSignature *unbox_sig;
4056
4057                 unbox_sig = mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4058                 unbox_sig->ret = &klass->byval_arg;
4059                 unbox_sig->param_count = 1;
4060                 unbox_sig->params [0] = &mono_defaults.object_class->byval_arg;
4061                 unbox_call = mono_emit_calli (cfg, unbox_sig, &obj, addr, NULL, NULL);
4062
4063                 EMIT_NEW_VARLOADA_VREG (cfg, addr, unbox_call->dreg, &klass->byval_arg);
4064                 addr->dreg = addr_reg;
4065         }
4066
4067         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4068
4069         /* End */
4070         MONO_START_BB (cfg, end_bb);
4071
4072         /* LDOBJ */
4073         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr_reg, 0);
4074
4075         return ins;
4076 }
4077
4078 /*
4079  * Returns NULL and set the cfg exception on error.
4080  */
4081 static MonoInst*
4082 handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_used)
4083 {
4084         MonoInst *iargs [2];
4085         void *alloc_ftn;
4086
4087         if (context_used) {
4088                 MonoInst *data;
4089                 int rgctx_info;
4090                 MonoInst *iargs [2];
4091                 gboolean known_instance_size = !mini_is_gsharedvt_klass (cfg, klass);
4092
4093                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (klass, for_box, known_instance_size);
4094
4095                 if (cfg->opt & MONO_OPT_SHARED)
4096                         rgctx_info = MONO_RGCTX_INFO_KLASS;
4097                 else
4098                         rgctx_info = MONO_RGCTX_INFO_VTABLE;
4099                 data = emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
4100
4101                 if (cfg->opt & MONO_OPT_SHARED) {
4102                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4103                         iargs [1] = data;
4104                         alloc_ftn = mono_object_new;
4105                 } else {
4106                         iargs [0] = data;
4107                         alloc_ftn = mono_object_new_specific;
4108                 }
4109
4110                 if (managed_alloc && !(cfg->opt & MONO_OPT_SHARED)) {
4111                         if (known_instance_size) {
4112                                 int size = mono_class_instance_size (klass);
4113                                 if (size < sizeof (MonoObject))
4114                                         g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4115
4116                                 EMIT_NEW_ICONST (cfg, iargs [1], mono_gc_get_aligned_size_for_allocator (size));
4117                         }
4118                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4119                 }
4120
4121                 return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4122         }
4123
4124         if (cfg->opt & MONO_OPT_SHARED) {
4125                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4126                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
4127
4128                 alloc_ftn = mono_object_new;
4129         } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !klass->generic_class) {
4130                 /* This happens often in argument checking code, eg. throw new FooException... */
4131                 /* Avoid relocations and save some space by calling a helper function specialized to mscorlib */
4132                 EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
4133                 return mono_emit_jit_icall (cfg, mono_helper_newobj_mscorlib, iargs);
4134         } else {
4135                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
4136                 MonoMethod *managed_alloc = NULL;
4137                 gboolean pass_lw;
4138
4139                 if (!vtable) {
4140                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4141                         cfg->exception_ptr = klass;
4142                         return NULL;
4143                 }
4144
4145                 managed_alloc = mono_gc_get_managed_allocator (klass, for_box, TRUE);
4146
4147                 if (managed_alloc) {
4148                         int size = mono_class_instance_size (klass);
4149                         if (size < sizeof (MonoObject))
4150                                 g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4151
4152                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4153                         EMIT_NEW_ICONST (cfg, iargs [1], mono_gc_get_aligned_size_for_allocator (size));
4154                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4155                 }
4156                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
4157                 if (pass_lw) {
4158                         guint32 lw = vtable->klass->instance_size;
4159                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
4160                         EMIT_NEW_ICONST (cfg, iargs [0], lw);
4161                         EMIT_NEW_VTABLECONST (cfg, iargs [1], vtable);
4162                 }
4163                 else {
4164                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4165                 }
4166         }
4167
4168         return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4169 }
4170         
4171 /*
4172  * Returns NULL and set the cfg exception on error.
4173  */     
4174 static MonoInst*
4175 handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used)
4176 {
4177         MonoInst *alloc, *ins;
4178
4179         if (mono_class_is_nullable (klass)) {
4180                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
4181
4182                 if (context_used) {
4183                         /* FIXME: What if the class is shared?  We might not
4184                            have to get the method address from the RGCTX. */
4185                         MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4186                                                                                                         MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4187                         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
4188
4189                         return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
4190                 } else {
4191                         gboolean pass_vtable, pass_mrgctx;
4192                         MonoInst *rgctx_arg = NULL;
4193
4194                         check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
4195                         g_assert (!pass_mrgctx);
4196
4197                         if (pass_vtable) {
4198                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4199
4200                                 g_assert (vtable);
4201                                 EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
4202                         }
4203
4204                         return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4205                 }
4206         }
4207
4208         if (mini_is_gsharedvt_klass (cfg, klass)) {
4209                 MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4210                 MonoInst *res, *is_ref, *src_var, *addr;
4211                 int dreg;
4212
4213                 dreg = alloc_ireg (cfg);
4214
4215                 NEW_BBLOCK (cfg, is_ref_bb);
4216                 NEW_BBLOCK (cfg, is_nullable_bb);
4217                 NEW_BBLOCK (cfg, end_bb);
4218                 is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4219                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 1);
4220                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4221
4222                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 2);
4223                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4224
4225                 /* Non-ref case */
4226                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4227                 if (!alloc)
4228                         return NULL;
4229                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4230                 ins->opcode = OP_STOREV_MEMBASE;
4231
4232                 EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, alloc->dreg);
4233                 res->type = STACK_OBJ;
4234                 res->klass = klass;
4235                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4236                 
4237                 /* Ref case */
4238                 MONO_START_BB (cfg, is_ref_bb);
4239
4240                 /* val is a vtype, so has to load the value manually */
4241                 src_var = get_vreg_to_inst (cfg, val->dreg);
4242                 if (!src_var)
4243                         src_var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, val->dreg);
4244                 EMIT_NEW_VARLOADA (cfg, addr, src_var, src_var->inst_vtype);
4245                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, addr->dreg, 0);
4246                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4247
4248                 /* Nullable case */
4249                 MONO_START_BB (cfg, is_nullable_bb);
4250
4251                 {
4252                         MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass,
4253                                                                                                         MONO_RGCTX_INFO_NULLABLE_CLASS_BOX);
4254                         MonoInst *box_call;
4255                         MonoMethodSignature *box_sig;
4256
4257                         /*
4258                          * klass is Nullable<T>, need to call Nullable<T>.Box () using a gsharedvt signature, but we cannot
4259                          * construct that method at JIT time, so have to do things by hand.
4260                          */
4261                         box_sig = mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4262                         box_sig->ret = &mono_defaults.object_class->byval_arg;
4263                         box_sig->param_count = 1;
4264                         box_sig->params [0] = &klass->byval_arg;
4265                         box_call = mono_emit_calli (cfg, box_sig, &val, addr, NULL, NULL);
4266                         EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, box_call->dreg);
4267                         res->type = STACK_OBJ;
4268                         res->klass = klass;
4269                 }
4270
4271                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4272
4273                 MONO_START_BB (cfg, end_bb);
4274
4275                 return res;
4276         } else {
4277                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4278                 if (!alloc)
4279                         return NULL;
4280
4281                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4282                 return alloc;
4283         }
4284 }
4285
4286 static gboolean
4287 mini_class_has_reference_variant_generic_argument (MonoCompile *cfg, MonoClass *klass, int context_used)
4288 {
4289         int i;
4290         MonoGenericContainer *container;
4291         MonoGenericInst *ginst;
4292
4293         if (klass->generic_class) {
4294                 container = klass->generic_class->container_class->generic_container;
4295                 ginst = klass->generic_class->context.class_inst;
4296         } else if (klass->generic_container && context_used) {
4297                 container = klass->generic_container;
4298                 ginst = container->context.class_inst;
4299         } else {
4300                 return FALSE;
4301         }
4302
4303         for (i = 0; i < container->type_argc; ++i) {
4304                 MonoType *type;
4305                 if (!(mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT)))
4306                         continue;
4307                 type = ginst->type_argv [i];
4308                 if (mini_type_is_reference (cfg, type))
4309                         return TRUE;
4310         }
4311         return FALSE;
4312 }
4313
4314 static GHashTable* direct_icall_type_hash;
4315
4316 static gboolean
4317 icall_is_direct_callable (MonoCompile *cfg, MonoMethod *cmethod)
4318 {
4319         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
4320         if (!direct_icalls_enabled (cfg))
4321                 return FALSE;
4322
4323         /*
4324          * An icall is directly callable if it doesn't directly or indirectly call mono_raise_exception ().
4325          * Whitelist a few icalls for now.
4326          */
4327         if (!direct_icall_type_hash) {
4328                 GHashTable *h = g_hash_table_new (g_str_hash, g_str_equal);
4329
4330                 g_hash_table_insert (h, (char*)"Decimal", GUINT_TO_POINTER (1));
4331                 g_hash_table_insert (h, (char*)"Number", GUINT_TO_POINTER (1));
4332                 g_hash_table_insert (h, (char*)"Buffer", GUINT_TO_POINTER (1));
4333                 mono_memory_barrier ();
4334                 direct_icall_type_hash = h;
4335         }
4336
4337         if (cmethod->klass == mono_defaults.math_class)
4338                 return TRUE;
4339         /* No locking needed */
4340         if (cmethod->klass->image == mono_defaults.corlib && g_hash_table_lookup (direct_icall_type_hash, cmethod->klass->name))
4341                 return TRUE;
4342         return FALSE;
4343 }
4344
4345 #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)
4346
4347 static MonoInst*
4348 emit_castclass_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args)
4349 {
4350         MonoMethod *mono_castclass;
4351         MonoInst *res;
4352
4353         mono_castclass = mono_marshal_get_castclass_with_cache ();
4354
4355         save_cast_details (cfg, klass, args [0]->dreg, TRUE);
4356         res = mono_emit_method_call (cfg, mono_castclass, args, NULL);
4357         reset_cast_details (cfg);
4358
4359         return res;
4360 }
4361
4362 static int
4363 get_castclass_cache_idx (MonoCompile *cfg)
4364 {
4365         /* Each CASTCLASS_CACHE patch needs a unique index which identifies the call site */
4366         cfg->castclass_cache_index ++;
4367         return (cfg->method_index << 16) | cfg->castclass_cache_index;
4368 }
4369
4370 static MonoInst*
4371 emit_castclass_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass *klass)
4372 {
4373         MonoInst *args [3];
4374         int idx;
4375
4376         /* obj */
4377         args [0] = obj;
4378
4379         /* klass */
4380         EMIT_NEW_CLASSCONST (cfg, args [1], klass);
4381
4382         /* inline cache*/
4383         if (cfg->compile_aot) {
4384                 idx = get_castclass_cache_idx (cfg);
4385                 EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
4386         } else {
4387                 EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
4388         }
4389
4390         /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
4391         return emit_castclass_with_cache (cfg, klass, args);
4392 }
4393
4394 /*
4395  * Returns NULL and set the cfg exception on error.
4396  */
4397 static MonoInst*
4398 handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, guint8 *ip, int *inline_costs)
4399 {
4400         MonoBasicBlock *is_null_bb;
4401         int obj_reg = src->dreg;
4402         int vtable_reg = alloc_preg (cfg);
4403         int context_used;
4404         MonoInst *klass_inst = NULL, *res;
4405
4406         context_used = mini_class_check_context_used (cfg, klass);
4407
4408         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
4409                 res = emit_castclass_with_cache_nonshared (cfg, src, klass);
4410                 (*inline_costs) += 2;
4411                 return res;
4412         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
4413                 MonoMethod *mono_castclass;
4414                 MonoInst *iargs [1];
4415                 int costs;
4416
4417                 mono_castclass = mono_marshal_get_castclass (klass); 
4418                 iargs [0] = src;
4419                                 
4420                 save_cast_details (cfg, klass, src->dreg, TRUE);
4421                 costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
4422                                                            iargs, ip, cfg->real_offset, TRUE);
4423                 reset_cast_details (cfg);
4424                 CHECK_CFG_EXCEPTION;
4425                 g_assert (costs > 0);
4426                                 
4427                 cfg->real_offset += 5;
4428
4429                 (*inline_costs) += costs;
4430
4431                 return src;
4432         }
4433
4434         if (context_used) {
4435                 MonoInst *args [3];
4436
4437                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4438                         MonoInst *cache_ins;
4439
4440                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4441
4442                         /* obj */
4443                         args [0] = src;
4444
4445                         /* klass - it's the second element of the cache entry*/
4446                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4447
4448                         /* cache */
4449                         args [2] = cache_ins;
4450
4451                         return emit_castclass_with_cache (cfg, klass, args);
4452                 }
4453
4454                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4455         }
4456
4457         NEW_BBLOCK (cfg, is_null_bb);
4458
4459         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4460         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
4461
4462         save_cast_details (cfg, klass, obj_reg, FALSE);
4463
4464         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4465                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4466                 mini_emit_iface_cast (cfg, vtable_reg, klass, NULL, NULL);
4467         } else {
4468                 int klass_reg = alloc_preg (cfg);
4469
4470                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4471
4472                 if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4473                         /* the remoting code is broken, access the class for now */
4474                         if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4475                                 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4476                                 if (!vt) {
4477                                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4478                                         cfg->exception_ptr = klass;
4479                                         return NULL;
4480                                 }
4481                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4482                         } else {
4483                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4484                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4485                         }
4486                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4487                 } else {
4488                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4489                         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, klass_inst, is_null_bb);
4490                 }
4491         }
4492
4493         MONO_START_BB (cfg, is_null_bb);
4494
4495         reset_cast_details (cfg);
4496
4497         return src;
4498
4499 exception_exit:
4500         return NULL;
4501 }
4502
4503 /*
4504  * Returns NULL and set the cfg exception on error.
4505  */
4506 static MonoInst*
4507 handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
4508 {
4509         MonoInst *ins;
4510         MonoBasicBlock *is_null_bb, *false_bb, *end_bb;
4511         int obj_reg = src->dreg;
4512         int vtable_reg = alloc_preg (cfg);
4513         int res_reg = alloc_ireg_ref (cfg);
4514         MonoInst *klass_inst = NULL;
4515
4516         if (context_used) {
4517                 MonoInst *args [3];
4518
4519                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4520                         MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
4521                         MonoInst *cache_ins;
4522
4523                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4524
4525                         /* obj */
4526                         args [0] = src;
4527
4528                         /* klass - it's the second element of the cache entry*/
4529                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4530
4531                         /* cache */
4532                         args [2] = cache_ins;
4533
4534                         return mono_emit_method_call (cfg, mono_isinst, args, NULL);
4535                 }
4536
4537                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4538         }
4539
4540         NEW_BBLOCK (cfg, is_null_bb);
4541         NEW_BBLOCK (cfg, false_bb);
4542         NEW_BBLOCK (cfg, end_bb);
4543
4544         /* Do the assignment at the beginning, so the other assignment can be if converted */
4545         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, res_reg, obj_reg);
4546         ins->type = STACK_OBJ;
4547         ins->klass = klass;
4548
4549         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4550         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_null_bb);
4551
4552         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4553
4554         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4555                 g_assert (!context_used);
4556                 /* the is_null_bb target simply copies the input register to the output */
4557                 mini_emit_iface_cast (cfg, vtable_reg, klass, false_bb, is_null_bb);
4558         } else {
4559                 int klass_reg = alloc_preg (cfg);
4560
4561                 if (klass->rank) {
4562                         int rank_reg = alloc_preg (cfg);
4563                         int eclass_reg = alloc_preg (cfg);
4564
4565                         g_assert (!context_used);
4566                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
4567                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
4568                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4569                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4570                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
4571                         if (klass->cast_class == mono_defaults.object_class) {
4572                                 int parent_reg = alloc_preg (cfg);
4573                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
4574                                 mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, is_null_bb);
4575                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4576                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4577                         } else if (klass->cast_class == mono_defaults.enum_class->parent) {
4578                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, is_null_bb);
4579                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);                          
4580                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4581                         } else if (klass->cast_class == mono_defaults.enum_class) {
4582                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4583                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4584                         } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
4585                                 mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4586                         } else {
4587                                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY)) {
4588                                         /* Check that the object is a vector too */
4589                                         int bounds_reg = alloc_preg (cfg);
4590                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
4591                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
4592                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4593                                 }
4594
4595                                 /* the is_null_bb target simply copies the input register to the output */
4596                                 mini_emit_isninst_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4597                         }
4598                 } else if (mono_class_is_nullable (klass)) {
4599                         g_assert (!context_used);
4600                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4601                         /* the is_null_bb target simply copies the input register to the output */
4602                         mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb);
4603                 } else {
4604                         if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4605                                 g_assert (!context_used);
4606                                 /* the remoting code is broken, access the class for now */
4607                                 if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4608                                         MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4609                                         if (!vt) {
4610                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4611                                                 cfg->exception_ptr = klass;
4612                                                 return NULL;
4613                                         }
4614                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4615                                 } else {
4616                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4617                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4618                                 }
4619                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4620                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
4621                         } else {
4622                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4623                                 /* the is_null_bb target simply copies the input register to the output */
4624                                 mini_emit_isninst_cast_inst (cfg, klass_reg, klass, klass_inst, false_bb, is_null_bb);
4625                         }
4626                 }
4627         }
4628
4629         MONO_START_BB (cfg, false_bb);
4630
4631         MONO_EMIT_NEW_PCONST (cfg, res_reg, 0);
4632         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4633
4634         MONO_START_BB (cfg, is_null_bb);
4635
4636         MONO_START_BB (cfg, end_bb);
4637
4638         return ins;
4639 }
4640
4641 static MonoInst*
4642 handle_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4643 {
4644         /* This opcode takes as input an object reference and a class, and returns:
4645         0) if the object is an instance of the class,
4646         1) if the object is not instance of the class,
4647         2) if the object is a proxy whose type cannot be determined */
4648
4649         MonoInst *ins;
4650 #ifndef DISABLE_REMOTING
4651         MonoBasicBlock *true_bb, *false_bb, *false2_bb, *end_bb, *no_proxy_bb, *interface_fail_bb;
4652 #else
4653         MonoBasicBlock *true_bb, *false_bb, *end_bb;
4654 #endif
4655         int obj_reg = src->dreg;
4656         int dreg = alloc_ireg (cfg);
4657         int tmp_reg;
4658 #ifndef DISABLE_REMOTING
4659         int klass_reg = alloc_preg (cfg);
4660 #endif
4661
4662         NEW_BBLOCK (cfg, true_bb);
4663         NEW_BBLOCK (cfg, false_bb);
4664         NEW_BBLOCK (cfg, end_bb);
4665 #ifndef DISABLE_REMOTING
4666         NEW_BBLOCK (cfg, false2_bb);
4667         NEW_BBLOCK (cfg, no_proxy_bb);
4668 #endif
4669
4670         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4671         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
4672
4673         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4674 #ifndef DISABLE_REMOTING
4675                 NEW_BBLOCK (cfg, interface_fail_bb);
4676 #endif
4677
4678                 tmp_reg = alloc_preg (cfg);
4679                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4680 #ifndef DISABLE_REMOTING
4681                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, true_bb);
4682                 MONO_START_BB (cfg, interface_fail_bb);
4683                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4684                 
4685                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, false_bb);
4686
4687                 tmp_reg = alloc_preg (cfg);
4688                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4689                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4690                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false2_bb);                
4691 #else
4692                 mini_emit_iface_cast (cfg, tmp_reg, klass, false_bb, true_bb);
4693 #endif
4694         } else {
4695 #ifndef DISABLE_REMOTING
4696                 tmp_reg = alloc_preg (cfg);
4697                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4698                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4699
4700                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4701                 tmp_reg = alloc_preg (cfg);
4702                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4703                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4704
4705                 tmp_reg = alloc_preg (cfg);             
4706                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4707                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4708                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4709                 
4710                 mini_emit_isninst_cast (cfg, klass_reg, klass, false2_bb, true_bb);
4711                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false2_bb);
4712
4713                 MONO_START_BB (cfg, no_proxy_bb);
4714
4715                 mini_emit_isninst_cast (cfg, klass_reg, klass, false_bb, true_bb);
4716 #else
4717                 g_error ("transparent proxy support is disabled while trying to JIT code that uses it");
4718 #endif
4719         }
4720
4721         MONO_START_BB (cfg, false_bb);
4722
4723         MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4724         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4725
4726 #ifndef DISABLE_REMOTING
4727         MONO_START_BB (cfg, false2_bb);
4728
4729         MONO_EMIT_NEW_ICONST (cfg, dreg, 2);
4730         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4731 #endif
4732
4733         MONO_START_BB (cfg, true_bb);
4734
4735         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4736
4737         MONO_START_BB (cfg, end_bb);
4738
4739         /* FIXME: */
4740         MONO_INST_NEW (cfg, ins, OP_ICONST);
4741         ins->dreg = dreg;
4742         ins->type = STACK_I4;
4743
4744         return ins;
4745 }
4746
4747 static MonoInst*
4748 handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4749 {
4750         /* This opcode takes as input an object reference and a class, and returns:
4751         0) if the object is an instance of the class,
4752         1) if the object is a proxy whose type cannot be determined
4753         an InvalidCastException exception is thrown otherwhise*/
4754         
4755         MonoInst *ins;
4756 #ifndef DISABLE_REMOTING
4757         MonoBasicBlock *end_bb, *ok_result_bb, *no_proxy_bb, *interface_fail_bb, *fail_1_bb;
4758 #else
4759         MonoBasicBlock *ok_result_bb;
4760 #endif
4761         int obj_reg = src->dreg;
4762         int dreg = alloc_ireg (cfg);
4763         int tmp_reg = alloc_preg (cfg);
4764
4765 #ifndef DISABLE_REMOTING
4766         int klass_reg = alloc_preg (cfg);
4767         NEW_BBLOCK (cfg, end_bb);
4768 #endif
4769
4770         NEW_BBLOCK (cfg, ok_result_bb);
4771
4772         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4773         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, ok_result_bb);
4774
4775         save_cast_details (cfg, klass, obj_reg, FALSE);
4776
4777         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4778 #ifndef DISABLE_REMOTING
4779                 NEW_BBLOCK (cfg, interface_fail_bb);
4780         
4781                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4782                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, ok_result_bb);
4783                 MONO_START_BB (cfg, interface_fail_bb);
4784                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4785
4786                 mini_emit_class_check (cfg, klass_reg, mono_defaults.transparent_proxy_class);
4787
4788                 tmp_reg = alloc_preg (cfg);             
4789                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4790                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4791                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
4792                 
4793                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4794                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4795 #else
4796                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4797                 mini_emit_iface_cast (cfg, tmp_reg, klass, NULL, NULL);
4798                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, ok_result_bb);
4799 #endif
4800         } else {
4801 #ifndef DISABLE_REMOTING
4802                 NEW_BBLOCK (cfg, no_proxy_bb);
4803
4804                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4805                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4806                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4807
4808                 tmp_reg = alloc_preg (cfg);
4809                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4810                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4811
4812                 tmp_reg = alloc_preg (cfg);
4813                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4814                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4815                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4816
4817                 NEW_BBLOCK (cfg, fail_1_bb);
4818                 
4819                 mini_emit_isninst_cast (cfg, klass_reg, klass, fail_1_bb, ok_result_bb);
4820
4821                 MONO_START_BB (cfg, fail_1_bb);
4822
4823                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4824                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4825
4826                 MONO_START_BB (cfg, no_proxy_bb);
4827
4828                 mini_emit_castclass (cfg, obj_reg, klass_reg, klass, ok_result_bb);
4829 #else
4830                 g_error ("Transparent proxy support is disabled while trying to JIT code that uses it");
4831 #endif
4832         }
4833
4834         MONO_START_BB (cfg, ok_result_bb);
4835
4836         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4837
4838 #ifndef DISABLE_REMOTING
4839         MONO_START_BB (cfg, end_bb);
4840 #endif
4841
4842         /* FIXME: */
4843         MONO_INST_NEW (cfg, ins, OP_ICONST);
4844         ins->dreg = dreg;
4845         ins->type = STACK_I4;
4846
4847         return ins;
4848 }
4849
4850 static G_GNUC_UNUSED MonoInst*
4851 handle_enum_has_flag (MonoCompile *cfg, MonoClass *klass, MonoInst *enum_this, MonoInst *enum_flag)
4852 {
4853         MonoType *enum_type = mono_type_get_underlying_type (&klass->byval_arg);
4854         guint32 load_opc = mono_type_to_load_membase (cfg, enum_type);
4855         gboolean is_i4;
4856
4857         switch (enum_type->type) {
4858         case MONO_TYPE_I8:
4859         case MONO_TYPE_U8:
4860 #if SIZEOF_REGISTER == 8
4861         case MONO_TYPE_I:
4862         case MONO_TYPE_U:
4863 #endif
4864                 is_i4 = FALSE;
4865                 break;
4866         default:
4867                 is_i4 = TRUE;
4868                 break;
4869         }
4870
4871         {
4872                 MonoInst *load, *and, *cmp, *ceq;
4873                 int enum_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4874                 int and_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4875                 int dest_reg = alloc_ireg (cfg);
4876
4877                 EMIT_NEW_LOAD_MEMBASE (cfg, load, load_opc, enum_reg, enum_this->dreg, 0);
4878                 EMIT_NEW_BIALU (cfg, and, is_i4 ? OP_IAND : OP_LAND, and_reg, enum_reg, enum_flag->dreg);
4879                 EMIT_NEW_BIALU (cfg, cmp, is_i4 ? OP_ICOMPARE : OP_LCOMPARE, -1, and_reg, enum_flag->dreg);
4880                 EMIT_NEW_UNALU (cfg, ceq, is_i4 ? OP_ICEQ : OP_LCEQ, dest_reg, -1);
4881
4882                 ceq->type = STACK_I4;
4883
4884                 if (!is_i4) {
4885                         load = mono_decompose_opcode (cfg, load);
4886                         and = mono_decompose_opcode (cfg, and);
4887                         cmp = mono_decompose_opcode (cfg, cmp);
4888                         ceq = mono_decompose_opcode (cfg, ceq);
4889                 }
4890
4891                 return ceq;
4892         }
4893 }
4894
4895 /*
4896  * Returns NULL and set the cfg exception on error.
4897  */
4898 static G_GNUC_UNUSED MonoInst*
4899 handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method, int context_used, gboolean virtual)
4900 {
4901         MonoInst *ptr;
4902         int dreg;
4903         gpointer trampoline;
4904         MonoInst *obj, *method_ins, *tramp_ins;
4905         MonoDomain *domain;
4906         guint8 **code_slot;
4907
4908         if (virtual) {
4909                 MonoMethod *invoke = mono_get_delegate_invoke (klass);
4910                 g_assert (invoke);
4911
4912                 if (!mono_get_delegate_virtual_invoke_impl (mono_method_signature (invoke), context_used ? NULL : method))
4913                         return NULL;
4914         }
4915
4916         obj = handle_alloc (cfg, klass, FALSE, 0);
4917         if (!obj)
4918                 return NULL;
4919
4920         /* Inline the contents of mono_delegate_ctor */
4921
4922         /* Set target field */
4923         /* Optimize away setting of NULL target */
4924         if (!(target->opcode == OP_PCONST && target->inst_p0 == 0)) {
4925                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
4926                 if (cfg->gen_write_barriers) {
4927                         dreg = alloc_preg (cfg);
4928                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target));
4929                         emit_write_barrier (cfg, ptr, target);
4930                 }
4931         }
4932
4933         /* Set method field */
4934         method_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
4935         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg);
4936
4937         /* 
4938          * To avoid looking up the compiled code belonging to the target method
4939          * in mono_delegate_trampoline (), we allocate a per-domain memory slot to
4940          * store it, and we fill it after the method has been compiled.
4941          */
4942         if (!method->dynamic && !(cfg->opt & MONO_OPT_SHARED)) {
4943                 MonoInst *code_slot_ins;
4944
4945                 if (context_used) {
4946                         code_slot_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD_DELEGATE_CODE);
4947                 } else {
4948                         domain = mono_domain_get ();
4949                         mono_domain_lock (domain);
4950                         if (!domain_jit_info (domain)->method_code_hash)
4951                                 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
4952                         code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, method);
4953                         if (!code_slot) {
4954                                 code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
4955                                 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, method, code_slot);
4956                         }
4957                         mono_domain_unlock (domain);
4958
4959                         if (cfg->compile_aot)
4960                                 EMIT_NEW_AOTCONST (cfg, code_slot_ins, MONO_PATCH_INFO_METHOD_CODE_SLOT, method);
4961                         else
4962                                 EMIT_NEW_PCONST (cfg, code_slot_ins, code_slot);
4963                 }
4964                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);                
4965         }
4966
4967         if (cfg->compile_aot) {
4968                 MonoDelegateClassMethodPair *del_tramp;
4969
4970                 del_tramp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoDelegateClassMethodPair));
4971                 del_tramp->klass = klass;
4972                 del_tramp->method = context_used ? NULL : method;
4973                 del_tramp->virtual = virtual;
4974                 EMIT_NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_DELEGATE_TRAMPOLINE, del_tramp);
4975         } else {
4976                 if (virtual)
4977                         trampoline = mono_create_delegate_virtual_trampoline (cfg->domain, klass, context_used ? NULL : method);
4978                 else
4979                         trampoline = mono_create_delegate_trampoline_info (cfg->domain, klass, context_used ? NULL : method);
4980                 EMIT_NEW_PCONST (cfg, tramp_ins, trampoline);
4981         }
4982
4983         /* Set invoke_impl field */
4984         if (virtual) {
4985                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), tramp_ins->dreg);
4986         } else {
4987                 dreg = alloc_preg (cfg);
4988                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, invoke_impl));
4989                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), dreg);
4990
4991                 dreg = alloc_preg (cfg);
4992                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, method_ptr));
4993                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr), dreg);
4994         }
4995
4996         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
4997
4998         return obj;
4999 }
5000
5001 static MonoInst*
5002 handle_array_new (MonoCompile *cfg, int rank, MonoInst **sp, unsigned char *ip)
5003 {
5004         MonoJitICallInfo *info;
5005
5006         /* Need to register the icall so it gets an icall wrapper */
5007         info = mono_get_array_new_va_icall (rank);
5008
5009         cfg->flags |= MONO_CFG_HAS_VARARGS;
5010
5011         /* mono_array_new_va () needs a vararg calling convention */
5012         cfg->disable_llvm = TRUE;
5013
5014         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
5015         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, sp);
5016 }
5017
5018 /*
5019  * handle_constrained_gsharedvt_call:
5020  *
5021  *   Handle constrained calls where the receiver is a gsharedvt type.
5022  * Return the instruction representing the call. Set the cfg exception on failure.
5023  */
5024 static MonoInst*
5025 handle_constrained_gsharedvt_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp, MonoClass *constrained_class,
5026                                                                    gboolean *ref_emit_widen)
5027 {
5028         MonoInst *ins = NULL;
5029         gboolean emit_widen = *ref_emit_widen;
5030
5031         /*
5032          * Constrained calls need to behave differently at runtime dependending on whenever the receiver is instantiated as ref type or as a vtype.
5033          * 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
5034          * pack the arguments into an array, and do the rest of the work in in an icall.
5035          */
5036         if (((cmethod->klass == mono_defaults.object_class) || (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) &&
5037                 (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 (cfg, fsig->ret)) &&
5038                 (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 (cfg, fsig->params [0]))))) {
5039                 MonoInst *args [16];
5040
5041                 /*
5042                  * This case handles calls to
5043                  * - object:ToString()/Equals()/GetHashCode(),
5044                  * - System.IComparable<T>:CompareTo()
5045                  * - System.IEquatable<T>:Equals ()
5046                  * plus some simple interface calls enough to support AsyncTaskMethodBuilder.
5047                  */
5048
5049                 args [0] = sp [0];
5050                 if (mono_method_check_context_used (cmethod))
5051                         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cmethod), cmethod, MONO_RGCTX_INFO_METHOD);
5052                 else
5053                         EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
5054                 args [2] = emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_class), constrained_class, MONO_RGCTX_INFO_KLASS);
5055
5056                 /* !fsig->hasthis is for the wrapper for the Object.GetType () icall */
5057                 if (fsig->hasthis && fsig->param_count) {
5058                         /* Pass the arguments using a localloc-ed array using the format expected by runtime_invoke () */
5059                         MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
5060                         ins->dreg = alloc_preg (cfg);
5061                         ins->inst_imm = fsig->param_count * sizeof (mgreg_t);
5062                         MONO_ADD_INS (cfg->cbb, ins);
5063                         args [4] = ins;
5064
5065                         if (mini_is_gsharedvt_type (cfg, fsig->params [0])) {
5066                                 int addr_reg;
5067
5068                                 args [3] = emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type (fsig->params [0]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
5069
5070                                 EMIT_NEW_VARLOADA_VREG (cfg, ins, sp [1]->dreg, fsig->params [0]);
5071                                 addr_reg = ins->dreg;
5072                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, addr_reg);
5073                         } else {
5074                                 EMIT_NEW_ICONST (cfg, args [3], 0);
5075                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, sp [1]->dreg);
5076                         }
5077                 } else {
5078                         EMIT_NEW_ICONST (cfg, args [3], 0);
5079                         EMIT_NEW_ICONST (cfg, args [4], 0);
5080                 }
5081                 ins = mono_emit_jit_icall (cfg, mono_gsharedvt_constrained_call, args);
5082                 emit_widen = FALSE;
5083
5084                 if (mini_is_gsharedvt_type (cfg, fsig->ret)) {
5085                         ins = handle_unbox_gsharedvt (cfg, mono_class_from_mono_type (fsig->ret), ins);
5086                 } else if (MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret)) {
5087                         MonoInst *add;
5088
5089                         /* Unbox */
5090                         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), ins->dreg, sizeof (MonoObject));
5091                         MONO_ADD_INS (cfg->cbb, add);
5092                         /* Load value */
5093                         NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, add->dreg, 0);
5094                         MONO_ADD_INS (cfg->cbb, ins);
5095                         /* ins represents the call result */
5096                 }
5097         } else {
5098                 GSHAREDVT_FAILURE (CEE_CALLVIRT);
5099         }
5100
5101         *ref_emit_widen = emit_widen;
5102
5103         return ins;
5104
5105  exception_exit:
5106         return NULL;
5107 }
5108
5109 static void
5110 mono_emit_load_got_addr (MonoCompile *cfg)
5111 {
5112         MonoInst *getaddr, *dummy_use;
5113
5114         if (!cfg->got_var || cfg->got_var_allocated)
5115                 return;
5116
5117         MONO_INST_NEW (cfg, getaddr, OP_LOAD_GOTADDR);
5118         getaddr->cil_code = cfg->header->code;
5119         getaddr->dreg = cfg->got_var->dreg;
5120
5121         /* Add it to the start of the first bblock */
5122         if (cfg->bb_entry->code) {
5123                 getaddr->next = cfg->bb_entry->code;
5124                 cfg->bb_entry->code = getaddr;
5125         }
5126         else
5127                 MONO_ADD_INS (cfg->bb_entry, getaddr);
5128
5129         cfg->got_var_allocated = TRUE;
5130
5131         /* 
5132          * Add a dummy use to keep the got_var alive, since real uses might
5133          * only be generated by the back ends.
5134          * Add it to end_bblock, so the variable's lifetime covers the whole
5135          * method.
5136          * It would be better to make the usage of the got var explicit in all
5137          * cases when the backend needs it (i.e. calls, throw etc.), so this
5138          * wouldn't be needed.
5139          */
5140         NEW_DUMMY_USE (cfg, dummy_use, cfg->got_var);
5141         MONO_ADD_INS (cfg->bb_exit, dummy_use);
5142 }
5143
5144 static int inline_limit;
5145 static gboolean inline_limit_inited;
5146
5147 static gboolean
5148 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
5149 {
5150         MonoMethodHeaderSummary header;
5151         MonoVTable *vtable;
5152 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5153         MonoMethodSignature *sig = mono_method_signature (method);
5154         int i;
5155 #endif
5156
5157         if (cfg->disable_inline)
5158                 return FALSE;
5159         if (cfg->generic_sharing_context)
5160                 return FALSE;
5161
5162         if (cfg->inline_depth > 10)
5163                 return FALSE;
5164
5165 #ifdef MONO_ARCH_HAVE_LMF_OPS
5166         if (((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
5167                  (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) &&
5168             !MONO_TYPE_ISSTRUCT (signature->ret) && !mini_class_is_system_array (method->klass))
5169                 return TRUE;
5170 #endif
5171
5172
5173         if (!mono_method_get_header_summary (method, &header))
5174                 return FALSE;
5175
5176         /*runtime, icall and pinvoke are checked by summary call*/
5177         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
5178             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
5179             (mono_class_is_marshalbyref (method->klass)) ||
5180             header.has_clauses)
5181                 return FALSE;
5182
5183         /* also consider num_locals? */
5184         /* Do the size check early to avoid creating vtables */
5185         if (!inline_limit_inited) {
5186                 if (g_getenv ("MONO_INLINELIMIT"))
5187                         inline_limit = atoi (g_getenv ("MONO_INLINELIMIT"));
5188                 else
5189                         inline_limit = INLINE_LENGTH_LIMIT;
5190                 inline_limit_inited = TRUE;
5191         }
5192         if (header.code_size >= inline_limit && !(method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
5193                 return FALSE;
5194
5195         /*
5196          * if we can initialize the class of the method right away, we do,
5197          * otherwise we don't allow inlining if the class needs initialization,
5198          * since it would mean inserting a call to mono_runtime_class_init()
5199          * inside the inlined code
5200          */
5201         if (!(cfg->opt & MONO_OPT_SHARED)) {
5202                 /* The AggressiveInlining hint is a good excuse to force that cctor to run. */
5203                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING) {
5204                         vtable = mono_class_vtable (cfg->domain, method->klass);
5205                         if (!vtable)
5206                                 return FALSE;
5207                         if (!cfg->compile_aot)
5208                                 mono_runtime_class_init (vtable);
5209                 } else if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5210                         if (cfg->run_cctors && method->klass->has_cctor) {
5211                                 /*FIXME it would easier and lazier to just use mono_class_try_get_vtable */
5212                                 if (!method->klass->runtime_info)
5213                                         /* No vtable created yet */
5214                                         return FALSE;
5215                                 vtable = mono_class_vtable (cfg->domain, method->klass);
5216                                 if (!vtable)
5217                                         return FALSE;
5218                                 /* This makes so that inline cannot trigger */
5219                                 /* .cctors: too many apps depend on them */
5220                                 /* running with a specific order... */
5221                                 if (! vtable->initialized)
5222                                         return FALSE;
5223                                 mono_runtime_class_init (vtable);
5224                         }
5225                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
5226                         if (!method->klass->runtime_info)
5227                                 /* No vtable created yet */
5228                                 return FALSE;
5229                         vtable = mono_class_vtable (cfg->domain, method->klass);
5230                         if (!vtable)
5231                                 return FALSE;
5232                         if (!vtable->initialized)
5233                                 return FALSE;
5234                 }
5235         } else {
5236                 /* 
5237                  * If we're compiling for shared code
5238                  * the cctor will need to be run at aot method load time, for example,
5239                  * or at the end of the compilation of the inlining method.
5240                  */
5241                 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
5242                         return FALSE;
5243         }
5244
5245 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5246         if (mono_arch_is_soft_float ()) {
5247                 /* FIXME: */
5248                 if (sig->ret && sig->ret->type == MONO_TYPE_R4)
5249                         return FALSE;
5250                 for (i = 0; i < sig->param_count; ++i)
5251                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4)
5252                                 return FALSE;
5253         }
5254 #endif
5255
5256         if (g_list_find (cfg->dont_inline, method))
5257                 return FALSE;
5258
5259         return TRUE;
5260 }
5261
5262 static gboolean
5263 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoClass *klass, MonoVTable *vtable)
5264 {
5265         if (!cfg->compile_aot) {
5266                 g_assert (vtable);
5267                 if (vtable->initialized)
5268                         return FALSE;
5269         }
5270
5271         if (klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5272                 if (cfg->method == method)
5273                         return FALSE;
5274         }
5275
5276         if (!mono_class_needs_cctor_run (klass, method))
5277                 return FALSE;
5278
5279         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (klass == method->klass))
5280                 /* The initialization is already done before the method is called */
5281                 return FALSE;
5282
5283         return TRUE;
5284 }
5285
5286 static MonoInst*
5287 mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck)
5288 {
5289         MonoInst *ins;
5290         guint32 size;
5291         int mult_reg, add_reg, array_reg, index_reg, index2_reg;
5292         int context_used;
5293
5294         if (mini_is_gsharedvt_variable_klass (cfg, klass)) {
5295                 size = -1;
5296         } else {
5297                 mono_class_init (klass);
5298                 size = mono_class_array_element_size (klass);
5299         }
5300
5301         mult_reg = alloc_preg (cfg);
5302         array_reg = arr->dreg;
5303         index_reg = index->dreg;
5304
5305 #if SIZEOF_REGISTER == 8
5306         /* The array reg is 64 bits but the index reg is only 32 */
5307         if (COMPILE_LLVM (cfg)) {
5308                 /* Not needed */
5309                 index2_reg = index_reg;
5310         } else {
5311                 index2_reg = alloc_preg (cfg);
5312                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
5313         }
5314 #else
5315         if (index->type == STACK_I8) {
5316                 index2_reg = alloc_preg (cfg);
5317                 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I4, index2_reg, index_reg);
5318         } else {
5319                 index2_reg = index_reg;
5320         }
5321 #endif
5322
5323         if (bcheck)
5324                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
5325
5326 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5327         if (size == 1 || size == 2 || size == 4 || size == 8) {
5328                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
5329
5330                 EMIT_NEW_X86_LEA (cfg, ins, array_reg, index2_reg, fast_log2 [size], MONO_STRUCT_OFFSET (MonoArray, vector));
5331                 ins->klass = mono_class_get_element_class (klass);
5332                 ins->type = STACK_MP;
5333
5334                 return ins;
5335         }
5336 #endif          
5337
5338         add_reg = alloc_ireg_mp (cfg);
5339
5340         if (size == -1) {
5341                 MonoInst *rgctx_ins;
5342
5343                 /* gsharedvt */
5344                 g_assert (cfg->generic_sharing_context);
5345                 context_used = mini_class_check_context_used (cfg, klass);
5346                 g_assert (context_used);
5347                 rgctx_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE);
5348                 MONO_EMIT_NEW_BIALU (cfg, OP_IMUL, mult_reg, index2_reg, rgctx_ins->dreg);
5349         } else {
5350                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
5351         }
5352         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg);
5353         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5354         ins->klass = mono_class_get_element_class (klass);
5355         ins->type = STACK_MP;
5356         MONO_ADD_INS (cfg->cbb, ins);
5357
5358         return ins;
5359 }
5360
5361 #ifndef MONO_ARCH_EMULATE_MUL_DIV
5362 static MonoInst*
5363 mini_emit_ldelema_2_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index_ins1, MonoInst *index_ins2)
5364 {
5365         int bounds_reg = alloc_preg (cfg);
5366         int add_reg = alloc_ireg_mp (cfg);
5367         int mult_reg = alloc_preg (cfg);
5368         int mult2_reg = alloc_preg (cfg);
5369         int low1_reg = alloc_preg (cfg);
5370         int low2_reg = alloc_preg (cfg);
5371         int high1_reg = alloc_preg (cfg);
5372         int high2_reg = alloc_preg (cfg);
5373         int realidx1_reg = alloc_preg (cfg);
5374         int realidx2_reg = alloc_preg (cfg);
5375         int sum_reg = alloc_preg (cfg);
5376         int index1, index2, tmpreg;
5377         MonoInst *ins;
5378         guint32 size;
5379
5380         mono_class_init (klass);
5381         size = mono_class_array_element_size (klass);
5382
5383         index1 = index_ins1->dreg;
5384         index2 = index_ins2->dreg;
5385
5386 #if SIZEOF_REGISTER == 8
5387         /* The array reg is 64 bits but the index reg is only 32 */
5388         if (COMPILE_LLVM (cfg)) {
5389                 /* Not needed */
5390         } else {
5391                 tmpreg = alloc_preg (cfg);
5392                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index1);
5393                 index1 = tmpreg;
5394                 tmpreg = alloc_preg (cfg);
5395                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index2);
5396                 index2 = tmpreg;
5397         }
5398 #else
5399         // FIXME: Do we need to do something here for i8 indexes, like in ldelema_1_ins ?
5400         tmpreg = -1;
5401 #endif
5402
5403         /* range checking */
5404         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, 
5405                                        arr->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5406
5407         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low1_reg, 
5408                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5409         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx1_reg, index1, low1_reg);
5410         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high1_reg, 
5411                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5412         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high1_reg, realidx1_reg);
5413         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5414
5415         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low2_reg, 
5416                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5417         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx2_reg, index2, low2_reg);
5418         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high2_reg, 
5419                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5420         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high2_reg, realidx2_reg);
5421         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5422
5423         MONO_EMIT_NEW_BIALU (cfg, OP_PMUL, mult_reg, high2_reg, realidx1_reg);
5424         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, mult_reg, realidx2_reg);
5425         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PMUL_IMM, mult2_reg, sum_reg, size);
5426         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult2_reg, arr->dreg);
5427         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5428
5429         ins->type = STACK_MP;
5430         ins->klass = klass;
5431         MONO_ADD_INS (cfg->cbb, ins);
5432
5433         return ins;
5434 }
5435 #endif
5436
5437 static MonoInst*
5438 mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
5439 {
5440         int rank;
5441         MonoInst *addr;
5442         MonoMethod *addr_method;
5443         int element_size;
5444         MonoClass *eclass = cmethod->klass->element_class;
5445
5446         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
5447
5448         if (rank == 1)
5449                 return mini_emit_ldelema_1_ins (cfg, eclass, sp [0], sp [1], TRUE);
5450
5451 #ifndef MONO_ARCH_EMULATE_MUL_DIV
5452         /* emit_ldelema_2 depends on OP_LMUL */
5453         if (rank == 2 && (cfg->opt & MONO_OPT_INTRINS) && !mini_is_gsharedvt_variable_klass (cfg, eclass)) {
5454                 return mini_emit_ldelema_2_ins (cfg, eclass, sp [0], sp [1], sp [2]);
5455         }
5456 #endif
5457
5458         if (mini_is_gsharedvt_variable_klass (cfg, eclass))
5459                 element_size = 0;
5460         else
5461                 element_size = mono_class_array_element_size (eclass);
5462         addr_method = mono_marshal_get_array_address (rank, element_size);
5463         addr = mono_emit_method_call (cfg, addr_method, sp, NULL);
5464
5465         return addr;
5466 }
5467
5468 static MonoBreakPolicy
5469 always_insert_breakpoint (MonoMethod *method)
5470 {
5471         return MONO_BREAK_POLICY_ALWAYS;
5472 }
5473
5474 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
5475
5476 /**
5477  * mono_set_break_policy:
5478  * policy_callback: the new callback function
5479  *
5480  * Allow embedders to decide wherther to actually obey breakpoint instructions
5481  * (both break IL instructions and Debugger.Break () method calls), for example
5482  * to not allow an app to be aborted by a perfectly valid IL opcode when executing
5483  * untrusted or semi-trusted code.
5484  *
5485  * @policy_callback will be called every time a break point instruction needs to
5486  * be inserted with the method argument being the method that calls Debugger.Break()
5487  * or has the IL break instruction. The callback should return #MONO_BREAK_POLICY_NEVER
5488  * if it wants the breakpoint to not be effective in the given method.
5489  * #MONO_BREAK_POLICY_ALWAYS is the default.
5490  */
5491 void
5492 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
5493 {
5494         if (policy_callback)
5495                 break_policy_func = policy_callback;
5496         else
5497                 break_policy_func = always_insert_breakpoint;
5498 }
5499
5500 static gboolean
5501 should_insert_brekpoint (MonoMethod *method) {
5502         switch (break_policy_func (method)) {
5503         case MONO_BREAK_POLICY_ALWAYS:
5504                 return TRUE;
5505         case MONO_BREAK_POLICY_NEVER:
5506                 return FALSE;
5507         case MONO_BREAK_POLICY_ON_DBG:
5508                 g_warning ("mdb no longer supported");
5509                 return FALSE;
5510         default:
5511                 g_warning ("Incorrect value returned from break policy callback");
5512                 return FALSE;
5513         }
5514 }
5515
5516 /* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */
5517 static MonoInst*
5518 emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5519 {
5520         MonoInst *addr, *store, *load;
5521         MonoClass *eklass = mono_class_from_mono_type (fsig->params [2]);
5522
5523         /* the bounds check is already done by the callers */
5524         addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5525         if (is_set) {
5526                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
5527                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
5528                 if (mini_type_is_reference (cfg, fsig->params [2]))
5529                         emit_write_barrier (cfg, addr, load);
5530         } else {
5531                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
5532                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
5533         }
5534         return store;
5535 }
5536
5537
5538 static gboolean
5539 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
5540 {
5541         return mini_type_is_reference (cfg, &klass->byval_arg);
5542 }
5543
5544 static MonoInst*
5545 emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboolean safety_checks)
5546 {
5547         if (safety_checks && generic_class_is_reference_type (cfg, klass) &&
5548                 !(sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL)) {
5549                 MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
5550                 MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
5551                 MonoInst *iargs [3];
5552
5553                 if (!helper->slot)
5554                         mono_class_setup_vtable (obj_array);
5555                 g_assert (helper->slot);
5556
5557                 if (sp [0]->type != STACK_OBJ)
5558                         return NULL;
5559                 if (sp [2]->type != STACK_OBJ)
5560                         return NULL;
5561
5562                 iargs [2] = sp [2];
5563                 iargs [1] = sp [1];
5564                 iargs [0] = sp [0];
5565
5566                 return mono_emit_method_call (cfg, helper, iargs, sp [0]);
5567         } else {
5568                 MonoInst *ins;
5569
5570                 if (mini_is_gsharedvt_variable_klass (cfg, klass)) {
5571                         MonoInst *addr;
5572
5573                         // FIXME-VT: OP_ICONST optimization
5574                         addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
5575                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5576                         ins->opcode = OP_STOREV_MEMBASE;
5577                 } else if (sp [1]->opcode == OP_ICONST) {
5578                         int array_reg = sp [0]->dreg;
5579                         int index_reg = sp [1]->dreg;
5580                         int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
5581
5582                         if (safety_checks)
5583                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
5584                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
5585                 } else {
5586                         MonoInst *addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], safety_checks);
5587                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5588                         if (generic_class_is_reference_type (cfg, klass))
5589                                 emit_write_barrier (cfg, addr, sp [2]);
5590                 }
5591                 return ins;
5592         }
5593 }
5594
5595 static MonoInst*
5596 emit_array_unsafe_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5597 {
5598         MonoClass *eklass;
5599         
5600         if (is_set)
5601                 eklass = mono_class_from_mono_type (fsig->params [2]);
5602         else
5603                 eklass = mono_class_from_mono_type (fsig->ret);
5604
5605         if (is_set) {
5606                 return emit_array_store (cfg, eklass, args, FALSE);
5607         } else {
5608                 MonoInst *ins, *addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5609                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &eklass->byval_arg, addr->dreg, 0);
5610                 return ins;
5611         }
5612 }
5613
5614 static gboolean
5615 is_unsafe_mov_compatible (MonoCompile *cfg, MonoClass *param_klass, MonoClass *return_klass)
5616 {
5617         uint32_t align;
5618
5619         param_klass = mono_class_from_mono_type (mini_get_underlying_type (cfg, &param_klass->byval_arg));
5620
5621         //Only allow for valuetypes
5622         if (!param_klass->valuetype || !return_klass->valuetype)
5623                 return FALSE;
5624
5625         //That are blitable
5626         if (param_klass->has_references || return_klass->has_references)
5627                 return FALSE;
5628
5629         /* Avoid mixing structs and primitive types/enums, they need to be handled differently in the JIT */
5630         if ((MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && !MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)) ||
5631                 (!MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)))
5632                 return FALSE;
5633
5634         if (param_klass->byval_arg.type == MONO_TYPE_R4 || param_klass->byval_arg.type == MONO_TYPE_R8 ||
5635                 return_klass->byval_arg.type == MONO_TYPE_R4 || return_klass->byval_arg.type == MONO_TYPE_R8)
5636                 return FALSE;
5637
5638         //And have the same size
5639         if (mono_class_value_size (param_klass, &align) != mono_class_value_size (return_klass, &align))
5640                 return FALSE;
5641         return TRUE;
5642 }
5643
5644 static MonoInst*
5645 emit_array_unsafe_mov (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args)
5646 {
5647         MonoClass *param_klass = mono_class_from_mono_type (fsig->params [0]);
5648         MonoClass *return_klass = mono_class_from_mono_type (fsig->ret);
5649
5650         //Valuetypes that are semantically equivalent
5651         if (is_unsafe_mov_compatible (cfg, param_klass, return_klass))
5652                 return args [0];
5653
5654         //Arrays of valuetypes that are semantically equivalent
5655         if (param_klass->rank == 1 && return_klass->rank == 1 && is_unsafe_mov_compatible (cfg, param_klass->element_class, return_klass->element_class))
5656                 return args [0];
5657
5658         return NULL;
5659 }
5660
5661 static MonoInst*
5662 mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5663 {
5664 #ifdef MONO_ARCH_SIMD_INTRINSICS
5665         MonoInst *ins = NULL;
5666
5667         if (cfg->opt & MONO_OPT_SIMD) {
5668                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5669                 if (ins)
5670                         return ins;
5671         }
5672 #endif
5673
5674         return mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
5675 }
5676
5677 static MonoInst*
5678 emit_memory_barrier (MonoCompile *cfg, int kind)
5679 {
5680         MonoInst *ins = NULL;
5681         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
5682         MONO_ADD_INS (cfg->cbb, ins);
5683         ins->backend.memory_barrier_kind = kind;
5684
5685         return ins;
5686 }
5687
5688 static MonoInst*
5689 llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5690 {
5691         MonoInst *ins = NULL;
5692         int opcode = 0;
5693
5694         /* The LLVM backend supports these intrinsics */
5695         if (cmethod->klass == mono_defaults.math_class) {
5696                 if (strcmp (cmethod->name, "Sin") == 0) {
5697                         opcode = OP_SIN;
5698                 } else if (strcmp (cmethod->name, "Cos") == 0) {
5699                         opcode = OP_COS;
5700                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
5701                         opcode = OP_SQRT;
5702                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
5703                         opcode = OP_ABS;
5704                 }
5705
5706                 if (opcode && fsig->param_count == 1) {
5707                         MONO_INST_NEW (cfg, ins, opcode);
5708                         ins->type = STACK_R8;
5709                         ins->dreg = mono_alloc_freg (cfg);
5710                         ins->sreg1 = args [0]->dreg;
5711                         MONO_ADD_INS (cfg->cbb, ins);
5712                 }
5713
5714                 opcode = 0;
5715                 if (cfg->opt & MONO_OPT_CMOV) {
5716                         if (strcmp (cmethod->name, "Min") == 0) {
5717                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5718                                         opcode = OP_IMIN;
5719                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5720                                         opcode = OP_IMIN_UN;
5721                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5722                                         opcode = OP_LMIN;
5723                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5724                                         opcode = OP_LMIN_UN;
5725                         } else if (strcmp (cmethod->name, "Max") == 0) {
5726                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5727                                         opcode = OP_IMAX;
5728                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5729                                         opcode = OP_IMAX_UN;
5730                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5731                                         opcode = OP_LMAX;
5732                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5733                                         opcode = OP_LMAX_UN;
5734                         }
5735                 }
5736
5737                 if (opcode && fsig->param_count == 2) {
5738                         MONO_INST_NEW (cfg, ins, opcode);
5739                         ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
5740                         ins->dreg = mono_alloc_ireg (cfg);
5741                         ins->sreg1 = args [0]->dreg;
5742                         ins->sreg2 = args [1]->dreg;
5743                         MONO_ADD_INS (cfg->cbb, ins);
5744                 }
5745         }
5746
5747         return ins;
5748 }
5749
5750 static MonoInst*
5751 mini_emit_inst_for_sharable_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5752 {
5753         if (cmethod->klass == mono_defaults.array_class) {
5754                 if (strcmp (cmethod->name, "UnsafeStore") == 0)
5755                         return emit_array_unsafe_access (cfg, fsig, args, TRUE);
5756                 else if (strcmp (cmethod->name, "UnsafeLoad") == 0)
5757                         return emit_array_unsafe_access (cfg, fsig, args, FALSE);
5758                 else if (strcmp (cmethod->name, "UnsafeMov") == 0)
5759                         return emit_array_unsafe_mov (cfg, fsig, args);
5760         }
5761
5762         return NULL;
5763 }
5764
5765 static MonoInst*
5766 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5767 {
5768         MonoInst *ins = NULL;
5769
5770         static MonoClass *runtime_helpers_class = NULL;
5771         if (! runtime_helpers_class)
5772                 runtime_helpers_class = mono_class_from_name (mono_defaults.corlib,
5773                         "System.Runtime.CompilerServices", "RuntimeHelpers");
5774
5775         if (cmethod->klass == mono_defaults.string_class) {
5776                 if (strcmp (cmethod->name, "get_Chars") == 0 && fsig->param_count + fsig->hasthis == 2) {
5777                         int dreg = alloc_ireg (cfg);
5778                         int index_reg = alloc_preg (cfg);
5779                         int add_reg = alloc_preg (cfg);
5780
5781 #if SIZEOF_REGISTER == 8
5782                         /* The array reg is 64 bits but the index reg is only 32 */
5783                         MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index_reg, args [1]->dreg);
5784 #else
5785                         index_reg = args [1]->dreg;
5786 #endif  
5787                         MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
5788
5789 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5790                         EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, MONO_STRUCT_OFFSET (MonoString, chars));
5791                         add_reg = ins->dreg;
5792                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5793                                                                    add_reg, 0);
5794 #else
5795                         int mult_reg = alloc_preg (cfg);
5796                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1);
5797                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5798                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5799                                                                    add_reg, MONO_STRUCT_OFFSET (MonoString, chars));
5800 #endif
5801                         type_from_op (cfg, ins, NULL, NULL);
5802                         return ins;
5803                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
5804                         int dreg = alloc_ireg (cfg);
5805                         /* Decompose later to allow more optimizations */
5806                         EMIT_NEW_UNALU (cfg, ins, OP_STRLEN, dreg, args [0]->dreg);
5807                         ins->type = STACK_I4;
5808                         ins->flags |= MONO_INST_FAULT;
5809                         cfg->cbb->has_array_access = TRUE;
5810                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
5811
5812                         return ins;
5813                 } else 
5814                         return NULL;
5815         } else if (cmethod->klass == mono_defaults.object_class) {
5816
5817                 if (strcmp (cmethod->name, "GetType") == 0 && fsig->param_count + fsig->hasthis == 1) {
5818                         int dreg = alloc_ireg_ref (cfg);
5819                         int vt_reg = alloc_preg (cfg);
5820                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
5821                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, MONO_STRUCT_OFFSET (MonoVTable, type));
5822                         type_from_op (cfg, ins, NULL, NULL);
5823
5824                         return ins;
5825 #if !defined(MONO_ARCH_EMULATE_MUL_DIV)
5826                 } else if (strcmp (cmethod->name, "InternalGetHashCode") == 0 && fsig->param_count == 1 && !mono_gc_is_moving ()) {
5827                         int dreg = alloc_ireg (cfg);
5828                         int t1 = alloc_ireg (cfg);
5829         
5830                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, t1, args [0]->dreg, 3);
5831                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_MUL_IMM, dreg, t1, 2654435761u);
5832                         ins->type = STACK_I4;
5833
5834                         return ins;
5835 #endif
5836                 } else if (strcmp (cmethod->name, ".ctor") == 0 && fsig->param_count == 0) {
5837                         MONO_INST_NEW (cfg, ins, OP_NOP);
5838                         MONO_ADD_INS (cfg->cbb, ins);
5839                         return ins;
5840                 } else
5841                         return NULL;
5842         } else if (cmethod->klass == mono_defaults.array_class) {
5843                 if (strcmp (cmethod->name, "GetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
5844                         return emit_array_generic_access (cfg, fsig, args, FALSE);
5845                 else if (strcmp (cmethod->name, "SetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
5846                         return emit_array_generic_access (cfg, fsig, args, TRUE);
5847
5848 #ifndef MONO_BIG_ARRAYS
5849                 /*
5850                  * This is an inline version of GetLength/GetLowerBound(0) used frequently in
5851                  * Array methods.
5852                  */
5853                 else if (((strcmp (cmethod->name, "GetLength") == 0 && fsig->param_count + fsig->hasthis == 2) ||
5854                          (strcmp (cmethod->name, "GetLowerBound") == 0 && fsig->param_count + fsig->hasthis == 2)) &&
5855                          args [1]->opcode == OP_ICONST && args [1]->inst_c0 == 0) {
5856                         int dreg = alloc_ireg (cfg);
5857                         int bounds_reg = alloc_ireg_mp (cfg);
5858                         MonoBasicBlock *end_bb, *szarray_bb;
5859                         gboolean get_length = strcmp (cmethod->name, "GetLength") == 0;
5860
5861                         NEW_BBLOCK (cfg, end_bb);
5862                         NEW_BBLOCK (cfg, szarray_bb);
5863
5864                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOAD_MEMBASE, bounds_reg,
5865                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5866                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
5867                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, szarray_bb);
5868                         /* Non-szarray case */
5869                         if (get_length)
5870                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5871                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5872                         else
5873                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5874                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5875                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
5876                         MONO_START_BB (cfg, szarray_bb);
5877                         /* Szarray case */
5878                         if (get_length)
5879                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5880                                                                            args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
5881                         else
5882                                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
5883                         MONO_START_BB (cfg, end_bb);
5884
5885                         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, dreg, dreg);
5886                         ins->type = STACK_I4;
5887                         
5888                         return ins;
5889                 }
5890 #endif
5891
5892                 if (cmethod->name [0] != 'g')
5893                         return NULL;
5894
5895                 if (strcmp (cmethod->name, "get_Rank") == 0 && fsig->param_count + fsig->hasthis == 1) {
5896                         int dreg = alloc_ireg (cfg);
5897                         int vtable_reg = alloc_preg (cfg);
5898                         MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, 
5899                                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
5900                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
5901                                                                    vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
5902                         type_from_op (cfg, ins, NULL, NULL);
5903
5904                         return ins;
5905                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
5906                         int dreg = alloc_ireg (cfg);
5907
5908                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
5909                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
5910                         type_from_op (cfg, ins, NULL, NULL);
5911
5912                         return ins;
5913                 } else
5914                         return NULL;
5915         } else if (cmethod->klass == runtime_helpers_class) {
5916
5917                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0 && fsig->param_count == 0) {
5918                         EMIT_NEW_ICONST (cfg, ins, MONO_STRUCT_OFFSET (MonoString, chars));
5919                         return ins;
5920                 } else
5921                         return NULL;
5922         } else if (cmethod->klass == mono_defaults.thread_class) {
5923                 if (strcmp (cmethod->name, "SpinWait_nop") == 0 && fsig->param_count == 0) {
5924                         MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
5925                         MONO_ADD_INS (cfg->cbb, ins);
5926                         return ins;
5927                 } else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0) {
5928                         return emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5929                 } else if (!strcmp (cmethod->name, "VolatileRead") && fsig->param_count == 1) {
5930                         guint32 opcode = 0;
5931                         gboolean is_ref = mini_type_is_reference (cfg, fsig->params [0]);
5932
5933                         if (fsig->params [0]->type == MONO_TYPE_I1)
5934                                 opcode = OP_LOADI1_MEMBASE;
5935                         else if (fsig->params [0]->type == MONO_TYPE_U1)
5936                                 opcode = OP_LOADU1_MEMBASE;
5937                         else if (fsig->params [0]->type == MONO_TYPE_I2)
5938                                 opcode = OP_LOADI2_MEMBASE;
5939                         else if (fsig->params [0]->type == MONO_TYPE_U2)
5940                                 opcode = OP_LOADU2_MEMBASE;
5941                         else if (fsig->params [0]->type == MONO_TYPE_I4)
5942                                 opcode = OP_LOADI4_MEMBASE;
5943                         else if (fsig->params [0]->type == MONO_TYPE_U4)
5944                                 opcode = OP_LOADU4_MEMBASE;
5945                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
5946                                 opcode = OP_LOADI8_MEMBASE;
5947                         else if (fsig->params [0]->type == MONO_TYPE_R4)
5948                                 opcode = OP_LOADR4_MEMBASE;
5949                         else if (fsig->params [0]->type == MONO_TYPE_R8)
5950                                 opcode = OP_LOADR8_MEMBASE;
5951                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
5952                                 opcode = OP_LOAD_MEMBASE;
5953
5954                         if (opcode) {
5955                                 MONO_INST_NEW (cfg, ins, opcode);
5956                                 ins->inst_basereg = args [0]->dreg;
5957                                 ins->inst_offset = 0;
5958                                 MONO_ADD_INS (cfg->cbb, ins);
5959
5960                                 switch (fsig->params [0]->type) {
5961                                 case MONO_TYPE_I1:
5962                                 case MONO_TYPE_U1:
5963                                 case MONO_TYPE_I2:
5964                                 case MONO_TYPE_U2:
5965                                 case MONO_TYPE_I4:
5966                                 case MONO_TYPE_U4:
5967                                         ins->dreg = mono_alloc_ireg (cfg);
5968                                         ins->type = STACK_I4;
5969                                         break;
5970                                 case MONO_TYPE_I8:
5971                                 case MONO_TYPE_U8:
5972                                         ins->dreg = mono_alloc_lreg (cfg);
5973                                         ins->type = STACK_I8;
5974                                         break;
5975                                 case MONO_TYPE_I:
5976                                 case MONO_TYPE_U:
5977                                         ins->dreg = mono_alloc_ireg (cfg);
5978 #if SIZEOF_REGISTER == 8
5979                                         ins->type = STACK_I8;
5980 #else
5981                                         ins->type = STACK_I4;
5982 #endif
5983                                         break;
5984                                 case MONO_TYPE_R4:
5985                                 case MONO_TYPE_R8:
5986                                         ins->dreg = mono_alloc_freg (cfg);
5987                                         ins->type = STACK_R8;
5988                                         break;
5989                                 default:
5990                                         g_assert (mini_type_is_reference (cfg, fsig->params [0]));
5991                                         ins->dreg = mono_alloc_ireg_ref (cfg);
5992                                         ins->type = STACK_OBJ;
5993                                         break;
5994                                 }
5995
5996                                 if (opcode == OP_LOADI8_MEMBASE)
5997                                         ins = mono_decompose_opcode (cfg, ins);
5998
5999                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
6000
6001                                 return ins;
6002                         }
6003                 } else if (!strcmp (cmethod->name, "VolatileWrite") && fsig->param_count == 2) {
6004                         guint32 opcode = 0;
6005                         gboolean is_ref = mini_type_is_reference (cfg, fsig->params [0]);
6006
6007                         if (fsig->params [0]->type == MONO_TYPE_I1 || fsig->params [0]->type == MONO_TYPE_U1)
6008                                 opcode = OP_STOREI1_MEMBASE_REG;
6009                         else if (fsig->params [0]->type == MONO_TYPE_I2 || fsig->params [0]->type == MONO_TYPE_U2)
6010                                 opcode = OP_STOREI2_MEMBASE_REG;
6011                         else if (fsig->params [0]->type == MONO_TYPE_I4 || fsig->params [0]->type == MONO_TYPE_U4)
6012                                 opcode = OP_STOREI4_MEMBASE_REG;
6013                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
6014                                 opcode = OP_STOREI8_MEMBASE_REG;
6015                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6016                                 opcode = OP_STORER4_MEMBASE_REG;
6017                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6018                                 opcode = OP_STORER8_MEMBASE_REG;
6019                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
6020                                 opcode = OP_STORE_MEMBASE_REG;
6021
6022                         if (opcode) {
6023                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
6024
6025                                 MONO_INST_NEW (cfg, ins, opcode);
6026                                 ins->sreg1 = args [1]->dreg;
6027                                 ins->inst_destbasereg = args [0]->dreg;
6028                                 ins->inst_offset = 0;
6029                                 MONO_ADD_INS (cfg->cbb, ins);
6030
6031                                 if (opcode == OP_STOREI8_MEMBASE_REG)
6032                                         ins = mono_decompose_opcode (cfg, ins);
6033
6034                                 return ins;
6035                         }
6036                 }
6037         } else if (cmethod->klass == mono_defaults.monitor_class) {
6038 #if defined(MONO_ARCH_MONITOR_OBJECT_REG)
6039                 if (strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 1) {
6040                         MonoCallInst *call;
6041
6042                         if (COMPILE_LLVM (cfg)) {
6043                                 /* 
6044                                  * Pass the argument normally, the LLVM backend will handle the
6045                                  * calling convention problems.
6046                                  */
6047                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER, NULL, helper_sig_monitor_enter_exit_trampoline_llvm, args);
6048                         } else {
6049                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER,
6050                                             NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
6051                                 mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg,
6052                                                                                            MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
6053                         }
6054
6055                         return (MonoInst*)call;
6056 #if defined(MONO_ARCH_MONITOR_LOCK_TAKEN_REG)
6057                 } else if (strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 2) {
6058                         MonoCallInst *call;
6059
6060                         if (COMPILE_LLVM (cfg)) {
6061                                 /*
6062                                  * Pass the argument normally, the LLVM backend will handle the
6063                                  * calling convention problems.
6064                                  */
6065                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER_V4, NULL, helper_sig_monitor_enter_v4_trampoline_llvm, args);
6066                         } else {
6067                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER_V4,
6068                                             NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
6069                                 mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg, MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
6070                                 mono_call_inst_add_outarg_reg (cfg, call, args [1]->dreg, MONO_ARCH_MONITOR_LOCK_TAKEN_REG, FALSE);
6071                         }
6072
6073                         return (MonoInst*)call;
6074 #endif
6075                 } else if (strcmp (cmethod->name, "Exit") == 0 && fsig->param_count == 1) {
6076                         MonoCallInst *call;
6077
6078                         if (COMPILE_LLVM (cfg)) {
6079                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_EXIT, NULL, helper_sig_monitor_enter_exit_trampoline_llvm, args);
6080                         } else {
6081                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_EXIT,
6082                                             NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
6083                                 mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg,
6084                                                                                            MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
6085                         }
6086
6087                         return (MonoInst*)call;
6088                 }
6089 #endif
6090         } else if (cmethod->klass->image == mono_defaults.corlib &&
6091                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6092                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
6093                 ins = NULL;
6094
6095 #if SIZEOF_REGISTER == 8
6096                 if (strcmp (cmethod->name, "Read") == 0 && fsig->param_count == 1 && (fsig->params [0]->type == MONO_TYPE_I8)) {
6097                         if (mono_arch_opcode_supported (OP_ATOMIC_LOAD_I8)) {
6098                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_LOAD_I8);
6099                                 ins->dreg = mono_alloc_preg (cfg);
6100                                 ins->sreg1 = args [0]->dreg;
6101                                 ins->type = STACK_I8;
6102                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_SEQ;
6103                                 MONO_ADD_INS (cfg->cbb, ins);
6104                         } else {
6105                                 MonoInst *load_ins;
6106
6107                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6108
6109                                 /* 64 bit reads are already atomic */
6110                                 MONO_INST_NEW (cfg, load_ins, OP_LOADI8_MEMBASE);
6111                                 load_ins->dreg = mono_alloc_preg (cfg);
6112                                 load_ins->inst_basereg = args [0]->dreg;
6113                                 load_ins->inst_offset = 0;
6114                                 load_ins->type = STACK_I8;
6115                                 MONO_ADD_INS (cfg->cbb, load_ins);
6116
6117                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6118
6119                                 ins = load_ins;
6120                         }
6121                 }
6122 #endif
6123
6124                 if (strcmp (cmethod->name, "Increment") == 0 && fsig->param_count == 1) {
6125                         MonoInst *ins_iconst;
6126                         guint32 opcode = 0;
6127
6128                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6129                                 opcode = OP_ATOMIC_ADD_I4;
6130                                 cfg->has_atomic_add_i4 = TRUE;
6131                         }
6132 #if SIZEOF_REGISTER == 8
6133                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6134                                 opcode = OP_ATOMIC_ADD_I8;
6135 #endif
6136                         if (opcode) {
6137                                 if (!mono_arch_opcode_supported (opcode))
6138                                         return NULL;
6139                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6140                                 ins_iconst->inst_c0 = 1;
6141                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6142                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6143
6144                                 MONO_INST_NEW (cfg, ins, opcode);
6145                                 ins->dreg = mono_alloc_ireg (cfg);
6146                                 ins->inst_basereg = args [0]->dreg;
6147                                 ins->inst_offset = 0;
6148                                 ins->sreg2 = ins_iconst->dreg;
6149                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6150                                 MONO_ADD_INS (cfg->cbb, ins);
6151                         }
6152                 } else if (strcmp (cmethod->name, "Decrement") == 0 && fsig->param_count == 1) {
6153                         MonoInst *ins_iconst;
6154                         guint32 opcode = 0;
6155
6156                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6157                                 opcode = OP_ATOMIC_ADD_I4;
6158                                 cfg->has_atomic_add_i4 = TRUE;
6159                         }
6160 #if SIZEOF_REGISTER == 8
6161                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6162                                 opcode = OP_ATOMIC_ADD_I8;
6163 #endif
6164                         if (opcode) {
6165                                 if (!mono_arch_opcode_supported (opcode))
6166                                         return NULL;
6167                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6168                                 ins_iconst->inst_c0 = -1;
6169                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6170                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6171
6172                                 MONO_INST_NEW (cfg, ins, opcode);
6173                                 ins->dreg = mono_alloc_ireg (cfg);
6174                                 ins->inst_basereg = args [0]->dreg;
6175                                 ins->inst_offset = 0;
6176                                 ins->sreg2 = ins_iconst->dreg;
6177                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6178                                 MONO_ADD_INS (cfg->cbb, ins);
6179                         }
6180                 } else if (strcmp (cmethod->name, "Add") == 0 && fsig->param_count == 2) {
6181                         guint32 opcode = 0;
6182
6183                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6184                                 opcode = OP_ATOMIC_ADD_I4;
6185                                 cfg->has_atomic_add_i4 = TRUE;
6186                         }
6187 #if SIZEOF_REGISTER == 8
6188                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6189                                 opcode = OP_ATOMIC_ADD_I8;
6190 #endif
6191                         if (opcode) {
6192                                 if (!mono_arch_opcode_supported (opcode))
6193                                         return NULL;
6194                                 MONO_INST_NEW (cfg, ins, opcode);
6195                                 ins->dreg = mono_alloc_ireg (cfg);
6196                                 ins->inst_basereg = args [0]->dreg;
6197                                 ins->inst_offset = 0;
6198                                 ins->sreg2 = args [1]->dreg;
6199                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6200                                 MONO_ADD_INS (cfg->cbb, ins);
6201                         }
6202                 }
6203                 else if (strcmp (cmethod->name, "Exchange") == 0 && fsig->param_count == 2) {
6204                         MonoInst *f2i = NULL, *i2f;
6205                         guint32 opcode, f2i_opcode, i2f_opcode;
6206                         gboolean is_ref = mini_type_is_reference (cfg, fsig->params [0]);
6207                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
6208
6209                         if (fsig->params [0]->type == MONO_TYPE_I4 ||
6210                             fsig->params [0]->type == MONO_TYPE_R4) {
6211                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6212                                 f2i_opcode = OP_MOVE_F_TO_I4;
6213                                 i2f_opcode = OP_MOVE_I4_TO_F;
6214                                 cfg->has_atomic_exchange_i4 = TRUE;
6215                         }
6216 #if SIZEOF_REGISTER == 8
6217                         else if (is_ref ||
6218                                  fsig->params [0]->type == MONO_TYPE_I8 ||
6219                                  fsig->params [0]->type == MONO_TYPE_R8 ||
6220                                  fsig->params [0]->type == MONO_TYPE_I) {
6221                                 opcode = OP_ATOMIC_EXCHANGE_I8;
6222                                 f2i_opcode = OP_MOVE_F_TO_I8;
6223                                 i2f_opcode = OP_MOVE_I8_TO_F;
6224                         }
6225 #else
6226                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I) {
6227                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6228                                 cfg->has_atomic_exchange_i4 = TRUE;
6229                         }
6230 #endif
6231                         else
6232                                 return NULL;
6233
6234                         if (!mono_arch_opcode_supported (opcode))
6235                                 return NULL;
6236
6237                         if (is_float) {
6238                                 /* TODO: Decompose these opcodes instead of bailing here. */
6239                                 if (COMPILE_SOFT_FLOAT (cfg))
6240                                         return NULL;
6241
6242                                 MONO_INST_NEW (cfg, f2i, f2i_opcode);
6243                                 f2i->dreg = mono_alloc_ireg (cfg);
6244                                 f2i->sreg1 = args [1]->dreg;
6245                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6246                                         f2i->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6247                                 MONO_ADD_INS (cfg->cbb, f2i);
6248                         }
6249
6250                         MONO_INST_NEW (cfg, ins, opcode);
6251                         ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : mono_alloc_ireg (cfg);
6252                         ins->inst_basereg = args [0]->dreg;
6253                         ins->inst_offset = 0;
6254                         ins->sreg2 = is_float ? f2i->dreg : args [1]->dreg;
6255                         MONO_ADD_INS (cfg->cbb, ins);
6256
6257                         switch (fsig->params [0]->type) {
6258                         case MONO_TYPE_I4:
6259                                 ins->type = STACK_I4;
6260                                 break;
6261                         case MONO_TYPE_I8:
6262                                 ins->type = STACK_I8;
6263                                 break;
6264                         case MONO_TYPE_I:
6265 #if SIZEOF_REGISTER == 8
6266                                 ins->type = STACK_I8;
6267 #else
6268                                 ins->type = STACK_I4;
6269 #endif
6270                                 break;
6271                         case MONO_TYPE_R4:
6272                         case MONO_TYPE_R8:
6273                                 ins->type = STACK_R8;
6274                                 break;
6275                         default:
6276                                 g_assert (mini_type_is_reference (cfg, fsig->params [0]));
6277                                 ins->type = STACK_OBJ;
6278                                 break;
6279                         }
6280
6281                         if (is_float) {
6282                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6283                                 i2f->dreg = mono_alloc_freg (cfg);
6284                                 i2f->sreg1 = ins->dreg;
6285                                 i2f->type = STACK_R8;
6286                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6287                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6288                                 MONO_ADD_INS (cfg->cbb, i2f);
6289
6290                                 ins = i2f;
6291                         }
6292
6293                         if (cfg->gen_write_barriers && is_ref)
6294                                 emit_write_barrier (cfg, args [0], args [1]);
6295                 }
6296                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 3) {
6297                         MonoInst *f2i_new = NULL, *f2i_cmp = NULL, *i2f;
6298                         guint32 opcode, f2i_opcode, i2f_opcode;
6299                         gboolean is_ref = mini_type_is_reference (cfg, fsig->params [1]);
6300                         gboolean is_float = fsig->params [1]->type == MONO_TYPE_R4 || fsig->params [1]->type == MONO_TYPE_R8;
6301
6302                         if (fsig->params [1]->type == MONO_TYPE_I4 ||
6303                             fsig->params [1]->type == MONO_TYPE_R4) {
6304                                 opcode = OP_ATOMIC_CAS_I4;
6305                                 f2i_opcode = OP_MOVE_F_TO_I4;
6306                                 i2f_opcode = OP_MOVE_I4_TO_F;
6307                                 cfg->has_atomic_cas_i4 = TRUE;
6308                         }
6309 #if SIZEOF_REGISTER == 8
6310                         else if (is_ref ||
6311                                  fsig->params [1]->type == MONO_TYPE_I8 ||
6312                                  fsig->params [1]->type == MONO_TYPE_R8 ||
6313                                  fsig->params [1]->type == MONO_TYPE_I) {
6314                                 opcode = OP_ATOMIC_CAS_I8;
6315                                 f2i_opcode = OP_MOVE_F_TO_I8;
6316                                 i2f_opcode = OP_MOVE_I8_TO_F;
6317                         }
6318 #else
6319                         else if (is_ref || fsig->params [1]->type == MONO_TYPE_I) {
6320                                 opcode = OP_ATOMIC_CAS_I4;
6321                                 cfg->has_atomic_cas_i4 = TRUE;
6322                         }
6323 #endif
6324                         else
6325                                 return NULL;
6326
6327                         if (!mono_arch_opcode_supported (opcode))
6328                                 return NULL;
6329
6330                         if (is_float) {
6331                                 /* TODO: Decompose these opcodes instead of bailing here. */
6332                                 if (COMPILE_SOFT_FLOAT (cfg))
6333                                         return NULL;
6334
6335                                 MONO_INST_NEW (cfg, f2i_new, f2i_opcode);
6336                                 f2i_new->dreg = mono_alloc_ireg (cfg);
6337                                 f2i_new->sreg1 = args [1]->dreg;
6338                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6339                                         f2i_new->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6340                                 MONO_ADD_INS (cfg->cbb, f2i_new);
6341
6342                                 MONO_INST_NEW (cfg, f2i_cmp, f2i_opcode);
6343                                 f2i_cmp->dreg = mono_alloc_ireg (cfg);
6344                                 f2i_cmp->sreg1 = args [2]->dreg;
6345                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6346                                         f2i_cmp->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6347                                 MONO_ADD_INS (cfg->cbb, f2i_cmp);
6348                         }
6349
6350                         MONO_INST_NEW (cfg, ins, opcode);
6351                         ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
6352                         ins->sreg1 = args [0]->dreg;
6353                         ins->sreg2 = is_float ? f2i_new->dreg : args [1]->dreg;
6354                         ins->sreg3 = is_float ? f2i_cmp->dreg : args [2]->dreg;
6355                         MONO_ADD_INS (cfg->cbb, ins);
6356
6357                         switch (fsig->params [1]->type) {
6358                         case MONO_TYPE_I4:
6359                                 ins->type = STACK_I4;
6360                                 break;
6361                         case MONO_TYPE_I8:
6362                                 ins->type = STACK_I8;
6363                                 break;
6364                         case MONO_TYPE_I:
6365 #if SIZEOF_REGISTER == 8
6366                                 ins->type = STACK_I8;
6367 #else
6368                                 ins->type = STACK_I4;
6369 #endif
6370                                 break;
6371                         case MONO_TYPE_R4:
6372                                 ins->type = cfg->r4_stack_type;
6373                                 break;
6374                         case MONO_TYPE_R8:
6375                                 ins->type = STACK_R8;
6376                                 break;
6377                         default:
6378                                 g_assert (mini_type_is_reference (cfg, fsig->params [1]));
6379                                 ins->type = STACK_OBJ;
6380                                 break;
6381                         }
6382
6383                         if (is_float) {
6384                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6385                                 i2f->dreg = mono_alloc_freg (cfg);
6386                                 i2f->sreg1 = ins->dreg;
6387                                 i2f->type = STACK_R8;
6388                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6389                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6390                                 MONO_ADD_INS (cfg->cbb, i2f);
6391
6392                                 ins = i2f;
6393                         }
6394
6395                         if (cfg->gen_write_barriers && is_ref)
6396                                 emit_write_barrier (cfg, args [0], args [1]);
6397                 }
6398                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 4 &&
6399                          fsig->params [1]->type == MONO_TYPE_I4) {
6400                         MonoInst *cmp, *ceq;
6401
6402                         if (!mono_arch_opcode_supported (OP_ATOMIC_CAS_I4))
6403                                 return NULL;
6404
6405                         /* int32 r = CAS (location, value, comparand); */
6406                         MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
6407                         ins->dreg = alloc_ireg (cfg);
6408                         ins->sreg1 = args [0]->dreg;
6409                         ins->sreg2 = args [1]->dreg;
6410                         ins->sreg3 = args [2]->dreg;
6411                         ins->type = STACK_I4;
6412                         MONO_ADD_INS (cfg->cbb, ins);
6413
6414                         /* bool result = r == comparand; */
6415                         MONO_INST_NEW (cfg, cmp, OP_ICOMPARE);
6416                         cmp->sreg1 = ins->dreg;
6417                         cmp->sreg2 = args [2]->dreg;
6418                         cmp->type = STACK_I4;
6419                         MONO_ADD_INS (cfg->cbb, cmp);
6420
6421                         MONO_INST_NEW (cfg, ceq, OP_ICEQ);
6422                         ceq->dreg = alloc_ireg (cfg);
6423                         ceq->type = STACK_I4;
6424                         MONO_ADD_INS (cfg->cbb, ceq);
6425
6426                         /* *success = result; */
6427                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, args [3]->dreg, 0, ceq->dreg);
6428
6429                         cfg->has_atomic_cas_i4 = TRUE;
6430                 }
6431                 else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0)
6432                         ins = emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6433
6434                 if (ins)
6435                         return ins;
6436         } else if (cmethod->klass->image == mono_defaults.corlib &&
6437                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6438                            (strcmp (cmethod->klass->name, "Volatile") == 0)) {
6439                 ins = NULL;
6440
6441                 if (!strcmp (cmethod->name, "Read") && fsig->param_count == 1) {
6442                         guint32 opcode = 0;
6443                         gboolean is_ref = mini_type_is_reference (cfg, fsig->params [0]);
6444                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
6445
6446                         if (fsig->params [0]->type == MONO_TYPE_I1)
6447                                 opcode = OP_ATOMIC_LOAD_I1;
6448                         else if (fsig->params [0]->type == MONO_TYPE_U1 || fsig->params [0]->type == MONO_TYPE_BOOLEAN)
6449                                 opcode = OP_ATOMIC_LOAD_U1;
6450                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6451                                 opcode = OP_ATOMIC_LOAD_I2;
6452                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6453                                 opcode = OP_ATOMIC_LOAD_U2;
6454                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6455                                 opcode = OP_ATOMIC_LOAD_I4;
6456                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6457                                 opcode = OP_ATOMIC_LOAD_U4;
6458                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6459                                 opcode = OP_ATOMIC_LOAD_R4;
6460                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6461                                 opcode = OP_ATOMIC_LOAD_R8;
6462 #if SIZEOF_REGISTER == 8
6463                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_I)
6464                                 opcode = OP_ATOMIC_LOAD_I8;
6465                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U8 || fsig->params [0]->type == MONO_TYPE_U)
6466                                 opcode = OP_ATOMIC_LOAD_U8;
6467 #else
6468                         else if (fsig->params [0]->type == MONO_TYPE_I)
6469                                 opcode = OP_ATOMIC_LOAD_I4;
6470                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U)
6471                                 opcode = OP_ATOMIC_LOAD_U4;
6472 #endif
6473
6474                         if (opcode) {
6475                                 if (!mono_arch_opcode_supported (opcode))
6476                                         return NULL;
6477
6478                                 MONO_INST_NEW (cfg, ins, opcode);
6479                                 ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : (is_float ? mono_alloc_freg (cfg) : mono_alloc_ireg (cfg));
6480                                 ins->sreg1 = args [0]->dreg;
6481                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_ACQ;
6482                                 MONO_ADD_INS (cfg->cbb, ins);
6483
6484                                 switch (fsig->params [0]->type) {
6485                                 case MONO_TYPE_BOOLEAN:
6486                                 case MONO_TYPE_I1:
6487                                 case MONO_TYPE_U1:
6488                                 case MONO_TYPE_I2:
6489                                 case MONO_TYPE_U2:
6490                                 case MONO_TYPE_I4:
6491                                 case MONO_TYPE_U4:
6492                                         ins->type = STACK_I4;
6493                                         break;
6494                                 case MONO_TYPE_I8:
6495                                 case MONO_TYPE_U8:
6496                                         ins->type = STACK_I8;
6497                                         break;
6498                                 case MONO_TYPE_I:
6499                                 case MONO_TYPE_U:
6500 #if SIZEOF_REGISTER == 8
6501                                         ins->type = STACK_I8;
6502 #else
6503                                         ins->type = STACK_I4;
6504 #endif
6505                                         break;
6506                                 case MONO_TYPE_R4:
6507                                         ins->type = cfg->r4_stack_type;
6508                                         break;
6509                                 case MONO_TYPE_R8:
6510                                         ins->type = STACK_R8;
6511                                         break;
6512                                 default:
6513                                         g_assert (mini_type_is_reference (cfg, fsig->params [0]));
6514                                         ins->type = STACK_OBJ;
6515                                         break;
6516                                 }
6517                         }
6518                 }
6519
6520                 if (!strcmp (cmethod->name, "Write") && fsig->param_count == 2) {
6521                         guint32 opcode = 0;
6522                         gboolean is_ref = mini_type_is_reference (cfg, fsig->params [0]);
6523
6524                         if (fsig->params [0]->type == MONO_TYPE_I1)
6525                                 opcode = OP_ATOMIC_STORE_I1;
6526                         else if (fsig->params [0]->type == MONO_TYPE_U1 || fsig->params [0]->type == MONO_TYPE_BOOLEAN)
6527                                 opcode = OP_ATOMIC_STORE_U1;
6528                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6529                                 opcode = OP_ATOMIC_STORE_I2;
6530                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6531                                 opcode = OP_ATOMIC_STORE_U2;
6532                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6533                                 opcode = OP_ATOMIC_STORE_I4;
6534                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6535                                 opcode = OP_ATOMIC_STORE_U4;
6536                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6537                                 opcode = OP_ATOMIC_STORE_R4;
6538                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6539                                 opcode = OP_ATOMIC_STORE_R8;
6540 #if SIZEOF_REGISTER == 8
6541                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_I)
6542                                 opcode = OP_ATOMIC_STORE_I8;
6543                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U8 || fsig->params [0]->type == MONO_TYPE_U)
6544                                 opcode = OP_ATOMIC_STORE_U8;
6545 #else
6546                         else if (fsig->params [0]->type == MONO_TYPE_I)
6547                                 opcode = OP_ATOMIC_STORE_I4;
6548                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U)
6549                                 opcode = OP_ATOMIC_STORE_U4;
6550 #endif
6551
6552                         if (opcode) {
6553                                 if (!mono_arch_opcode_supported (opcode))
6554                                         return NULL;
6555
6556                                 MONO_INST_NEW (cfg, ins, opcode);
6557                                 ins->dreg = args [0]->dreg;
6558                                 ins->sreg1 = args [1]->dreg;
6559                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_REL;
6560                                 MONO_ADD_INS (cfg->cbb, ins);
6561
6562                                 if (cfg->gen_write_barriers && is_ref)
6563                                         emit_write_barrier (cfg, args [0], args [1]);
6564                         }
6565                 }
6566
6567                 if (ins)
6568                         return ins;
6569         } else if (cmethod->klass->image == mono_defaults.corlib &&
6570                            (strcmp (cmethod->klass->name_space, "System.Diagnostics") == 0) &&
6571                            (strcmp (cmethod->klass->name, "Debugger") == 0)) {
6572                 if (!strcmp (cmethod->name, "Break") && fsig->param_count == 0) {
6573                         if (should_insert_brekpoint (cfg->method)) {
6574                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
6575                         } else {
6576                                 MONO_INST_NEW (cfg, ins, OP_NOP);
6577                                 MONO_ADD_INS (cfg->cbb, ins);
6578                         }
6579                         return ins;
6580                 }
6581         } else if (cmethod->klass->image == mono_defaults.corlib &&
6582                    (strcmp (cmethod->klass->name_space, "System") == 0) &&
6583                    (strcmp (cmethod->klass->name, "Environment") == 0)) {
6584                 if (!strcmp (cmethod->name, "get_IsRunningOnWindows") && fsig->param_count == 0) {
6585 #ifdef TARGET_WIN32
6586                         EMIT_NEW_ICONST (cfg, ins, 1);
6587 #else
6588                         EMIT_NEW_ICONST (cfg, ins, 0);
6589 #endif
6590                 }
6591         } else if (cmethod->klass == mono_defaults.math_class) {
6592                 /* 
6593                  * There is general branchless code for Min/Max, but it does not work for 
6594                  * all inputs:
6595                  * http://everything2.com/?node_id=1051618
6596                  */
6597         } else if (((!strcmp (cmethod->klass->image->assembly->aname.name, "MonoMac") ||
6598                     !strcmp (cmethod->klass->image->assembly->aname.name, "monotouch")) &&
6599                                 !strcmp (cmethod->klass->name_space, "XamCore.ObjCRuntime") &&
6600                                 !strcmp (cmethod->klass->name, "Selector")) ||
6601                            (!strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.iOS") &&
6602                                 !strcmp (cmethod->klass->name_space, "ObjCRuntime") &&
6603                                 !strcmp (cmethod->klass->name, "Selector"))
6604                            ) {
6605 #ifdef MONO_ARCH_HAVE_OBJC_GET_SELECTOR
6606                 if (!strcmp (cmethod->name, "GetHandle") && fsig->param_count == 1 &&
6607                     (args [0]->opcode == OP_GOT_ENTRY || args [0]->opcode == OP_AOTCONST) &&
6608                     cfg->compile_aot) {
6609                         MonoInst *pi;
6610                         MonoJumpInfoToken *ji;
6611                         MonoString *s;
6612
6613                         cfg->disable_llvm = TRUE;
6614
6615                         if (args [0]->opcode == OP_GOT_ENTRY) {
6616                                 pi = args [0]->inst_p1;
6617                                 g_assert (pi->opcode == OP_PATCH_INFO);
6618                                 g_assert (GPOINTER_TO_INT (pi->inst_p1) == MONO_PATCH_INFO_LDSTR);
6619                                 ji = pi->inst_p0;
6620                         } else {
6621                                 g_assert (GPOINTER_TO_INT (args [0]->inst_p1) == MONO_PATCH_INFO_LDSTR);
6622                                 ji = args [0]->inst_p0;
6623                         }
6624
6625                         NULLIFY_INS (args [0]);
6626
6627                         // FIXME: Ugly
6628                         s = mono_ldstr (cfg->domain, ji->image, mono_metadata_token_index (ji->token));
6629                         MONO_INST_NEW (cfg, ins, OP_OBJC_GET_SELECTOR);
6630                         ins->dreg = mono_alloc_ireg (cfg);
6631                         // FIXME: Leaks
6632                         ins->inst_p0 = mono_string_to_utf8 (s);
6633                         MONO_ADD_INS (cfg->cbb, ins);
6634                         return ins;
6635                 }
6636 #endif
6637         }
6638
6639 #ifdef MONO_ARCH_SIMD_INTRINSICS
6640         if (cfg->opt & MONO_OPT_SIMD) {
6641                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
6642                 if (ins)
6643                         return ins;
6644         }
6645 #endif
6646
6647         ins = mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
6648         if (ins)
6649                 return ins;
6650
6651         if (COMPILE_LLVM (cfg)) {
6652                 ins = llvm_emit_inst_for_method (cfg, cmethod, fsig, args);
6653                 if (ins)
6654                         return ins;
6655         }
6656
6657         return mono_arch_emit_inst_for_method (cfg, cmethod, fsig, args);
6658 }
6659
6660 /*
6661  * This entry point could be used later for arbitrary method
6662  * redirection.
6663  */
6664 inline static MonoInst*
6665 mini_redirect_call (MonoCompile *cfg, MonoMethod *method,  
6666                                         MonoMethodSignature *signature, MonoInst **args, MonoInst *this)
6667 {
6668         if (method->klass == mono_defaults.string_class) {
6669                 /* managed string allocation support */
6670                 if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && !(cfg->opt & MONO_OPT_SHARED)) {
6671                         MonoInst *iargs [2];
6672                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
6673                         MonoMethod *managed_alloc = NULL;
6674
6675                         g_assert (vtable); /*Should not fail since it System.String*/
6676 #ifndef MONO_CROSS_COMPILE
6677                         managed_alloc = mono_gc_get_managed_allocator (method->klass, FALSE, FALSE);
6678 #endif
6679                         if (!managed_alloc)
6680                                 return NULL;
6681                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
6682                         iargs [1] = args [0];
6683                         return mono_emit_method_call (cfg, managed_alloc, iargs, this);
6684                 }
6685         }
6686         return NULL;
6687 }
6688
6689 static void
6690 mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp)
6691 {
6692         MonoInst *store, *temp;
6693         int i;
6694
6695         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
6696                 MonoType *argtype = (sig->hasthis && (i == 0)) ? type_from_stack_type (*sp) : sig->params [i - sig->hasthis];
6697
6698                 /*
6699                  * FIXME: We should use *args++ = sp [0], but that would mean the arg
6700                  * would be different than the MonoInst's used to represent arguments, and
6701                  * the ldelema implementation can't deal with that.
6702                  * Solution: When ldelema is used on an inline argument, create a var for 
6703                  * it, emit ldelema on that var, and emit the saving code below in
6704                  * inline_method () if needed.
6705                  */
6706                 temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
6707                 cfg->args [i] = temp;
6708                 /* This uses cfg->args [i] which is set by the preceeding line */
6709                 EMIT_NEW_ARGSTORE (cfg, store, i, *sp);
6710                 store->cil_code = sp [0]->cil_code;
6711                 sp++;
6712         }
6713 }
6714
6715 #define MONO_INLINE_CALLED_LIMITED_METHODS 1
6716 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
6717
6718 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6719 static gboolean
6720 check_inline_called_method_name_limit (MonoMethod *called_method)
6721 {
6722         int strncmp_result;
6723         static const char *limit = NULL;
6724         
6725         if (limit == NULL) {
6726                 const char *limit_string = g_getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
6727
6728                 if (limit_string != NULL)
6729                         limit = limit_string;
6730                 else
6731                         limit = "";
6732         }
6733
6734         if (limit [0] != '\0') {
6735                 char *called_method_name = mono_method_full_name (called_method, TRUE);
6736
6737                 strncmp_result = strncmp (called_method_name, limit, strlen (limit));
6738                 g_free (called_method_name);
6739         
6740                 //return (strncmp_result <= 0);
6741                 return (strncmp_result == 0);
6742         } else {
6743                 return TRUE;
6744         }
6745 }
6746 #endif
6747
6748 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6749 static gboolean
6750 check_inline_caller_method_name_limit (MonoMethod *caller_method)
6751 {
6752         int strncmp_result;
6753         static const char *limit = NULL;
6754         
6755         if (limit == NULL) {
6756                 const char *limit_string = g_getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
6757                 if (limit_string != NULL) {
6758                         limit = limit_string;
6759                 } else {
6760                         limit = "";
6761                 }
6762         }
6763
6764         if (limit [0] != '\0') {
6765                 char *caller_method_name = mono_method_full_name (caller_method, TRUE);
6766
6767                 strncmp_result = strncmp (caller_method_name, limit, strlen (limit));
6768                 g_free (caller_method_name);
6769         
6770                 //return (strncmp_result <= 0);
6771                 return (strncmp_result == 0);
6772         } else {
6773                 return TRUE;
6774         }
6775 }
6776 #endif
6777
6778 static void
6779 emit_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6780 {
6781         static double r8_0 = 0.0;
6782         static float r4_0 = 0.0;
6783         MonoInst *ins;
6784         int t;
6785
6786         rtype = mini_get_underlying_type (cfg, rtype);
6787         t = rtype->type;
6788
6789         if (rtype->byref) {
6790                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6791         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6792                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
6793         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6794                 MONO_EMIT_NEW_I8CONST (cfg, dreg, 0);
6795         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6796                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
6797                 ins->type = STACK_R4;
6798                 ins->inst_p0 = (void*)&r4_0;
6799                 ins->dreg = dreg;
6800                 MONO_ADD_INS (cfg->cbb, ins);
6801         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6802                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
6803                 ins->type = STACK_R8;
6804                 ins->inst_p0 = (void*)&r8_0;
6805                 ins->dreg = dreg;
6806                 MONO_ADD_INS (cfg->cbb, ins);
6807         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6808                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6809                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6810         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (cfg, rtype)) {
6811                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6812         } else {
6813                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6814         }
6815 }
6816
6817 static void
6818 emit_dummy_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6819 {
6820         int t;
6821
6822         rtype = mini_get_underlying_type (cfg, rtype);
6823         t = rtype->type;
6824
6825         if (rtype->byref) {
6826                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_PCONST);
6827         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6828                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_ICONST);
6829         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6830                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_I8CONST);
6831         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6832                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R4CONST);
6833         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6834                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R8CONST);
6835         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6836                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6837                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6838         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (cfg, rtype)) {
6839                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6840         } else {
6841                 emit_init_rvar (cfg, dreg, rtype);
6842         }
6843 }
6844
6845 /* If INIT is FALSE, emit dummy initialization statements to keep the IR valid */
6846 static void
6847 emit_init_local (MonoCompile *cfg, int local, MonoType *type, gboolean init)
6848 {
6849         MonoInst *var = cfg->locals [local];
6850         if (COMPILE_SOFT_FLOAT (cfg)) {
6851                 MonoInst *store;
6852                 int reg = alloc_dreg (cfg, var->type);
6853                 emit_init_rvar (cfg, reg, type);
6854                 EMIT_NEW_LOCSTORE (cfg, store, local, cfg->cbb->last_ins);
6855         } else {
6856                 if (init)
6857                         emit_init_rvar (cfg, var->dreg, type);
6858                 else
6859                         emit_dummy_init_rvar (cfg, var->dreg, type);
6860         }
6861 }
6862
6863 /*
6864  * inline_method:
6865  *
6866  *   Return the cost of inlining CMETHOD.
6867  */
6868 static int
6869 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
6870                            guchar *ip, guint real_offset, gboolean inline_always)
6871 {
6872         MonoInst *ins, *rvar = NULL;
6873         MonoMethodHeader *cheader;
6874         MonoBasicBlock *ebblock, *sbblock;
6875         int i, costs;
6876         MonoMethod *prev_inlined_method;
6877         MonoInst **prev_locals, **prev_args;
6878         MonoType **prev_arg_types;
6879         guint prev_real_offset;
6880         GHashTable *prev_cbb_hash;
6881         MonoBasicBlock **prev_cil_offset_to_bb;
6882         MonoBasicBlock *prev_cbb;
6883         unsigned char* prev_cil_start;
6884         guint32 prev_cil_offset_to_bb_len;
6885         MonoMethod *prev_current_method;
6886         MonoGenericContext *prev_generic_context;
6887         gboolean ret_var_set, prev_ret_var_set, prev_disable_inline, virtual = FALSE;
6888
6889         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
6890
6891 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6892         if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod))
6893                 return 0;
6894 #endif
6895 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6896         if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method))
6897                 return 0;
6898 #endif
6899
6900         if (!fsig)
6901                 fsig = mono_method_signature (cmethod);
6902
6903         if (cfg->verbose_level > 2)
6904                 printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
6905
6906         if (!cmethod->inline_info) {
6907                 cfg->stat_inlineable_methods++;
6908                 cmethod->inline_info = 1;
6909         }
6910
6911         /* allocate local variables */
6912         cheader = mono_method_get_header (cmethod);
6913
6914         if (cheader == NULL || mono_loader_get_last_error ()) {
6915                 MonoLoaderError *error = mono_loader_get_last_error ();
6916
6917                 if (cheader)
6918                         mono_metadata_free_mh (cheader);
6919                 if (inline_always && error)
6920                         mono_cfg_set_exception (cfg, error->exception_type);
6921
6922                 mono_loader_clear_error ();
6923                 return 0;
6924         }
6925
6926         /*Must verify before creating locals as it can cause the JIT to assert.*/
6927         if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
6928                 mono_metadata_free_mh (cheader);
6929                 return 0;
6930         }
6931
6932         /* allocate space to store the return value */
6933         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
6934                 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
6935         }
6936
6937         prev_locals = cfg->locals;
6938         cfg->locals = mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));     
6939         for (i = 0; i < cheader->num_locals; ++i)
6940                 cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
6941
6942         /* allocate start and end blocks */
6943         /* This is needed so if the inline is aborted, we can clean up */
6944         NEW_BBLOCK (cfg, sbblock);
6945         sbblock->real_offset = real_offset;
6946
6947         NEW_BBLOCK (cfg, ebblock);
6948         ebblock->block_num = cfg->num_bblocks++;
6949         ebblock->real_offset = real_offset;
6950
6951         prev_args = cfg->args;
6952         prev_arg_types = cfg->arg_types;
6953         prev_inlined_method = cfg->inlined_method;
6954         cfg->inlined_method = cmethod;
6955         cfg->ret_var_set = FALSE;
6956         cfg->inline_depth ++;
6957         prev_real_offset = cfg->real_offset;
6958         prev_cbb_hash = cfg->cbb_hash;
6959         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
6960         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
6961         prev_cil_start = cfg->cil_start;
6962         prev_cbb = cfg->cbb;
6963         prev_current_method = cfg->current_method;
6964         prev_generic_context = cfg->generic_context;
6965         prev_ret_var_set = cfg->ret_var_set;
6966         prev_disable_inline = cfg->disable_inline;
6967
6968         if (ip && *ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
6969                 virtual = TRUE;
6970
6971         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, sp, real_offset, virtual);
6972
6973         ret_var_set = cfg->ret_var_set;
6974
6975         cfg->inlined_method = prev_inlined_method;
6976         cfg->real_offset = prev_real_offset;
6977         cfg->cbb_hash = prev_cbb_hash;
6978         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
6979         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
6980         cfg->cil_start = prev_cil_start;
6981         cfg->locals = prev_locals;
6982         cfg->args = prev_args;
6983         cfg->arg_types = prev_arg_types;
6984         cfg->current_method = prev_current_method;
6985         cfg->generic_context = prev_generic_context;
6986         cfg->ret_var_set = prev_ret_var_set;
6987         cfg->disable_inline = prev_disable_inline;
6988         cfg->inline_depth --;
6989
6990         if ((costs >= 0 && costs < 60) || inline_always) {
6991                 if (cfg->verbose_level > 2)
6992                         printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
6993                 
6994                 cfg->stat_inlined_methods++;
6995
6996                 /* always add some code to avoid block split failures */
6997                 MONO_INST_NEW (cfg, ins, OP_NOP);
6998                 MONO_ADD_INS (prev_cbb, ins);
6999
7000                 prev_cbb->next_bb = sbblock;
7001                 link_bblock (cfg, prev_cbb, sbblock);
7002
7003                 /* 
7004                  * Get rid of the begin and end bblocks if possible to aid local
7005                  * optimizations.
7006                  */
7007                 mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
7008
7009                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
7010                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
7011
7012                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
7013                         MonoBasicBlock *prev = ebblock->in_bb [0];
7014                         mono_merge_basic_blocks (cfg, prev, ebblock);
7015                         cfg->cbb = prev;
7016                         if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
7017                                 mono_merge_basic_blocks (cfg, prev_cbb, prev);
7018                                 cfg->cbb = prev_cbb;
7019                         }
7020                 } else {
7021                         /* 
7022                          * Its possible that the rvar is set in some prev bblock, but not in others.
7023                          * (#1835).
7024                          */
7025                         if (rvar) {
7026                                 MonoBasicBlock *bb;
7027
7028                                 for (i = 0; i < ebblock->in_count; ++i) {
7029                                         bb = ebblock->in_bb [i];
7030
7031                                         if (bb->last_ins && bb->last_ins->opcode == OP_NOT_REACHED) {
7032                                                 cfg->cbb = bb;
7033
7034                                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
7035                                         }
7036                                 }
7037                         }
7038
7039                         cfg->cbb = ebblock;
7040                 }
7041
7042                 if (rvar) {
7043                         /*
7044                          * If the inlined method contains only a throw, then the ret var is not 
7045                          * set, so set it to a dummy value.
7046                          */
7047                         if (!ret_var_set)
7048                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
7049
7050                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
7051                         *sp++ = ins;
7052                 }
7053                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
7054                 return costs + 1;
7055         } else {
7056                 if (cfg->verbose_level > 2)
7057                         printf ("INLINE ABORTED %s (cost %d)\n", mono_method_full_name (cmethod, TRUE), costs);
7058                 cfg->exception_type = MONO_EXCEPTION_NONE;
7059                 mono_loader_clear_error ();
7060
7061                 /* This gets rid of the newly added bblocks */
7062                 cfg->cbb = prev_cbb;
7063         }
7064         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
7065         return 0;
7066 }
7067
7068 /*
7069  * Some of these comments may well be out-of-date.
7070  * Design decisions: we do a single pass over the IL code (and we do bblock 
7071  * splitting/merging in the few cases when it's required: a back jump to an IL
7072  * address that was not already seen as bblock starting point).
7073  * Code is validated as we go (full verification is still better left to metadata/verify.c).
7074  * Complex operations are decomposed in simpler ones right away. We need to let the 
7075  * arch-specific code peek and poke inside this process somehow (except when the 
7076  * optimizations can take advantage of the full semantic info of coarse opcodes).
7077  * All the opcodes of the form opcode.s are 'normalized' to opcode.
7078  * MonoInst->opcode initially is the IL opcode or some simplification of that 
7079  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
7080  * opcode with value bigger than OP_LAST.
7081  * At this point the IR can be handed over to an interpreter, a dumb code generator
7082  * or to the optimizing code generator that will translate it to SSA form.
7083  *
7084  * Profiling directed optimizations.
7085  * We may compile by default with few or no optimizations and instrument the code
7086  * or the user may indicate what methods to optimize the most either in a config file
7087  * or through repeated runs where the compiler applies offline the optimizations to 
7088  * each method and then decides if it was worth it.
7089  */
7090
7091 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
7092 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
7093 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
7094 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
7095 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
7096 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
7097 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
7098 #define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) TYPE_LOAD_ERROR ((klass))
7099
7100 /* offset from br.s -> br like opcodes */
7101 #define BIG_BRANCH_OFFSET 13
7102
7103 static gboolean
7104 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
7105 {
7106         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
7107
7108         return b == NULL || b == bb;
7109 }
7110
7111 static int
7112 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
7113 {
7114         unsigned char *ip = start;
7115         unsigned char *target;
7116         int i;
7117         guint cli_addr;
7118         MonoBasicBlock *bblock;
7119         const MonoOpcode *opcode;
7120
7121         while (ip < end) {
7122                 cli_addr = ip - start;
7123                 i = mono_opcode_value ((const guint8 **)&ip, end);
7124                 if (i < 0)
7125                         UNVERIFIED;
7126                 opcode = &mono_opcodes [i];
7127                 switch (opcode->argument) {
7128                 case MonoInlineNone:
7129                         ip++; 
7130                         break;
7131                 case MonoInlineString:
7132                 case MonoInlineType:
7133                 case MonoInlineField:
7134                 case MonoInlineMethod:
7135                 case MonoInlineTok:
7136                 case MonoInlineSig:
7137                 case MonoShortInlineR:
7138                 case MonoInlineI:
7139                         ip += 5;
7140                         break;
7141                 case MonoInlineVar:
7142                         ip += 3;
7143                         break;
7144                 case MonoShortInlineVar:
7145                 case MonoShortInlineI:
7146                         ip += 2;
7147                         break;
7148                 case MonoShortInlineBrTarget:
7149                         target = start + cli_addr + 2 + (signed char)ip [1];
7150                         GET_BBLOCK (cfg, bblock, target);
7151                         ip += 2;
7152                         if (ip < end)
7153                                 GET_BBLOCK (cfg, bblock, ip);
7154                         break;
7155                 case MonoInlineBrTarget:
7156                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
7157                         GET_BBLOCK (cfg, bblock, target);
7158                         ip += 5;
7159                         if (ip < end)
7160                                 GET_BBLOCK (cfg, bblock, ip);
7161                         break;
7162                 case MonoInlineSwitch: {
7163                         guint32 n = read32 (ip + 1);
7164                         guint32 j;
7165                         ip += 5;
7166                         cli_addr += 5 + 4 * n;
7167                         target = start + cli_addr;
7168                         GET_BBLOCK (cfg, bblock, target);
7169                         
7170                         for (j = 0; j < n; ++j) {
7171                                 target = start + cli_addr + (gint32)read32 (ip);
7172                                 GET_BBLOCK (cfg, bblock, target);
7173                                 ip += 4;
7174                         }
7175                         break;
7176                 }
7177                 case MonoInlineR:
7178                 case MonoInlineI8:
7179                         ip += 9;
7180                         break;
7181                 default:
7182                         g_assert_not_reached ();
7183                 }
7184
7185                 if (i == CEE_THROW) {
7186                         unsigned char *bb_start = ip - 1;
7187                         
7188                         /* Find the start of the bblock containing the throw */
7189                         bblock = NULL;
7190                         while ((bb_start >= start) && !bblock) {
7191                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
7192                                 bb_start --;
7193                         }
7194                         if (bblock)
7195                                 bblock->out_of_line = 1;
7196                 }
7197         }
7198         return 0;
7199 unverified:
7200 exception_exit:
7201         *pos = ip;
7202         return 1;
7203 }
7204
7205 static inline MonoMethod *
7206 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
7207 {
7208         MonoMethod *method;
7209
7210         if (m->wrapper_type != MONO_WRAPPER_NONE) {
7211                 method = mono_method_get_wrapper_data (m, token);
7212                 if (context) {
7213                         MonoError error;
7214                         method = mono_class_inflate_generic_method_checked (method, context, &error);
7215                         g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
7216                 }
7217         } else {
7218                 method = mono_get_method_full (m->klass->image, token, klass, context);
7219         }
7220
7221         return method;
7222 }
7223
7224 static inline MonoMethod *
7225 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
7226 {
7227         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context);
7228
7229         if (method && cfg && !cfg->generic_sharing_context && mono_class_is_open_constructed_type (&method->klass->byval_arg))
7230                 return NULL;
7231
7232         return method;
7233 }
7234
7235 static inline MonoClass*
7236 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
7237 {
7238         MonoError error;
7239         MonoClass *klass;
7240
7241         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7242                 klass = mono_method_get_wrapper_data (method, token);
7243                 if (context)
7244                         klass = mono_class_inflate_generic_class (klass, context);
7245         } else {
7246                 klass = mono_class_get_and_inflate_typespec_checked (method->klass->image, token, context, &error);
7247                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
7248         }
7249         if (klass)
7250                 mono_class_init (klass);
7251         return klass;
7252 }
7253
7254 static inline MonoMethodSignature*
7255 mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context)
7256 {
7257         MonoMethodSignature *fsig;
7258
7259         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7260                 MonoError error;
7261
7262                 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
7263                 if (context) {
7264                         fsig = mono_inflate_generic_signature (fsig, context, &error);
7265                         // FIXME:
7266                         g_assert (mono_error_ok (&error));
7267                 }
7268         } else {
7269                 fsig = mono_metadata_parse_signature (method->klass->image, token);
7270         }
7271         return fsig;
7272 }
7273
7274 static MonoMethod*
7275 throw_exception (void)
7276 {
7277         static MonoMethod *method = NULL;
7278
7279         if (!method) {
7280                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
7281                 method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
7282         }
7283         g_assert (method);
7284         return method;
7285 }
7286
7287 static void
7288 emit_throw_exception (MonoCompile *cfg, MonoException *ex)
7289 {
7290         MonoMethod *thrower = throw_exception ();
7291         MonoInst *args [1];
7292
7293         EMIT_NEW_PCONST (cfg, args [0], ex);
7294         mono_emit_method_call (cfg, thrower, args, NULL);
7295 }
7296
7297 /*
7298  * Return the original method is a wrapper is specified. We can only access 
7299  * the custom attributes from the original method.
7300  */
7301 static MonoMethod*
7302 get_original_method (MonoMethod *method)
7303 {
7304         if (method->wrapper_type == MONO_WRAPPER_NONE)
7305                 return method;
7306
7307         /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
7308         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
7309                 return NULL;
7310
7311         /* in other cases we need to find the original method */
7312         return mono_marshal_method_from_wrapper (method);
7313 }
7314
7315 static void
7316 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field)
7317 {
7318         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7319         MonoException *ex = mono_security_core_clr_is_field_access_allowed (get_original_method (caller), field);
7320         if (ex)
7321                 emit_throw_exception (cfg, ex);
7322 }
7323
7324 static void
7325 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
7326 {
7327         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7328         MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
7329         if (ex)
7330                 emit_throw_exception (cfg, ex);
7331 }
7332
7333 /*
7334  * Check that the IL instructions at ip are the array initialization
7335  * sequence and return the pointer to the data and the size.
7336  */
7337 static const char*
7338 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
7339 {
7340         /*
7341          * newarr[System.Int32]
7342          * dup
7343          * ldtoken field valuetype ...
7344          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
7345          */
7346         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
7347                 MonoError error;
7348                 guint32 token = read32 (ip + 7);
7349                 guint32 field_token = read32 (ip + 2);
7350                 guint32 field_index = field_token & 0xffffff;
7351                 guint32 rva;
7352                 const char *data_ptr;
7353                 int size = 0;
7354                 MonoMethod *cmethod;
7355                 MonoClass *dummy_class;
7356                 MonoClassField *field = mono_field_from_token_checked (method->klass->image, field_token, &dummy_class, NULL, &error);
7357                 int dummy_align;
7358
7359                 if (!field) {
7360                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7361                         return NULL;
7362                 }
7363
7364                 *out_field_token = field_token;
7365
7366                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
7367                 if (!cmethod)
7368                         return NULL;
7369                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
7370                         return NULL;
7371                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
7372                 case MONO_TYPE_BOOLEAN:
7373                 case MONO_TYPE_I1:
7374                 case MONO_TYPE_U1:
7375                         size = 1; break;
7376                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
7377 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
7378                 case MONO_TYPE_CHAR:
7379                 case MONO_TYPE_I2:
7380                 case MONO_TYPE_U2:
7381                         size = 2; break;
7382                 case MONO_TYPE_I4:
7383                 case MONO_TYPE_U4:
7384                 case MONO_TYPE_R4:
7385                         size = 4; break;
7386                 case MONO_TYPE_R8:
7387                 case MONO_TYPE_I8:
7388                 case MONO_TYPE_U8:
7389                         size = 8; break;
7390 #endif
7391                 default:
7392                         return NULL;
7393                 }
7394                 size *= len;
7395                 if (size > mono_type_size (field->type, &dummy_align))
7396                     return NULL;
7397                 *out_size = size;
7398                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
7399                 if (!image_is_dynamic (method->klass->image)) {
7400                         field_index = read32 (ip + 2) & 0xffffff;
7401                         mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
7402                         data_ptr = mono_image_rva_map (method->klass->image, rva);
7403                         /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
7404                         /* for aot code we do the lookup on load */
7405                         if (aot && data_ptr)
7406                                 return GUINT_TO_POINTER (rva);
7407                 } else {
7408                         /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
7409                         g_assert (!aot);
7410                         data_ptr = mono_field_get_data (field);
7411                 }
7412                 return data_ptr;
7413         }
7414         return NULL;
7415 }
7416
7417 static void
7418 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
7419 {
7420         char *method_fname = mono_method_full_name (method, TRUE);
7421         char *method_code;
7422         MonoMethodHeader *header = mono_method_get_header (method);
7423
7424         if (header->code_size == 0)
7425                 method_code = g_strdup ("method body is empty.");
7426         else
7427                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
7428         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
7429         cfg->exception_message = g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code);
7430         g_free (method_fname);
7431         g_free (method_code);
7432         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
7433 }
7434
7435 static void
7436 set_exception_object (MonoCompile *cfg, MonoException *exception)
7437 {
7438         mono_cfg_set_exception (cfg, MONO_EXCEPTION_OBJECT_SUPPLIED);
7439         MONO_GC_REGISTER_ROOT_SINGLE (cfg->exception_ptr);
7440         cfg->exception_ptr = exception;
7441 }
7442
7443 static void
7444 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
7445 {
7446         MonoInst *ins;
7447         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
7448         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
7449                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
7450                 /* Optimize reg-reg moves away */
7451                 /* 
7452                  * Can't optimize other opcodes, since sp[0] might point to
7453                  * the last ins of a decomposed opcode.
7454                  */
7455                 sp [0]->dreg = (cfg)->locals [n]->dreg;
7456         } else {
7457                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
7458         }
7459 }
7460
7461 /*
7462  * ldloca inhibits many optimizations so try to get rid of it in common
7463  * cases.
7464  */
7465 static inline unsigned char *
7466 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
7467 {
7468         int local, token;
7469         MonoClass *klass;
7470         MonoType *type;
7471
7472         if (size == 1) {
7473                 local = ip [1];
7474                 ip += 2;
7475         } else {
7476                 local = read16 (ip + 2);
7477                 ip += 4;
7478         }
7479         
7480         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
7481                 /* From the INITOBJ case */
7482                 token = read32 (ip + 2);
7483                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
7484                 CHECK_TYPELOAD (klass);
7485                 type = mini_get_underlying_type (cfg, &klass->byval_arg);
7486                 emit_init_local (cfg, local, type, TRUE);
7487                 return ip + 6;
7488         }
7489  exception_exit:
7490         return NULL;
7491 }
7492
7493 static gboolean
7494 is_exception_class (MonoClass *class)
7495 {
7496         while (class) {
7497                 if (class == mono_defaults.exception_class)
7498                         return TRUE;
7499                 class = class->parent;
7500         }
7501         return FALSE;
7502 }
7503
7504 /*
7505  * is_jit_optimizer_disabled:
7506  *
7507  *   Determine whenever M's assembly has a DebuggableAttribute with the
7508  * IsJITOptimizerDisabled flag set.
7509  */
7510 static gboolean
7511 is_jit_optimizer_disabled (MonoMethod *m)
7512 {
7513         MonoAssembly *ass = m->klass->image->assembly;
7514         MonoCustomAttrInfo* attrs;
7515         static MonoClass *klass;
7516         int i;
7517         gboolean val = FALSE;
7518
7519         g_assert (ass);
7520         if (ass->jit_optimizer_disabled_inited)
7521                 return ass->jit_optimizer_disabled;
7522
7523         if (!klass)
7524                 klass = mono_class_from_name (mono_defaults.corlib, "System.Diagnostics", "DebuggableAttribute");
7525         if (!klass) {
7526                 /* Linked away */
7527                 ass->jit_optimizer_disabled = FALSE;
7528                 mono_memory_barrier ();
7529                 ass->jit_optimizer_disabled_inited = TRUE;
7530                 return FALSE;
7531         }
7532
7533         attrs = mono_custom_attrs_from_assembly (ass);
7534         if (attrs) {
7535                 for (i = 0; i < attrs->num_attrs; ++i) {
7536                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
7537                         const gchar *p;
7538                         MonoMethodSignature *sig;
7539
7540                         if (!attr->ctor || attr->ctor->klass != klass)
7541                                 continue;
7542                         /* Decode the attribute. See reflection.c */
7543                         p = (const char*)attr->data;
7544                         g_assert (read16 (p) == 0x0001);
7545                         p += 2;
7546
7547                         // FIXME: Support named parameters
7548                         sig = mono_method_signature (attr->ctor);
7549                         if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
7550                                 continue;
7551                         /* Two boolean arguments */
7552                         p ++;
7553                         val = *p;
7554                 }
7555                 mono_custom_attrs_free (attrs);
7556         }
7557
7558         ass->jit_optimizer_disabled = val;
7559         mono_memory_barrier ();
7560         ass->jit_optimizer_disabled_inited = TRUE;
7561
7562         return val;
7563 }
7564
7565 static gboolean
7566 is_supported_tail_call (MonoCompile *cfg, MonoMethod *method, MonoMethod *cmethod, MonoMethodSignature *fsig, int call_opcode)
7567 {
7568         gboolean supported_tail_call;
7569         int i;
7570
7571 #ifdef MONO_ARCH_HAVE_OP_TAIL_CALL
7572         supported_tail_call = mono_arch_tail_call_supported (cfg, mono_method_signature (method), mono_method_signature (cmethod));
7573 #else
7574         supported_tail_call = mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod)) && !MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->ret);
7575 #endif
7576
7577         for (i = 0; i < fsig->param_count; ++i) {
7578                 if (fsig->params [i]->byref || fsig->params [i]->type == MONO_TYPE_PTR || fsig->params [i]->type == MONO_TYPE_FNPTR)
7579                         /* These can point to the current method's stack */
7580                         supported_tail_call = FALSE;
7581         }
7582         if (fsig->hasthis && cmethod->klass->valuetype)
7583                 /* this might point to the current method's stack */
7584                 supported_tail_call = FALSE;
7585         if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
7586                 supported_tail_call = FALSE;
7587         if (cfg->method->save_lmf)
7588                 supported_tail_call = FALSE;
7589         if (cmethod->wrapper_type && cmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
7590                 supported_tail_call = FALSE;
7591         if (call_opcode != CEE_CALL)
7592                 supported_tail_call = FALSE;
7593
7594         /* Debugging support */
7595 #if 0
7596         if (supported_tail_call) {
7597                 if (!mono_debug_count ())
7598                         supported_tail_call = FALSE;
7599         }
7600 #endif
7601
7602         return supported_tail_call;
7603 }
7604
7605 /* emits the code needed to access a managed tls var (like ThreadStatic)
7606  * with the value of the tls offset in offset_reg. thread_ins represents the MonoInternalThread
7607  * pointer for the current thread.
7608  * Returns the MonoInst* representing the address of the tls var.
7609  */
7610 static MonoInst*
7611 emit_managed_static_data_access (MonoCompile *cfg, MonoInst *thread_ins, int offset_reg)
7612 {
7613         MonoInst *addr;
7614         int static_data_reg, array_reg, dreg;
7615         int offset2_reg, idx_reg;
7616         // inlined access to the tls data (see threads.c)
7617         static_data_reg = alloc_ireg (cfg);
7618         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
7619         idx_reg = alloc_ireg (cfg);
7620         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, idx_reg, offset_reg, 0x3f);
7621         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
7622         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
7623         array_reg = alloc_ireg (cfg);
7624         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
7625         offset2_reg = alloc_ireg (cfg);
7626         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, offset2_reg, offset_reg, 6);
7627         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset2_reg, 0x1ffffff);
7628         dreg = alloc_ireg (cfg);
7629         EMIT_NEW_BIALU (cfg, addr, OP_PADD, dreg, array_reg, offset2_reg);
7630         return addr;
7631 }
7632
7633 /*
7634  * handle_ctor_call:
7635  *
7636  *   Handle calls made to ctors from NEWOBJ opcodes.
7637  */
7638 static void
7639 handle_ctor_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used,
7640                                   MonoInst **sp, guint8 *ip, int *inline_costs)
7641 {
7642         MonoInst *vtable_arg = NULL, *callvirt_this_arg = NULL, *ins;
7643
7644         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
7645                                         mono_method_is_generic_sharable (cmethod, TRUE)) {
7646                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
7647                         mono_class_vtable (cfg->domain, cmethod->klass);
7648                         CHECK_TYPELOAD (cmethod->klass);
7649
7650                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
7651                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
7652                 } else {
7653                         if (context_used) {
7654                                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
7655                                                                                                    cmethod->klass, MONO_RGCTX_INFO_VTABLE);
7656                         } else {
7657                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
7658
7659                                 CHECK_TYPELOAD (cmethod->klass);
7660                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
7661                         }
7662                 }
7663         }
7664
7665         /* Avoid virtual calls to ctors if possible */
7666         if (mono_class_is_marshalbyref (cmethod->klass))
7667                 callvirt_this_arg = sp [0];
7668
7669         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
7670                 g_assert (MONO_TYPE_IS_VOID (fsig->ret));
7671                 CHECK_CFG_EXCEPTION;
7672         } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
7673                            mono_method_check_inlining (cfg, cmethod) &&
7674                            !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE)) {
7675                 int costs;
7676
7677                 if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, FALSE))) {
7678                         cfg->real_offset += 5;
7679
7680                         *inline_costs += costs - 5;
7681                 } else {
7682                         INLINE_FAILURE ("inline failure");
7683                         // FIXME-VT: Clean this up
7684                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))
7685                                 GSHAREDVT_FAILURE(*ip);
7686                         mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, callvirt_this_arg, NULL, NULL);
7687                 }
7688         } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig)) {
7689                 MonoInst *addr;
7690
7691                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
7692                 mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
7693         } else if (context_used &&
7694                            ((!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
7695                                  !mono_class_generic_sharing_enabled (cmethod->klass)) || cfg->gsharedvt)) {
7696                 MonoInst *cmethod_addr;
7697
7698                 /* Generic calls made out of gsharedvt methods cannot be patched, so use an indirect call */
7699
7700                 cmethod_addr = emit_get_rgctx_method (cfg, context_used,
7701                                                                                           cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
7702
7703                 mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
7704         } else {
7705                 INLINE_FAILURE ("ctor call");
7706                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
7707                                                                                   callvirt_this_arg, NULL, vtable_arg);
7708         }
7709  exception_exit:
7710         return;
7711 }
7712
7713 /*
7714  * mono_method_to_ir:
7715  *
7716  *   Translate the .net IL into linear IR.
7717  */
7718 int
7719 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
7720                    MonoInst *return_var, MonoInst **inline_args, 
7721                    guint inline_offset, gboolean is_virtual_call)
7722 {
7723         MonoError error;
7724         MonoInst *ins, **sp, **stack_start;
7725         MonoBasicBlock *tblock = NULL, *init_localsbb = NULL;
7726         MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
7727         MonoMethod *cmethod, *method_definition;
7728         MonoInst **arg_array;
7729         MonoMethodHeader *header;
7730         MonoImage *image;
7731         guint32 token, ins_flag;
7732         MonoClass *klass;
7733         MonoClass *constrained_class = NULL;
7734         unsigned char *ip, *end, *target, *err_pos;
7735         MonoMethodSignature *sig;
7736         MonoGenericContext *generic_context = NULL;
7737         MonoGenericContainer *generic_container = NULL;
7738         MonoType **param_types;
7739         int i, n, start_new_bblock, dreg;
7740         int num_calls = 0, inline_costs = 0;
7741         int breakpoint_id = 0;
7742         guint num_args;
7743         GSList *class_inits = NULL;
7744         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
7745         int context_used;
7746         gboolean init_locals, seq_points, skip_dead_blocks;
7747         gboolean sym_seq_points = FALSE;
7748         MonoDebugMethodInfo *minfo;
7749         MonoBitSet *seq_point_locs = NULL;
7750         MonoBitSet *seq_point_set_locs = NULL;
7751
7752         cfg->disable_inline = is_jit_optimizer_disabled (method);
7753
7754         /* serialization and xdomain stuff may need access to private fields and methods */
7755         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
7756         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
7757         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
7758         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
7759         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
7760         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
7761
7762         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
7763         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
7764         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
7765         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
7766         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF;
7767
7768         image = method->klass->image;
7769         header = mono_method_get_header (method);
7770         if (!header) {
7771                 MonoLoaderError *error;
7772
7773                 if ((error = mono_loader_get_last_error ())) {
7774                         mono_cfg_set_exception (cfg, error->exception_type);
7775                 } else {
7776                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
7777                         cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
7778                 }
7779                 goto exception_exit;
7780         }
7781         generic_container = mono_method_get_generic_container (method);
7782         sig = mono_method_signature (method);
7783         num_args = sig->hasthis + sig->param_count;
7784         ip = (unsigned char*)header->code;
7785         cfg->cil_start = ip;
7786         end = ip + header->code_size;
7787         cfg->stat_cil_code_size += header->code_size;
7788
7789         seq_points = cfg->gen_seq_points && cfg->method == method;
7790
7791         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
7792                 /* We could hit a seq point before attaching to the JIT (#8338) */
7793                 seq_points = FALSE;
7794         }
7795
7796         if (cfg->gen_sdb_seq_points && cfg->method == method) {
7797                 minfo = mono_debug_lookup_method (method);
7798                 if (minfo) {
7799                         MonoSymSeqPoint *sps;
7800                         int i, n_il_offsets;
7801
7802                         mono_debug_get_seq_points (minfo, NULL, NULL, NULL, &sps, &n_il_offsets);
7803                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7804                         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);
7805                         sym_seq_points = TRUE;
7806                         for (i = 0; i < n_il_offsets; ++i) {
7807                                 if (sps [i].il_offset < header->code_size)
7808                                         mono_bitset_set_fast (seq_point_locs, sps [i].il_offset);
7809                         }
7810                         g_free (sps);
7811                 } else if (!method->wrapper_type && !method->dynamic && mono_debug_image_has_debug_info (method->klass->image)) {
7812                         /* Methods without line number info like auto-generated property accessors */
7813                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7814                         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);
7815                         sym_seq_points = TRUE;
7816                 }
7817         }
7818
7819         /* 
7820          * Methods without init_locals set could cause asserts in various passes
7821          * (#497220). To work around this, we emit dummy initialization opcodes
7822          * (OP_DUMMY_ICONST etc.) which generate no code. These are only supported
7823          * on some platforms.
7824          */
7825         if ((cfg->opt & MONO_OPT_UNSAFE) && ARCH_HAVE_DUMMY_INIT)
7826                 init_locals = header->init_locals;
7827         else
7828                 init_locals = TRUE;
7829
7830         method_definition = method;
7831         while (method_definition->is_inflated) {
7832                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
7833                 method_definition = imethod->declaring;
7834         }
7835
7836         /* SkipVerification is not allowed if core-clr is enabled */
7837         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
7838                 dont_verify = TRUE;
7839                 dont_verify_stloc = TRUE;
7840         }
7841
7842         if (sig->is_inflated)
7843                 generic_context = mono_method_get_context (method);
7844         else if (generic_container)
7845                 generic_context = &generic_container->context;
7846         cfg->generic_context = generic_context;
7847
7848         if (!cfg->generic_sharing_context)
7849                 g_assert (!sig->has_type_parameters);
7850
7851         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
7852                 g_assert (method->is_inflated);
7853                 g_assert (mono_method_get_context (method)->method_inst);
7854         }
7855         if (method->is_inflated && mono_method_get_context (method)->method_inst)
7856                 g_assert (sig->generic_param_count);
7857
7858         if (cfg->method == method) {
7859                 cfg->real_offset = 0;
7860         } else {
7861                 cfg->real_offset = inline_offset;
7862         }
7863
7864         cfg->cil_offset_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
7865         cfg->cil_offset_to_bb_len = header->code_size;
7866
7867         cfg->current_method = method;
7868
7869         if (cfg->verbose_level > 2)
7870                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
7871
7872         param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
7873         if (sig->hasthis)
7874                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
7875         for (n = 0; n < sig->param_count; ++n)
7876                 param_types [n + sig->hasthis] = sig->params [n];
7877         cfg->arg_types = param_types;
7878
7879         cfg->dont_inline = g_list_prepend (cfg->dont_inline, method);
7880         if (cfg->method == method) {
7881
7882                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
7883                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
7884
7885                 /* ENTRY BLOCK */
7886                 NEW_BBLOCK (cfg, start_bblock);
7887                 cfg->bb_entry = start_bblock;
7888                 start_bblock->cil_code = NULL;
7889                 start_bblock->cil_length = 0;
7890
7891                 /* EXIT BLOCK */
7892                 NEW_BBLOCK (cfg, end_bblock);
7893                 cfg->bb_exit = end_bblock;
7894                 end_bblock->cil_code = NULL;
7895                 end_bblock->cil_length = 0;
7896                 end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
7897                 g_assert (cfg->num_bblocks == 2);
7898
7899                 arg_array = cfg->args;
7900
7901                 if (header->num_clauses) {
7902                         cfg->spvars = g_hash_table_new (NULL, NULL);
7903                         cfg->exvars = g_hash_table_new (NULL, NULL);
7904                 }
7905                 /* handle exception clauses */
7906                 for (i = 0; i < header->num_clauses; ++i) {
7907                         MonoBasicBlock *try_bb;
7908                         MonoExceptionClause *clause = &header->clauses [i];
7909                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
7910                         try_bb->real_offset = clause->try_offset;
7911                         try_bb->try_start = TRUE;
7912                         try_bb->region = ((i + 1) << 8) | clause->flags;
7913                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
7914                         tblock->real_offset = clause->handler_offset;
7915                         tblock->flags |= BB_EXCEPTION_HANDLER;
7916
7917                         /*
7918                          * Linking the try block with the EH block hinders inlining as we won't be able to 
7919                          * merge the bblocks from inlining and produce an artificial hole for no good reason.
7920                          */
7921                         if (COMPILE_LLVM (cfg))
7922                                 link_bblock (cfg, try_bb, tblock);
7923
7924                         if (*(ip + clause->handler_offset) == CEE_POP)
7925                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
7926
7927                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
7928                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
7929                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
7930                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
7931                                 MONO_ADD_INS (tblock, ins);
7932
7933                                 if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY) {
7934                                         /* finally clauses already have a seq point */
7935                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
7936                                         MONO_ADD_INS (tblock, ins);
7937                                 }
7938
7939                                 /* todo: is a fault block unsafe to optimize? */
7940                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
7941                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
7942                         }
7943
7944                         /*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);
7945                           while (p < end) {
7946                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
7947                           }*/
7948                         /* catch and filter blocks get the exception object on the stack */
7949                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
7950                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7951
7952                                 /* mostly like handle_stack_args (), but just sets the input args */
7953                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
7954                                 tblock->in_scount = 1;
7955                                 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
7956                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
7957
7958                                 cfg->cbb = tblock;
7959
7960 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
7961                                 /* The EH code passes in the exception in a register to both JITted and LLVM compiled code */
7962                                 if (!cfg->compile_llvm) {
7963                                         MONO_INST_NEW (cfg, ins, OP_GET_EX_OBJ);
7964                                         ins->dreg = tblock->in_stack [0]->dreg;
7965                                         MONO_ADD_INS (tblock, ins);
7966                                 }
7967 #else
7968                                 MonoInst *dummy_use;
7969
7970                                 /* 
7971                                  * Add a dummy use for the exvar so its liveness info will be
7972                                  * correct.
7973                                  */
7974                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
7975 #endif
7976                                 
7977                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7978                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
7979                                         tblock->flags |= BB_EXCEPTION_HANDLER;
7980                                         tblock->real_offset = clause->data.filter_offset;
7981                                         tblock->in_scount = 1;
7982                                         tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
7983                                         /* The filter block shares the exvar with the handler block */
7984                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
7985                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
7986                                         MONO_ADD_INS (tblock, ins);
7987                                 }
7988                         }
7989
7990                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
7991                                         clause->data.catch_class &&
7992                                         cfg->generic_sharing_context &&
7993                                         mono_class_check_context_used (clause->data.catch_class)) {
7994                                 /*
7995                                  * In shared generic code with catch
7996                                  * clauses containing type variables
7997                                  * the exception handling code has to
7998                                  * be able to get to the rgctx.
7999                                  * Therefore we have to make sure that
8000                                  * the vtable/mrgctx argument (for
8001                                  * static or generic methods) or the
8002                                  * "this" argument (for non-static
8003                                  * methods) are live.
8004                                  */
8005                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8006                                                 mini_method_get_context (method)->method_inst ||
8007                                                 method->klass->valuetype) {
8008                                         mono_get_vtable_var (cfg);
8009                                 } else {
8010                                         MonoInst *dummy_use;
8011
8012                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
8013                                 }
8014                         }
8015                 }
8016         } else {
8017                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
8018                 cfg->cbb = start_bblock;
8019                 cfg->args = arg_array;
8020                 mono_save_args (cfg, sig, inline_args);
8021         }
8022
8023         /* FIRST CODE BLOCK */
8024         NEW_BBLOCK (cfg, tblock);
8025         tblock->cil_code = ip;
8026         cfg->cbb = tblock;
8027         cfg->ip = ip;
8028
8029         ADD_BBLOCK (cfg, tblock);
8030
8031         if (cfg->method == method) {
8032                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
8033                 if (breakpoint_id) {
8034                         MONO_INST_NEW (cfg, ins, OP_BREAK);
8035                         MONO_ADD_INS (cfg->cbb, ins);
8036                 }
8037         }
8038
8039         /* we use a separate basic block for the initialization code */
8040         NEW_BBLOCK (cfg, init_localsbb);
8041         cfg->bb_init = init_localsbb;
8042         init_localsbb->real_offset = cfg->real_offset;
8043         start_bblock->next_bb = init_localsbb;
8044         init_localsbb->next_bb = cfg->cbb;
8045         link_bblock (cfg, start_bblock, init_localsbb);
8046         link_bblock (cfg, init_localsbb, cfg->cbb);
8047                 
8048         cfg->cbb = init_localsbb;
8049
8050         if (cfg->gsharedvt && cfg->method == method) {
8051                 MonoGSharedVtMethodInfo *info;
8052                 MonoInst *var, *locals_var;
8053                 int dreg;
8054
8055                 info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoGSharedVtMethodInfo));
8056                 info->method = cfg->method;
8057                 info->count_entries = 16;
8058                 info->entries = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
8059                 cfg->gsharedvt_info = info;
8060
8061                 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8062                 /* prevent it from being register allocated */
8063                 //var->flags |= MONO_INST_VOLATILE;
8064                 cfg->gsharedvt_info_var = var;
8065
8066                 ins = emit_get_rgctx_gsharedvt_method (cfg, mini_method_check_context_used (cfg, method), method, info);
8067                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, var->dreg, ins->dreg);
8068
8069                 /* Allocate locals */
8070                 locals_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8071                 /* prevent it from being register allocated */
8072                 //locals_var->flags |= MONO_INST_VOLATILE;
8073                 cfg->gsharedvt_locals_var = locals_var;
8074
8075                 dreg = alloc_ireg (cfg);
8076                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, dreg, var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, locals_size));
8077
8078                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
8079                 ins->dreg = locals_var->dreg;
8080                 ins->sreg1 = dreg;
8081                 MONO_ADD_INS (cfg->cbb, ins);
8082                 cfg->gsharedvt_locals_var_ins = ins;
8083                 
8084                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
8085                 /*
8086                 if (init_locals)
8087                         ins->flags |= MONO_INST_INIT;
8088                 */
8089         }
8090
8091         if (mono_security_core_clr_enabled ()) {
8092                 /* check if this is native code, e.g. an icall or a p/invoke */
8093                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
8094                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
8095                         if (wrapped) {
8096                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
8097                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
8098
8099                                 /* if this ia a native call then it can only be JITted from platform code */
8100                                 if ((icall || pinvk) && method->klass && method->klass->image) {
8101                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
8102                                                 MonoException *ex = icall ? mono_get_exception_security () : 
8103                                                         mono_get_exception_method_access ();
8104                                                 emit_throw_exception (cfg, ex);
8105                                         }
8106                                 }
8107                         }
8108                 }
8109         }
8110
8111         CHECK_CFG_EXCEPTION;
8112
8113         if (header->code_size == 0)
8114                 UNVERIFIED;
8115
8116         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
8117                 ip = err_pos;
8118                 UNVERIFIED;
8119         }
8120
8121         if (cfg->method == method)
8122                 mono_debug_init_method (cfg, cfg->cbb, breakpoint_id);
8123
8124         for (n = 0; n < header->num_locals; ++n) {
8125                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
8126                         UNVERIFIED;
8127         }
8128         class_inits = NULL;
8129
8130         /* We force the vtable variable here for all shared methods
8131            for the possibility that they might show up in a stack
8132            trace where their exact instantiation is needed. */
8133         if (cfg->generic_sharing_context && method == cfg->method) {
8134                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8135                                 mini_method_get_context (method)->method_inst ||
8136                                 method->klass->valuetype) {
8137                         mono_get_vtable_var (cfg);
8138                 } else {
8139                         /* FIXME: Is there a better way to do this?
8140                            We need the variable live for the duration
8141                            of the whole method. */
8142                         cfg->args [0]->flags |= MONO_INST_VOLATILE;
8143                 }
8144         }
8145
8146         /* add a check for this != NULL to inlined methods */
8147         if (is_virtual_call) {
8148                 MonoInst *arg_ins;
8149
8150                 NEW_ARGLOAD (cfg, arg_ins, 0);
8151                 MONO_ADD_INS (cfg->cbb, arg_ins);
8152                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
8153         }
8154
8155         skip_dead_blocks = !dont_verify;
8156         if (skip_dead_blocks) {
8157                 original_bb = bb = mono_basic_block_split (method, &cfg->error);
8158                 CHECK_CFG_ERROR;
8159                 g_assert (bb);
8160         }
8161
8162         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
8163         stack_start = sp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
8164
8165         ins_flag = 0;
8166         start_new_bblock = 0;
8167         while (ip < end) {
8168                 if (cfg->method == method)
8169                         cfg->real_offset = ip - header->code;
8170                 else
8171                         cfg->real_offset = inline_offset;
8172                 cfg->ip = ip;
8173
8174                 context_used = 0;
8175
8176                 if (start_new_bblock) {
8177                         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
8178                         if (start_new_bblock == 2) {
8179                                 g_assert (ip == tblock->cil_code);
8180                         } else {
8181                                 GET_BBLOCK (cfg, tblock, ip);
8182                         }
8183                         cfg->cbb->next_bb = tblock;
8184                         cfg->cbb = tblock;
8185                         start_new_bblock = 0;
8186                         for (i = 0; i < cfg->cbb->in_scount; ++i) {
8187                                 if (cfg->verbose_level > 3)
8188                                         printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8189                                 EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8190                                 *sp++ = ins;
8191                         }
8192                         if (class_inits)
8193                                 g_slist_free (class_inits);
8194                         class_inits = NULL;
8195                 } else {
8196                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != cfg->cbb)) {
8197                                 link_bblock (cfg, cfg->cbb, tblock);
8198                                 if (sp != stack_start) {
8199                                         handle_stack_args (cfg, stack_start, sp - stack_start);
8200                                         sp = stack_start;
8201                                         CHECK_UNVERIFIABLE (cfg);
8202                                 }
8203                                 cfg->cbb->next_bb = tblock;
8204                                 cfg->cbb = tblock;
8205                                 for (i = 0; i < cfg->cbb->in_scount; ++i) {
8206                                         if (cfg->verbose_level > 3)
8207                                                 printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8208                                         EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8209                                         *sp++ = ins;
8210                                 }
8211                                 g_slist_free (class_inits);
8212                                 class_inits = NULL;
8213                         }
8214                 }
8215
8216                 if (skip_dead_blocks) {
8217                         int ip_offset = ip - header->code;
8218
8219                         if (ip_offset == bb->end)
8220                                 bb = bb->next;
8221
8222                         if (bb->dead) {
8223                                 int op_size = mono_opcode_size (ip, end);
8224                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
8225
8226                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
8227
8228                                 if (ip_offset + op_size == bb->end) {
8229                                         MONO_INST_NEW (cfg, ins, OP_NOP);
8230                                         MONO_ADD_INS (cfg->cbb, ins);
8231                                         start_new_bblock = 1;
8232                                 }
8233
8234                                 ip += op_size;
8235                                 continue;
8236                         }
8237                 }
8238                 /*
8239                  * Sequence points are points where the debugger can place a breakpoint.
8240                  * Currently, we generate these automatically at points where the IL
8241                  * stack is empty.
8242                  */
8243                 if (seq_points && ((!sym_seq_points && (sp == stack_start)) || (sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code)))) {
8244                         /*
8245                          * Make methods interruptable at the beginning, and at the targets of
8246                          * backward branches.
8247                          * Also, do this at the start of every bblock in methods with clauses too,
8248                          * to be able to handle instructions with inprecise control flow like
8249                          * throw/endfinally.
8250                          * Backward branches are handled at the end of method-to-ir ().
8251                          */
8252                         gboolean intr_loc = ip == header->code || (!cfg->cbb->last_ins && cfg->header->num_clauses);
8253                         gboolean sym_seq_point = sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code);
8254
8255                         /* Avoid sequence points on empty IL like .volatile */
8256                         // FIXME: Enable this
8257                         //if (!(cfg->cbb->last_ins && cfg->cbb->last_ins->opcode == OP_SEQ_POINT)) {
8258                         NEW_SEQ_POINT (cfg, ins, ip - header->code, intr_loc);
8259                         if ((sp != stack_start) && !sym_seq_point)
8260                                 ins->flags |= MONO_INST_NONEMPTY_STACK;
8261                         MONO_ADD_INS (cfg->cbb, ins);
8262
8263                         if (sym_seq_points)
8264                                 mono_bitset_set_fast (seq_point_set_locs, ip - header->code);
8265                 }
8266
8267                 cfg->cbb->real_offset = cfg->real_offset;
8268
8269                 if ((cfg->method == method) && cfg->coverage_info) {
8270                         guint32 cil_offset = ip - header->code;
8271                         cfg->coverage_info->data [cil_offset].cil_code = ip;
8272
8273                         /* TODO: Use an increment here */
8274 #if defined(TARGET_X86)
8275                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
8276                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
8277                         ins->inst_imm = 1;
8278                         MONO_ADD_INS (cfg->cbb, ins);
8279 #else
8280                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
8281                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
8282 #endif
8283                 }
8284
8285                 if (cfg->verbose_level > 3)
8286                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
8287
8288                 switch (*ip) {
8289                 case CEE_NOP:
8290                         if (seq_points && !sym_seq_points && sp != stack_start) {
8291                                 /*
8292                                  * The C# compiler uses these nops to notify the JIT that it should
8293                                  * insert seq points.
8294                                  */
8295                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, FALSE);
8296                                 MONO_ADD_INS (cfg->cbb, ins);
8297                         }
8298                         if (cfg->keep_cil_nops)
8299                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
8300                         else
8301                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8302                         ip++;
8303                         MONO_ADD_INS (cfg->cbb, ins);
8304                         break;
8305                 case CEE_BREAK:
8306                         if (should_insert_brekpoint (cfg->method)) {
8307                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
8308                         } else {
8309                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8310                         }
8311                         ip++;
8312                         MONO_ADD_INS (cfg->cbb, ins);
8313                         break;
8314                 case CEE_LDARG_0:
8315                 case CEE_LDARG_1:
8316                 case CEE_LDARG_2:
8317                 case CEE_LDARG_3:
8318                         CHECK_STACK_OVF (1);
8319                         n = (*ip)-CEE_LDARG_0;
8320                         CHECK_ARG (n);
8321                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8322                         ip++;
8323                         *sp++ = ins;
8324                         break;
8325                 case CEE_LDLOC_0:
8326                 case CEE_LDLOC_1:
8327                 case CEE_LDLOC_2:
8328                 case CEE_LDLOC_3:
8329                         CHECK_STACK_OVF (1);
8330                         n = (*ip)-CEE_LDLOC_0;
8331                         CHECK_LOCAL (n);
8332                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8333                         ip++;
8334                         *sp++ = ins;
8335                         break;
8336                 case CEE_STLOC_0:
8337                 case CEE_STLOC_1:
8338                 case CEE_STLOC_2:
8339                 case CEE_STLOC_3: {
8340                         CHECK_STACK (1);
8341                         n = (*ip)-CEE_STLOC_0;
8342                         CHECK_LOCAL (n);
8343                         --sp;
8344                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
8345                                 UNVERIFIED;
8346                         emit_stloc_ir (cfg, sp, header, n);
8347                         ++ip;
8348                         inline_costs += 1;
8349                         break;
8350                         }
8351                 case CEE_LDARG_S:
8352                         CHECK_OPSIZE (2);
8353                         CHECK_STACK_OVF (1);
8354                         n = ip [1];
8355                         CHECK_ARG (n);
8356                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8357                         *sp++ = ins;
8358                         ip += 2;
8359                         break;
8360                 case CEE_LDARGA_S:
8361                         CHECK_OPSIZE (2);
8362                         CHECK_STACK_OVF (1);
8363                         n = ip [1];
8364                         CHECK_ARG (n);
8365                         NEW_ARGLOADA (cfg, ins, n);
8366                         MONO_ADD_INS (cfg->cbb, ins);
8367                         *sp++ = ins;
8368                         ip += 2;
8369                         break;
8370                 case CEE_STARG_S:
8371                         CHECK_OPSIZE (2);
8372                         CHECK_STACK (1);
8373                         --sp;
8374                         n = ip [1];
8375                         CHECK_ARG (n);
8376                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
8377                                 UNVERIFIED;
8378                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
8379                         ip += 2;
8380                         break;
8381                 case CEE_LDLOC_S:
8382                         CHECK_OPSIZE (2);
8383                         CHECK_STACK_OVF (1);
8384                         n = ip [1];
8385                         CHECK_LOCAL (n);
8386                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8387                         *sp++ = ins;
8388                         ip += 2;
8389                         break;
8390                 case CEE_LDLOCA_S: {
8391                         unsigned char *tmp_ip;
8392                         CHECK_OPSIZE (2);
8393                         CHECK_STACK_OVF (1);
8394                         CHECK_LOCAL (ip [1]);
8395
8396                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
8397                                 ip = tmp_ip;
8398                                 inline_costs += 1;
8399                                 break;
8400                         }
8401
8402                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
8403                         *sp++ = ins;
8404                         ip += 2;
8405                         break;
8406                 }
8407                 case CEE_STLOC_S:
8408                         CHECK_OPSIZE (2);
8409                         CHECK_STACK (1);
8410                         --sp;
8411                         CHECK_LOCAL (ip [1]);
8412                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
8413                                 UNVERIFIED;
8414                         emit_stloc_ir (cfg, sp, header, ip [1]);
8415                         ip += 2;
8416                         inline_costs += 1;
8417                         break;
8418                 case CEE_LDNULL:
8419                         CHECK_STACK_OVF (1);
8420                         EMIT_NEW_PCONST (cfg, ins, NULL);
8421                         ins->type = STACK_OBJ;
8422                         ++ip;
8423                         *sp++ = ins;
8424                         break;
8425                 case CEE_LDC_I4_M1:
8426                         CHECK_STACK_OVF (1);
8427                         EMIT_NEW_ICONST (cfg, ins, -1);
8428                         ++ip;
8429                         *sp++ = ins;
8430                         break;
8431                 case CEE_LDC_I4_0:
8432                 case CEE_LDC_I4_1:
8433                 case CEE_LDC_I4_2:
8434                 case CEE_LDC_I4_3:
8435                 case CEE_LDC_I4_4:
8436                 case CEE_LDC_I4_5:
8437                 case CEE_LDC_I4_6:
8438                 case CEE_LDC_I4_7:
8439                 case CEE_LDC_I4_8:
8440                         CHECK_STACK_OVF (1);
8441                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
8442                         ++ip;
8443                         *sp++ = ins;
8444                         break;
8445                 case CEE_LDC_I4_S:
8446                         CHECK_OPSIZE (2);
8447                         CHECK_STACK_OVF (1);
8448                         ++ip;
8449                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
8450                         ++ip;
8451                         *sp++ = ins;
8452                         break;
8453                 case CEE_LDC_I4:
8454                         CHECK_OPSIZE (5);
8455                         CHECK_STACK_OVF (1);
8456                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
8457                         ip += 5;
8458                         *sp++ = ins;
8459                         break;
8460                 case CEE_LDC_I8:
8461                         CHECK_OPSIZE (9);
8462                         CHECK_STACK_OVF (1);
8463                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
8464                         ins->type = STACK_I8;
8465                         ins->dreg = alloc_dreg (cfg, STACK_I8);
8466                         ++ip;
8467                         ins->inst_l = (gint64)read64 (ip);
8468                         MONO_ADD_INS (cfg->cbb, ins);
8469                         ip += 8;
8470                         *sp++ = ins;
8471                         break;
8472                 case CEE_LDC_R4: {
8473                         float *f;
8474                         gboolean use_aotconst = FALSE;
8475
8476 #ifdef TARGET_POWERPC
8477                         /* FIXME: Clean this up */
8478                         if (cfg->compile_aot)
8479                                 use_aotconst = TRUE;
8480 #endif
8481
8482                         /* FIXME: we should really allocate this only late in the compilation process */
8483                         f = mono_domain_alloc (cfg->domain, sizeof (float));
8484                         CHECK_OPSIZE (5);
8485                         CHECK_STACK_OVF (1);
8486
8487                         if (use_aotconst) {
8488                                 MonoInst *cons;
8489                                 int dreg;
8490
8491                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
8492
8493                                 dreg = alloc_freg (cfg);
8494                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
8495                                 ins->type = cfg->r4_stack_type;
8496                         } else {
8497                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
8498                                 ins->type = cfg->r4_stack_type;
8499                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8500                                 ins->inst_p0 = f;
8501                                 MONO_ADD_INS (cfg->cbb, ins);
8502                         }
8503                         ++ip;
8504                         readr4 (ip, f);
8505                         ip += 4;
8506                         *sp++ = ins;                    
8507                         break;
8508                 }
8509                 case CEE_LDC_R8: {
8510                         double *d;
8511                         gboolean use_aotconst = FALSE;
8512
8513 #ifdef TARGET_POWERPC
8514                         /* FIXME: Clean this up */
8515                         if (cfg->compile_aot)
8516                                 use_aotconst = TRUE;
8517 #endif
8518
8519                         /* FIXME: we should really allocate this only late in the compilation process */
8520                         d = mono_domain_alloc (cfg->domain, sizeof (double));
8521                         CHECK_OPSIZE (9);
8522                         CHECK_STACK_OVF (1);
8523
8524                         if (use_aotconst) {
8525                                 MonoInst *cons;
8526                                 int dreg;
8527
8528                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
8529
8530                                 dreg = alloc_freg (cfg);
8531                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
8532                                 ins->type = STACK_R8;
8533                         } else {
8534                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
8535                                 ins->type = STACK_R8;
8536                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8537                                 ins->inst_p0 = d;
8538                                 MONO_ADD_INS (cfg->cbb, ins);
8539                         }
8540                         ++ip;
8541                         readr8 (ip, d);
8542                         ip += 8;
8543                         *sp++ = ins;
8544                         break;
8545                 }
8546                 case CEE_DUP: {
8547                         MonoInst *temp, *store;
8548                         CHECK_STACK (1);
8549                         CHECK_STACK_OVF (1);
8550                         sp--;
8551                         ins = *sp;
8552
8553                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
8554                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
8555
8556                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8557                         *sp++ = ins;
8558
8559                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8560                         *sp++ = ins;
8561
8562                         ++ip;
8563                         inline_costs += 2;
8564                         break;
8565                 }
8566                 case CEE_POP:
8567                         CHECK_STACK (1);
8568                         ip++;
8569                         --sp;
8570
8571 #ifdef TARGET_X86
8572                         if (sp [0]->type == STACK_R8)
8573                                 /* we need to pop the value from the x86 FP stack */
8574                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
8575 #endif
8576                         break;
8577                 case CEE_JMP: {
8578                         MonoCallInst *call;
8579
8580                         INLINE_FAILURE ("jmp");
8581                         GSHAREDVT_FAILURE (*ip);
8582
8583                         CHECK_OPSIZE (5);
8584                         if (stack_start != sp)
8585                                 UNVERIFIED;
8586                         token = read32 (ip + 1);
8587                         /* FIXME: check the signature matches */
8588                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8589
8590                         if (!cmethod || mono_loader_get_last_error ())
8591                                 LOAD_ERROR;
8592  
8593                         if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod))
8594                                 GENERIC_SHARING_FAILURE (CEE_JMP);
8595
8596                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
8597
8598                         if (ARCH_HAVE_OP_TAIL_CALL) {
8599                                 MonoMethodSignature *fsig = mono_method_signature (cmethod);
8600                                 int i, n;
8601
8602                                 /* Handle tail calls similarly to calls */
8603                                 n = fsig->param_count + fsig->hasthis;
8604
8605                                 DISABLE_AOT (cfg);
8606
8607                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
8608                                 call->method = cmethod;
8609                                 call->tail_call = TRUE;
8610                                 call->signature = mono_method_signature (cmethod);
8611                                 call->args = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
8612                                 call->inst.inst_p0 = cmethod;
8613                                 for (i = 0; i < n; ++i)
8614                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
8615
8616                                 mono_arch_emit_call (cfg, call);
8617                                 cfg->param_area = MAX(cfg->param_area, call->stack_usage);
8618                                 MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
8619                         } else {
8620                                 for (i = 0; i < num_args; ++i)
8621                                         /* Prevent arguments from being optimized away */
8622                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
8623
8624                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
8625                                 ins = (MonoInst*)call;
8626                                 ins->inst_p0 = cmethod;
8627                                 MONO_ADD_INS (cfg->cbb, ins);
8628                         }
8629
8630                         ip += 5;
8631                         start_new_bblock = 1;
8632                         break;
8633                 }
8634                 case CEE_CALLI: {
8635                         MonoInst *addr;
8636                         MonoMethodSignature *fsig;
8637
8638                         CHECK_OPSIZE (5);
8639                         token = read32 (ip + 1);
8640
8641                         ins = NULL;
8642
8643                         //GSHAREDVT_FAILURE (*ip);
8644                         cmethod = NULL;
8645                         CHECK_STACK (1);
8646                         --sp;
8647                         addr = *sp;
8648                         fsig = mini_get_signature (method, token, generic_context);
8649
8650                         if (method->dynamic && fsig->pinvoke) {
8651                                 MonoInst *args [3];
8652
8653                                 /*
8654                                  * This is a call through a function pointer using a pinvoke
8655                                  * signature. Have to create a wrapper and call that instead.
8656                                  * FIXME: This is very slow, need to create a wrapper at JIT time
8657                                  * instead based on the signature.
8658                                  */
8659                                 EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
8660                                 EMIT_NEW_PCONST (cfg, args [1], fsig);
8661                                 args [2] = addr;
8662                                 addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
8663                         }
8664
8665                         n = fsig->param_count + fsig->hasthis;
8666
8667                         CHECK_STACK (n);
8668
8669                         //g_assert (!virtual || fsig->hasthis);
8670
8671                         sp -= n;
8672
8673                         inline_costs += 10 * num_calls++;
8674
8675                         /*
8676                          * Making generic calls out of gsharedvt methods.
8677                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
8678                          * patching gshared method addresses into a gsharedvt method.
8679                          */
8680                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig)) {
8681                                 /*
8682                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
8683                                  */
8684                                 MonoInst *callee = addr;
8685
8686                                 if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
8687                                         /* Not tested */
8688                                         GSHAREDVT_FAILURE (*ip);
8689
8690                                 addr = emit_get_rgctx_sig (cfg, context_used,
8691                                                                                           fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
8692                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
8693                                 goto calli_end;
8694                         }
8695
8696                         /* Prevent inlining of methods with indirect calls */
8697                         INLINE_FAILURE ("indirect call");
8698
8699                         if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
8700                                 int info_type;
8701                                 gpointer info_data;
8702
8703                                 /*
8704                                  * Instead of emitting an indirect call, emit a direct call
8705                                  * with the contents of the aotconst as the patch info.
8706                                  */
8707                                 if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
8708                                         info_type = addr->inst_c1;
8709                                         info_data = addr->inst_p0;
8710                                 } else {
8711                                         info_type = addr->inst_right->inst_c1;
8712                                         info_data = addr->inst_right->inst_left;
8713                                 }
8714
8715                                 if (info_type == MONO_PATCH_INFO_ICALL_ADDR || info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
8716                                         ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
8717                                         NULLIFY_INS (addr);
8718                                         goto calli_end;
8719                                 }
8720                         }
8721                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8722
8723                         calli_end:
8724
8725                         /* End of call, INS should contain the result of the call, if any */
8726
8727                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8728                                 g_assert (ins);
8729                                 *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
8730                         }
8731
8732                         CHECK_CFG_EXCEPTION;
8733
8734                         ip += 5;
8735                         ins_flag = 0;
8736                         constrained_class = NULL;
8737                         break;
8738                 }
8739                 case CEE_CALL:
8740                 case CEE_CALLVIRT: {
8741                         MonoInst *addr = NULL;
8742                         MonoMethodSignature *fsig = NULL;
8743                         int array_rank = 0;
8744                         int virtual = *ip == CEE_CALLVIRT;
8745                         gboolean pass_imt_from_rgctx = FALSE;
8746                         MonoInst *imt_arg = NULL;
8747                         MonoInst *keep_this_alive = NULL;
8748                         gboolean pass_vtable = FALSE;
8749                         gboolean pass_mrgctx = FALSE;
8750                         MonoInst *vtable_arg = NULL;
8751                         gboolean check_this = FALSE;
8752                         gboolean supported_tail_call = FALSE;
8753                         gboolean tail_call = FALSE;
8754                         gboolean need_seq_point = FALSE;
8755                         guint32 call_opcode = *ip;
8756                         gboolean emit_widen = TRUE;
8757                         gboolean push_res = TRUE;
8758                         gboolean skip_ret = FALSE;
8759                         gboolean delegate_invoke = FALSE;
8760                         gboolean direct_icall = FALSE;
8761                         gboolean constrained_partial_call = FALSE;
8762                         MonoMethod *cil_method;
8763
8764                         CHECK_OPSIZE (5);
8765                         token = read32 (ip + 1);
8766
8767                         ins = NULL;
8768
8769                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8770                         cil_method = cmethod;
8771                                 
8772                         if (constrained_class) {
8773                                 if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->generic_sharing_context) {
8774                                         if (!mini_is_gsharedvt_klass (cfg, constrained_class)) {
8775                                                 g_assert (!cmethod->klass->valuetype);
8776                                                 if (!mini_type_is_reference (cfg, &constrained_class->byval_arg))
8777                                                         constrained_partial_call = TRUE;
8778                                         }
8779                                 }
8780
8781                                 if (method->wrapper_type != MONO_WRAPPER_NONE) {
8782                                         if (cfg->verbose_level > 2)
8783                                                 printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_class));
8784                                         if (!((constrained_class->byval_arg.type == MONO_TYPE_VAR ||
8785                                                    constrained_class->byval_arg.type == MONO_TYPE_MVAR) &&
8786                                                   cfg->generic_sharing_context)) {
8787                                                 cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_class, generic_context, &cfg->error);
8788                                                 CHECK_CFG_ERROR;
8789                                         }
8790                                 } else {
8791                                         if (cfg->verbose_level > 2)
8792                                                 printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_class));
8793
8794                                         if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->generic_sharing_context) {
8795                                                 /* 
8796                                                  * This is needed since get_method_constrained can't find 
8797                                                  * the method in klass representing a type var.
8798                                                  * The type var is guaranteed to be a reference type in this
8799                                                  * case.
8800                                                  */
8801                                                 if (!mini_is_gsharedvt_klass (cfg, constrained_class))
8802                                                         g_assert (!cmethod->klass->valuetype);
8803                                         } else {
8804                                                 cmethod = mono_get_method_constrained_checked (image, token, constrained_class, generic_context, &cil_method, &cfg->error);
8805                                                 CHECK_CFG_ERROR;
8806                                         }
8807                                 }
8808                         }
8809                                         
8810                         if (!cmethod || mono_loader_get_last_error ())
8811                                 LOAD_ERROR;
8812                         if (!dont_verify && !cfg->skip_visibility) {
8813                                 MonoMethod *target_method = cil_method;
8814                                 if (method->is_inflated) {
8815                                         target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context));
8816                                 }
8817                                 if (!mono_method_can_access_method (method_definition, target_method) &&
8818                                         !mono_method_can_access_method (method, cil_method))
8819                                         METHOD_ACCESS_FAILURE (method, cil_method);
8820                         }
8821
8822                         if (mono_security_core_clr_enabled ())
8823                                 ensure_method_is_allowed_to_call_method (cfg, method, cil_method);
8824
8825                         if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
8826                                 /* MS.NET seems to silently convert this to a callvirt */
8827                                 virtual = 1;
8828
8829                         {
8830                                 /*
8831                                  * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
8832                                  * converts to a callvirt.
8833                                  *
8834                                  * tests/bug-515884.il is an example of this behavior
8835                                  */
8836                                 const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
8837                                 const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
8838                                 if (!virtual && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
8839                                         virtual = 1;
8840                         }
8841
8842                         if (!cmethod->klass->inited)
8843                                 if (!mono_class_init (cmethod->klass))
8844                                         TYPE_LOAD_ERROR (cmethod->klass);
8845
8846                         fsig = mono_method_signature (cmethod);
8847                         if (!fsig)
8848                                 LOAD_ERROR;
8849                         if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
8850                                 mini_class_is_system_array (cmethod->klass)) {
8851                                 array_rank = cmethod->klass->rank;
8852                         } else if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && icall_is_direct_callable (cfg, cmethod)) {
8853                                 direct_icall = TRUE;
8854                         } else if (fsig->pinvoke) {
8855                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod,
8856                                                                                                                                            check_for_pending_exc, cfg->compile_aot);
8857                                 fsig = mono_method_signature (wrapper);
8858                         } else if (constrained_class) {
8859                         } else {
8860                                 fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
8861                                 CHECK_CFG_ERROR;
8862                         }
8863
8864                         mono_save_token_info (cfg, image, token, cil_method);
8865
8866                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip + 5 - header->code)))
8867                                 need_seq_point = TRUE;
8868
8869                         /* Don't support calls made using type arguments for now */
8870                         /*
8871                           if (cfg->gsharedvt) {
8872                           if (mini_is_gsharedvt_signature (cfg, fsig))
8873                           GSHAREDVT_FAILURE (*ip);
8874                           }
8875                         */
8876
8877                         if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
8878                                 g_assert_not_reached ();
8879
8880                         n = fsig->param_count + fsig->hasthis;
8881
8882                         if (!cfg->generic_sharing_context && cmethod->klass->generic_container)
8883                                 UNVERIFIED;
8884
8885                         if (!cfg->generic_sharing_context)
8886                                 g_assert (!mono_method_check_context_used (cmethod));
8887
8888                         CHECK_STACK (n);
8889
8890                         //g_assert (!virtual || fsig->hasthis);
8891
8892                         sp -= n;
8893
8894                         if (constrained_class) {
8895                                 if (mini_is_gsharedvt_klass (cfg, constrained_class)) {
8896                                         if ((cmethod->klass != mono_defaults.object_class) && constrained_class->valuetype && cmethod->klass->valuetype) {
8897                                                 /* The 'Own method' case below */
8898                                         } else if (cmethod->klass->image != mono_defaults.corlib && !(cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !cmethod->klass->valuetype) {
8899                                                 /* 'The type parameter is instantiated as a reference type' case below. */
8900                                         } else {
8901                                                 ins = handle_constrained_gsharedvt_call (cfg, cmethod, fsig, sp, constrained_class, &emit_widen);
8902                                                 CHECK_CFG_EXCEPTION;
8903                                                 g_assert (ins);
8904                                                 goto call_end;
8905                                         }
8906                                 }
8907
8908                                 /*
8909                                  * We have the `constrained.' prefix opcode.
8910                                  */
8911                                 if (constrained_partial_call) {
8912                                         gboolean need_box = TRUE;
8913
8914                                         /*
8915                                          * The receiver is a valuetype, but the exact type is not known at compile time. This means the
8916                                          * called method is not known at compile time either. The called method could end up being
8917                                          * one of the methods on the parent classes (object/valuetype/enum), in which case we need
8918                                          * to box the receiver.
8919                                          * A simple solution would be to box always and make a normal virtual call, but that would
8920                                          * be bad performance wise.
8921                                          */
8922                                         if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE && cmethod->klass->generic_class) {
8923                                                 /*
8924                                                  * The parent classes implement no generic interfaces, so the called method will be a vtype method, so no boxing neccessary.
8925                                                  */
8926                                                 need_box = FALSE;
8927                                         }
8928
8929                                         if (need_box) {
8930                                                 MonoInst *box_type;
8931                                                 MonoBasicBlock *is_ref_bb, *end_bb;
8932                                                 MonoInst *nonbox_call;
8933
8934                                                 /*
8935                                                  * Determine at runtime whenever the called method is defined on object/valuetype/enum, and emit a boxing call
8936                                                  * if needed.
8937                                                  * FIXME: It is possible to inline the called method in a lot of cases, i.e. for T_INT,
8938                                                  * the no-box case goes to a method in Int32, while the box case goes to a method in Enum.
8939                                                  */
8940                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
8941
8942                                                 NEW_BBLOCK (cfg, is_ref_bb);
8943                                                 NEW_BBLOCK (cfg, end_bb);
8944
8945                                                 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);
8946                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, box_type->dreg, 1);
8947                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
8948
8949                                                 /* Non-ref case */
8950                                                 nonbox_call = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8951
8952                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
8953
8954                                                 /* Ref case */
8955                                                 MONO_START_BB (cfg, is_ref_bb);
8956                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8957                                                 ins->klass = constrained_class;
8958                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8959                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8960
8961                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
8962
8963                                                 MONO_START_BB (cfg, end_bb);
8964                                                 cfg->cbb = end_bb;
8965
8966                                                 nonbox_call->dreg = ins->dreg;
8967                                         } else {
8968                                                 g_assert (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
8969                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
8970                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8971                                         }
8972                                         goto call_end;
8973                                 } else if (constrained_class->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
8974                                         /*
8975                                          * The type parameter is instantiated as a valuetype,
8976                                          * but that type doesn't override the method we're
8977                                          * calling, so we need to box `this'.
8978                                          */
8979                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8980                                         ins->klass = constrained_class;
8981                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8982                                         CHECK_CFG_EXCEPTION;
8983                                 } else if (!constrained_class->valuetype) {
8984                                         int dreg = alloc_ireg_ref (cfg);
8985
8986                                         /*
8987                                          * The type parameter is instantiated as a reference
8988                                          * type.  We have a managed pointer on the stack, so
8989                                          * we need to dereference it here.
8990                                          */
8991                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
8992                                         ins->type = STACK_OBJ;
8993                                         sp [0] = ins;
8994                                 } else {
8995                                         if (cmethod->klass->valuetype) {
8996                                                 /* Own method */
8997                                         } else {
8998                                                 /* Interface method */
8999                                                 int ioffset, slot;
9000
9001                                                 mono_class_setup_vtable (constrained_class);
9002                                                 CHECK_TYPELOAD (constrained_class);
9003                                                 ioffset = mono_class_interface_offset (constrained_class, cmethod->klass);
9004                                                 if (ioffset == -1)
9005                                                         TYPE_LOAD_ERROR (constrained_class);
9006                                                 slot = mono_method_get_vtable_slot (cmethod);
9007                                                 if (slot == -1)
9008                                                         TYPE_LOAD_ERROR (cmethod->klass);
9009                                                 cmethod = constrained_class->vtable [ioffset + slot];
9010
9011                                                 if (cmethod->klass == mono_defaults.enum_class) {
9012                                                         /* Enum implements some interfaces, so treat this as the first case */
9013                                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9014                                                         ins->klass = constrained_class;
9015                                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9016                                                         CHECK_CFG_EXCEPTION;
9017                                                 }
9018                                         }
9019                                         virtual = 0;
9020                                 }
9021                                 constrained_class = NULL;
9022                         }
9023
9024                         if (check_call_signature (cfg, fsig, sp))
9025                                 UNVERIFIED;
9026
9027                         if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
9028                                 delegate_invoke = TRUE;
9029
9030                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
9031                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9032                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9033                                         emit_widen = FALSE;
9034                                 }
9035
9036                                 goto call_end;
9037                         }
9038
9039                         /* 
9040                          * If the callee is a shared method, then its static cctor
9041                          * might not get called after the call was patched.
9042                          */
9043                         if (cfg->generic_sharing_context && cmethod->klass != method->klass && cmethod->klass->generic_class && mono_method_is_generic_sharable (cmethod, TRUE) && mono_class_needs_cctor_run (cmethod->klass, method)) {
9044                                 emit_generic_class_init (cfg, cmethod->klass);
9045                                 CHECK_TYPELOAD (cmethod->klass);
9046                         }
9047
9048                         check_method_sharing (cfg, cmethod, &pass_vtable, &pass_mrgctx);
9049
9050                         if (cfg->generic_sharing_context) {
9051                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
9052
9053                                 context_used = mini_method_check_context_used (cfg, cmethod);
9054
9055                                 if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9056                                         /* Generic method interface
9057                                            calls are resolved via a
9058                                            helper function and don't
9059                                            need an imt. */
9060                                         if (!cmethod_context || !cmethod_context->method_inst)
9061                                                 pass_imt_from_rgctx = TRUE;
9062                                 }
9063
9064                                 /*
9065                                  * If a shared method calls another
9066                                  * shared method then the caller must
9067                                  * have a generic sharing context
9068                                  * because the magic trampoline
9069                                  * requires it.  FIXME: We shouldn't
9070                                  * have to force the vtable/mrgctx
9071                                  * variable here.  Instead there
9072                                  * should be a flag in the cfg to
9073                                  * request a generic sharing context.
9074                                  */
9075                                 if (context_used &&
9076                                                 ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
9077                                         mono_get_vtable_var (cfg);
9078                         }
9079
9080                         if (pass_vtable) {
9081                                 if (context_used) {
9082                                         vtable_arg = emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
9083                                 } else {
9084                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
9085
9086                                         CHECK_TYPELOAD (cmethod->klass);
9087                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
9088                                 }
9089                         }
9090
9091                         if (pass_mrgctx) {
9092                                 g_assert (!vtable_arg);
9093
9094                                 if (!cfg->compile_aot) {
9095                                         /* 
9096                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
9097                                          * for type load errors before.
9098                                          */
9099                                         mono_class_setup_vtable (cmethod->klass);
9100                                         CHECK_TYPELOAD (cmethod->klass);
9101                                 }
9102
9103                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
9104
9105                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
9106                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
9107                                          MONO_METHOD_IS_FINAL (cmethod)) &&
9108                                         !mono_class_is_marshalbyref (cmethod->klass)) {
9109                                         if (virtual)
9110                                                 check_this = TRUE;
9111                                         virtual = 0;
9112                                 }
9113                         }
9114
9115                         if (pass_imt_from_rgctx) {
9116                                 g_assert (!pass_vtable);
9117
9118                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9119                                         cmethod, MONO_RGCTX_INFO_METHOD);
9120                         }
9121
9122                         if (check_this)
9123                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9124
9125                         /* Calling virtual generic methods */
9126                         if (virtual && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) && 
9127                             !(MONO_METHOD_IS_FINAL (cmethod) && 
9128                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
9129                             fsig->generic_param_count && 
9130                                 !(cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))) {
9131                                 MonoInst *this_temp, *this_arg_temp, *store;
9132                                 MonoInst *iargs [4];
9133                                 gboolean use_imt = FALSE;
9134
9135                                 g_assert (fsig->is_inflated);
9136
9137                                 /* Prevent inlining of methods that contain indirect calls */
9138                                 INLINE_FAILURE ("virtual generic call");
9139
9140                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))
9141                                         GSHAREDVT_FAILURE (*ip);
9142
9143 #if MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK && defined(MONO_ARCH_GSHARED_SUPPORTED)
9144                                 if (cmethod->wrapper_type == MONO_WRAPPER_NONE)
9145                                         use_imt = TRUE;
9146 #endif
9147
9148                                 if (use_imt) {
9149                                         g_assert (!imt_arg);
9150                                         if (!context_used)
9151                                                 g_assert (cmethod->is_inflated);
9152                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
9153                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
9154                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, sp [0], imt_arg, NULL);
9155                                 } else {
9156                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
9157                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
9158                                         MONO_ADD_INS (cfg->cbb, store);
9159
9160                                         /* FIXME: This should be a managed pointer */
9161                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
9162
9163                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
9164                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
9165                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
9166                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
9167                                         addr = mono_emit_jit_icall (cfg,
9168                                                                                                 mono_helper_compile_generic_method, iargs);
9169
9170                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
9171
9172                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9173                                 }
9174
9175                                 goto call_end;
9176                         }
9177
9178                         /*
9179                          * Implement a workaround for the inherent races involved in locking:
9180                          * Monitor.Enter ()
9181                          * try {
9182                          * } finally {
9183                          *    Monitor.Exit ()
9184                          * }
9185                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
9186                          * try block, the Exit () won't be executed, see:
9187                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
9188                          * To work around this, we extend such try blocks to include the last x bytes
9189                          * of the Monitor.Enter () call.
9190                          */
9191                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
9192                                 MonoBasicBlock *tbb;
9193
9194                                 GET_BBLOCK (cfg, tbb, ip + 5);
9195                                 /* 
9196                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
9197                                  * from Monitor.Enter like ArgumentNullException.
9198                                  */
9199                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
9200                                         /* Mark this bblock as needing to be extended */
9201                                         tbb->extend_try_block = TRUE;
9202                                 }
9203                         }
9204
9205                         /* Conversion to a JIT intrinsic */
9206                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
9207                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9208                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9209                                         emit_widen = FALSE;
9210                                 }
9211                                 goto call_end;
9212                         }
9213
9214                         /* Inlining */
9215                         if ((cfg->opt & MONO_OPT_INLINE) &&
9216                                 (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
9217                             mono_method_check_inlining (cfg, cmethod)) {
9218                                 int costs;
9219                                 gboolean always = FALSE;
9220
9221                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
9222                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
9223                                         /* Prevent inlining of methods that call wrappers */
9224                                         INLINE_FAILURE ("wrapper call");
9225                                         cmethod = mono_marshal_get_native_wrapper (cmethod, check_for_pending_exc, FALSE);
9226                                         always = TRUE;
9227                                 }
9228
9229                                 costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, always);
9230                                 if (costs) {
9231                                         cfg->real_offset += 5;
9232
9233                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9234                                                 /* *sp is already set by inline_method */
9235                                                 sp++;
9236                                                 push_res = FALSE;
9237                                         }
9238
9239                                         inline_costs += costs;
9240
9241                                         goto call_end;
9242                                 }
9243                         }
9244
9245                         /* Tail recursion elimination */
9246                         if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
9247                                 gboolean has_vtargs = FALSE;
9248                                 int i;
9249
9250                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9251                                 INLINE_FAILURE ("tail call");
9252
9253                                 /* keep it simple */
9254                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
9255                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
9256                                                 has_vtargs = TRUE;
9257                                 }
9258
9259                                 if (!has_vtargs) {
9260                                         for (i = 0; i < n; ++i)
9261                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9262                                         MONO_INST_NEW (cfg, ins, OP_BR);
9263                                         MONO_ADD_INS (cfg->cbb, ins);
9264                                         tblock = start_bblock->out_bb [0];
9265                                         link_bblock (cfg, cfg->cbb, tblock);
9266                                         ins->inst_target_bb = tblock;
9267                                         start_new_bblock = 1;
9268
9269                                         /* skip the CEE_RET, too */
9270                                         if (ip_in_bb (cfg, cfg->cbb, ip + 5))
9271                                                 skip_ret = TRUE;
9272                                         push_res = FALSE;
9273                                         goto call_end;
9274                                 }
9275                         }
9276
9277                         inline_costs += 10 * num_calls++;
9278
9279                         /*
9280                          * Making generic calls out of gsharedvt methods.
9281                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9282                          * patching gshared method addresses into a gsharedvt method.
9283                          */
9284                         if (cfg->gsharedvt && (mini_is_gsharedvt_signature (cfg, fsig) || cmethod->is_inflated || cmethod->klass->generic_class) &&
9285                                 !(cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY)) {
9286                                 MonoRgctxInfoType info_type;
9287
9288                                 if (virtual) {
9289                                         //if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
9290                                                 //GSHAREDVT_FAILURE (*ip);
9291                                         // disable for possible remoting calls
9292                                         if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
9293                                                 GSHAREDVT_FAILURE (*ip);
9294                                         if (fsig->generic_param_count) {
9295                                                 /* virtual generic call */
9296                                                 g_assert (!imt_arg);
9297                                                 /* Same as the virtual generic case above */
9298                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9299                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9300                                                 /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
9301                                                 vtable_arg = NULL;
9302                                         } else if ((cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !imt_arg) {
9303                                                 /* This can happen when we call a fully instantiated iface method */
9304                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9305                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9306                                                 vtable_arg = NULL;
9307                                         }
9308                                 }
9309
9310                                 if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
9311                                         keep_this_alive = sp [0];
9312
9313                                 if (virtual && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
9314                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
9315                                 else
9316                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
9317                                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
9318
9319                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9320                                 goto call_end;
9321                         }
9322
9323                         /* Generic sharing */
9324
9325                         /*
9326                          * Use this if the callee is gsharedvt sharable too, since
9327                          * at runtime we might find an instantiation so the call cannot
9328                          * be patched (the 'no_patch' code path in mini-trampolines.c).
9329                          */
9330                         if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
9331                                 (!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
9332                                  !mono_class_generic_sharing_enabled (cmethod->klass)) &&
9333                                 (!virtual || MONO_METHOD_IS_FINAL (cmethod) ||
9334                                  !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
9335                                 INLINE_FAILURE ("gshared");
9336
9337                                 g_assert (cfg->generic_sharing_context && cmethod);
9338                                 g_assert (!addr);
9339
9340                                 /*
9341                                  * We are compiling a call to a
9342                                  * generic method from shared code,
9343                                  * which means that we have to look up
9344                                  * the method in the rgctx and do an
9345                                  * indirect call.
9346                                  */
9347                                 if (fsig->hasthis)
9348                                         MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9349
9350                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9351                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9352                                 goto call_end;
9353                         }
9354
9355                         /* Direct calls to icalls */
9356                         if (direct_icall) {
9357                                 MonoMethod *wrapper;
9358                                 int costs;
9359
9360                                 /* Inline the wrapper */
9361                                 wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
9362
9363                                 costs = inline_method (cfg, wrapper, fsig, sp, ip, cfg->real_offset, TRUE);
9364                                 g_assert (costs > 0);
9365                                 cfg->real_offset += 5;
9366
9367                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9368                                         /* *sp is already set by inline_method */
9369                                         sp++;
9370                                         push_res = FALSE;
9371                                 }
9372
9373                                 inline_costs += costs;
9374
9375                                 goto call_end;
9376                         }
9377                                         
9378                         /* Array methods */
9379                         if (array_rank) {
9380                                 MonoInst *addr;
9381
9382                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
9383                                         MonoInst *val = sp [fsig->param_count];
9384
9385                                         if (val->type == STACK_OBJ) {
9386                                                 MonoInst *iargs [2];
9387
9388                                                 iargs [0] = sp [0];
9389                                                 iargs [1] = val;
9390                                                 
9391                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
9392                                         }
9393                                         
9394                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
9395                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
9396                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !(val->opcode == OP_PCONST && val->inst_c0 == 0))
9397                                                 emit_write_barrier (cfg, addr, val);
9398                                         if (cfg->gen_write_barriers && mini_is_gsharedvt_klass (cfg, cmethod->klass))
9399                                                 GSHAREDVT_FAILURE (*ip);
9400                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
9401                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9402
9403                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
9404                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
9405                                         if (!cmethod->klass->element_class->valuetype && !readonly)
9406                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
9407                                         CHECK_TYPELOAD (cmethod->klass);
9408                                         
9409                                         readonly = FALSE;
9410                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9411                                         ins = addr;
9412                                 } else {
9413                                         g_assert_not_reached ();
9414                                 }
9415
9416                                 emit_widen = FALSE;
9417                                 goto call_end;
9418                         }
9419
9420                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL);
9421                         if (ins)
9422                                 goto call_end;
9423
9424                         /* Tail prefix / tail call optimization */
9425
9426                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
9427                         /* FIXME: runtime generic context pointer for jumps? */
9428                         /* FIXME: handle this for generic sharing eventually */
9429                         if ((ins_flag & MONO_INST_TAILCALL) &&
9430                                 !vtable_arg && !cfg->generic_sharing_context && is_supported_tail_call (cfg, method, cmethod, fsig, call_opcode))
9431                                 supported_tail_call = TRUE;
9432
9433                         if (supported_tail_call) {
9434                                 MonoCallInst *call;
9435
9436                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9437                                 INLINE_FAILURE ("tail call");
9438
9439                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
9440
9441                                 if (ARCH_HAVE_OP_TAIL_CALL) {
9442                                         /* Handle tail calls similarly to normal calls */
9443                                         tail_call = TRUE;
9444                                 } else {
9445                                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
9446
9447                                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9448                                         call->tail_call = TRUE;
9449                                         call->method = cmethod;
9450                                         call->signature = mono_method_signature (cmethod);
9451
9452                                         /*
9453                                          * We implement tail calls by storing the actual arguments into the 
9454                                          * argument variables, then emitting a CEE_JMP.
9455                                          */
9456                                         for (i = 0; i < n; ++i) {
9457                                                 /* Prevent argument from being register allocated */
9458                                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
9459                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9460                                         }
9461                                         ins = (MonoInst*)call;
9462                                         ins->inst_p0 = cmethod;
9463                                         ins->inst_p1 = arg_array [0];
9464                                         MONO_ADD_INS (cfg->cbb, ins);
9465                                         link_bblock (cfg, cfg->cbb, end_bblock);
9466                                         start_new_bblock = 1;
9467
9468                                         // FIXME: Eliminate unreachable epilogs
9469
9470                                         /*
9471                                          * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9472                                          * only reachable from this call.
9473                                          */
9474                                         GET_BBLOCK (cfg, tblock, ip + 5);
9475                                         if (tblock == cfg->cbb || tblock->in_count == 0)
9476                                                 skip_ret = TRUE;
9477                                         push_res = FALSE;
9478
9479                                         goto call_end;
9480                                 }
9481                         }
9482
9483                         /* 
9484                          * Synchronized wrappers.
9485                          * Its hard to determine where to replace a method with its synchronized
9486                          * wrapper without causing an infinite recursion. The current solution is
9487                          * to add the synchronized wrapper in the trampolines, and to
9488                          * change the called method to a dummy wrapper, and resolve that wrapper
9489                          * to the real method in mono_jit_compile_method ().
9490                          */
9491                         if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
9492                                 MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
9493                                 if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
9494                                         cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
9495                         }
9496
9497                         /* Common call */
9498                         INLINE_FAILURE ("call");
9499                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual ? sp [0] : NULL,
9500                                                                                           imt_arg, vtable_arg);
9501
9502                         if (tail_call) {
9503                                 link_bblock (cfg, cfg->cbb, end_bblock);
9504                                 start_new_bblock = 1;
9505
9506                                 // FIXME: Eliminate unreachable epilogs
9507
9508                                 /*
9509                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9510                                  * only reachable from this call.
9511                                  */
9512                                 GET_BBLOCK (cfg, tblock, ip + 5);
9513                                 if (tblock == cfg->cbb || tblock->in_count == 0)
9514                                         skip_ret = TRUE;
9515                                 push_res = FALSE;
9516                         }
9517
9518                         call_end:
9519
9520                         /* End of call, INS should contain the result of the call, if any */
9521
9522                         if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
9523                                 g_assert (ins);
9524                                 if (emit_widen)
9525                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
9526                                 else
9527                                         *sp++ = ins;
9528                         }
9529
9530                         if (keep_this_alive) {
9531                                 MonoInst *dummy_use;
9532
9533                                 /* See mono_emit_method_call_full () */
9534                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
9535                         }
9536
9537                         CHECK_CFG_EXCEPTION;
9538
9539                         ip += 5;
9540                         if (skip_ret) {
9541                                 g_assert (*ip == CEE_RET);
9542                                 ip += 1;
9543                         }
9544                         ins_flag = 0;
9545                         constrained_class = NULL;
9546                         if (need_seq_point)
9547                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
9548                         break;
9549                 }
9550                 case CEE_RET:
9551                         if (cfg->method != method) {
9552                                 /* return from inlined method */
9553                                 /* 
9554                                  * If in_count == 0, that means the ret is unreachable due to
9555                                  * being preceeded by a throw. In that case, inline_method () will
9556                                  * handle setting the return value 
9557                                  * (test case: test_0_inline_throw ()).
9558                                  */
9559                                 if (return_var && cfg->cbb->in_count) {
9560                                         MonoType *ret_type = mono_method_signature (method)->ret;
9561
9562                                         MonoInst *store;
9563                                         CHECK_STACK (1);
9564                                         --sp;
9565
9566                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9567                                                 UNVERIFIED;
9568
9569                                         //g_assert (returnvar != -1);
9570                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
9571                                         cfg->ret_var_set = TRUE;
9572                                 } 
9573                         } else {
9574                                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
9575
9576                                 if (cfg->lmf_var && cfg->cbb->in_count)
9577                                         emit_pop_lmf (cfg);
9578
9579                                 if (cfg->ret) {
9580                                         MonoType *ret_type = mini_get_underlying_type (cfg, mono_method_signature (method)->ret);
9581
9582                                         if (seq_points && !sym_seq_points) {
9583                                                 /* 
9584                                                  * Place a seq point here too even through the IL stack is not
9585                                                  * empty, so a step over on
9586                                                  * call <FOO>
9587                                                  * ret
9588                                                  * will work correctly.
9589                                                  */
9590                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
9591                                                 MONO_ADD_INS (cfg->cbb, ins);
9592                                         }
9593
9594                                         g_assert (!return_var);
9595                                         CHECK_STACK (1);
9596                                         --sp;
9597
9598                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9599                                                 UNVERIFIED;
9600
9601                                         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
9602                                                 MonoInst *ret_addr;
9603
9604                                                 if (!cfg->vret_addr) {
9605                                                         MonoInst *ins;
9606
9607                                                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, (*sp));
9608                                                 } else {
9609                                                         EMIT_NEW_RETLOADA (cfg, ret_addr);
9610
9611                                                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, (*sp)->dreg);
9612                                                         ins->klass = mono_class_from_mono_type (ret_type);
9613                                                 }
9614                                         } else {
9615 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
9616                                                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
9617                                                         MonoInst *iargs [1];
9618                                                         MonoInst *conv;
9619
9620                                                         iargs [0] = *sp;
9621                                                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
9622                                                         mono_arch_emit_setret (cfg, method, conv);
9623                                                 } else {
9624                                                         mono_arch_emit_setret (cfg, method, *sp);
9625                                                 }
9626 #else
9627                                                 mono_arch_emit_setret (cfg, method, *sp);
9628 #endif
9629                                         }
9630                                 }
9631                         }
9632                         if (sp != stack_start)
9633                                 UNVERIFIED;
9634                         MONO_INST_NEW (cfg, ins, OP_BR);
9635                         ip++;
9636                         ins->inst_target_bb = end_bblock;
9637                         MONO_ADD_INS (cfg->cbb, ins);
9638                         link_bblock (cfg, cfg->cbb, end_bblock);
9639                         start_new_bblock = 1;
9640                         break;
9641                 case CEE_BR_S:
9642                         CHECK_OPSIZE (2);
9643                         MONO_INST_NEW (cfg, ins, OP_BR);
9644                         ip++;
9645                         target = ip + 1 + (signed char)(*ip);
9646                         ++ip;
9647                         GET_BBLOCK (cfg, tblock, target);
9648                         link_bblock (cfg, cfg->cbb, tblock);
9649                         ins->inst_target_bb = tblock;
9650                         if (sp != stack_start) {
9651                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9652                                 sp = stack_start;
9653                                 CHECK_UNVERIFIABLE (cfg);
9654                         }
9655                         MONO_ADD_INS (cfg->cbb, ins);
9656                         start_new_bblock = 1;
9657                         inline_costs += BRANCH_COST;
9658                         break;
9659                 case CEE_BEQ_S:
9660                 case CEE_BGE_S:
9661                 case CEE_BGT_S:
9662                 case CEE_BLE_S:
9663                 case CEE_BLT_S:
9664                 case CEE_BNE_UN_S:
9665                 case CEE_BGE_UN_S:
9666                 case CEE_BGT_UN_S:
9667                 case CEE_BLE_UN_S:
9668                 case CEE_BLT_UN_S:
9669                         CHECK_OPSIZE (2);
9670                         CHECK_STACK (2);
9671                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
9672                         ip++;
9673                         target = ip + 1 + *(signed char*)ip;
9674                         ip++;
9675
9676                         ADD_BINCOND (NULL);
9677
9678                         sp = stack_start;
9679                         inline_costs += BRANCH_COST;
9680                         break;
9681                 case CEE_BR:
9682                         CHECK_OPSIZE (5);
9683                         MONO_INST_NEW (cfg, ins, OP_BR);
9684                         ip++;
9685
9686                         target = ip + 4 + (gint32)read32(ip);
9687                         ip += 4;
9688                         GET_BBLOCK (cfg, tblock, target);
9689                         link_bblock (cfg, cfg->cbb, tblock);
9690                         ins->inst_target_bb = tblock;
9691                         if (sp != stack_start) {
9692                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9693                                 sp = stack_start;
9694                                 CHECK_UNVERIFIABLE (cfg);
9695                         }
9696
9697                         MONO_ADD_INS (cfg->cbb, ins);
9698
9699                         start_new_bblock = 1;
9700                         inline_costs += BRANCH_COST;
9701                         break;
9702                 case CEE_BRFALSE_S:
9703                 case CEE_BRTRUE_S:
9704                 case CEE_BRFALSE:
9705                 case CEE_BRTRUE: {
9706                         MonoInst *cmp;
9707                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
9708                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
9709                         guint32 opsize = is_short ? 1 : 4;
9710
9711                         CHECK_OPSIZE (opsize);
9712                         CHECK_STACK (1);
9713                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
9714                                 UNVERIFIED;
9715                         ip ++;
9716                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
9717                         ip += opsize;
9718
9719                         sp--;
9720
9721                         GET_BBLOCK (cfg, tblock, target);
9722                         link_bblock (cfg, cfg->cbb, tblock);
9723                         GET_BBLOCK (cfg, tblock, ip);
9724                         link_bblock (cfg, cfg->cbb, tblock);
9725
9726                         if (sp != stack_start) {
9727                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9728                                 CHECK_UNVERIFIABLE (cfg);
9729                         }
9730
9731                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
9732                         cmp->sreg1 = sp [0]->dreg;
9733                         type_from_op (cfg, cmp, sp [0], NULL);
9734                         CHECK_TYPE (cmp);
9735
9736 #if SIZEOF_REGISTER == 4
9737                         if (cmp->opcode == OP_LCOMPARE_IMM) {
9738                                 /* Convert it to OP_LCOMPARE */
9739                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
9740                                 ins->type = STACK_I8;
9741                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
9742                                 ins->inst_l = 0;
9743                                 MONO_ADD_INS (cfg->cbb, ins);
9744                                 cmp->opcode = OP_LCOMPARE;
9745                                 cmp->sreg2 = ins->dreg;
9746                         }
9747 #endif
9748                         MONO_ADD_INS (cfg->cbb, cmp);
9749
9750                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
9751                         type_from_op (cfg, ins, sp [0], NULL);
9752                         MONO_ADD_INS (cfg->cbb, ins);
9753                         ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
9754                         GET_BBLOCK (cfg, tblock, target);
9755                         ins->inst_true_bb = tblock;
9756                         GET_BBLOCK (cfg, tblock, ip);
9757                         ins->inst_false_bb = tblock;
9758                         start_new_bblock = 2;
9759
9760                         sp = stack_start;
9761                         inline_costs += BRANCH_COST;
9762                         break;
9763                 }
9764                 case CEE_BEQ:
9765                 case CEE_BGE:
9766                 case CEE_BGT:
9767                 case CEE_BLE:
9768                 case CEE_BLT:
9769                 case CEE_BNE_UN:
9770                 case CEE_BGE_UN:
9771                 case CEE_BGT_UN:
9772                 case CEE_BLE_UN:
9773                 case CEE_BLT_UN:
9774                         CHECK_OPSIZE (5);
9775                         CHECK_STACK (2);
9776                         MONO_INST_NEW (cfg, ins, *ip);
9777                         ip++;
9778                         target = ip + 4 + (gint32)read32(ip);
9779                         ip += 4;
9780
9781                         ADD_BINCOND (NULL);
9782
9783                         sp = stack_start;
9784                         inline_costs += BRANCH_COST;
9785                         break;
9786                 case CEE_SWITCH: {
9787                         MonoInst *src1;
9788                         MonoBasicBlock **targets;
9789                         MonoBasicBlock *default_bblock;
9790                         MonoJumpInfoBBTable *table;
9791                         int offset_reg = alloc_preg (cfg);
9792                         int target_reg = alloc_preg (cfg);
9793                         int table_reg = alloc_preg (cfg);
9794                         int sum_reg = alloc_preg (cfg);
9795                         gboolean use_op_switch;
9796
9797                         CHECK_OPSIZE (5);
9798                         CHECK_STACK (1);
9799                         n = read32 (ip + 1);
9800                         --sp;
9801                         src1 = sp [0];
9802                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
9803                                 UNVERIFIED;
9804
9805                         ip += 5;
9806                         CHECK_OPSIZE (n * sizeof (guint32));
9807                         target = ip + n * sizeof (guint32);
9808
9809                         GET_BBLOCK (cfg, default_bblock, target);
9810                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
9811
9812                         targets = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
9813                         for (i = 0; i < n; ++i) {
9814                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
9815                                 targets [i] = tblock;
9816                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
9817                                 ip += 4;
9818                         }
9819
9820                         if (sp != stack_start) {
9821                                 /* 
9822                                  * Link the current bb with the targets as well, so handle_stack_args
9823                                  * will set their in_stack correctly.
9824                                  */
9825                                 link_bblock (cfg, cfg->cbb, default_bblock);
9826                                 for (i = 0; i < n; ++i)
9827                                         link_bblock (cfg, cfg->cbb, targets [i]);
9828
9829                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9830                                 sp = stack_start;
9831                                 CHECK_UNVERIFIABLE (cfg);
9832                         }
9833
9834                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
9835                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
9836
9837                         for (i = 0; i < n; ++i)
9838                                 link_bblock (cfg, cfg->cbb, targets [i]);
9839
9840                         table = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
9841                         table->table = targets;
9842                         table->table_size = n;
9843
9844                         use_op_switch = FALSE;
9845 #ifdef TARGET_ARM
9846                         /* ARM implements SWITCH statements differently */
9847                         /* FIXME: Make it use the generic implementation */
9848                         if (!cfg->compile_aot)
9849                                 use_op_switch = TRUE;
9850 #endif
9851
9852                         if (COMPILE_LLVM (cfg))
9853                                 use_op_switch = TRUE;
9854
9855                         cfg->cbb->has_jump_table = 1;
9856
9857                         if (use_op_switch) {
9858                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
9859                                 ins->sreg1 = src1->dreg;
9860                                 ins->inst_p0 = table;
9861                                 ins->inst_many_bb = targets;
9862                                 ins->klass = GUINT_TO_POINTER (n);
9863                                 MONO_ADD_INS (cfg->cbb, ins);
9864                         } else {
9865                                 if (sizeof (gpointer) == 8)
9866                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
9867                                 else
9868                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
9869
9870 #if SIZEOF_REGISTER == 8
9871                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
9872                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
9873 #endif
9874
9875                                 if (cfg->compile_aot) {
9876                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
9877                                 } else {
9878                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
9879                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
9880                                         ins->inst_p0 = table;
9881                                         ins->dreg = table_reg;
9882                                         MONO_ADD_INS (cfg->cbb, ins);
9883                                 }
9884
9885                                 /* FIXME: Use load_memindex */
9886                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
9887                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
9888                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
9889                         }
9890                         start_new_bblock = 1;
9891                         inline_costs += (BRANCH_COST * 2);
9892                         break;
9893                 }
9894                 case CEE_LDIND_I1:
9895                 case CEE_LDIND_U1:
9896                 case CEE_LDIND_I2:
9897                 case CEE_LDIND_U2:
9898                 case CEE_LDIND_I4:
9899                 case CEE_LDIND_U4:
9900                 case CEE_LDIND_I8:
9901                 case CEE_LDIND_I:
9902                 case CEE_LDIND_R4:
9903                 case CEE_LDIND_R8:
9904                 case CEE_LDIND_REF:
9905                         CHECK_STACK (1);
9906                         --sp;
9907
9908                         switch (*ip) {
9909                         case CEE_LDIND_R4:
9910                         case CEE_LDIND_R8:
9911                                 dreg = alloc_freg (cfg);
9912                                 break;
9913                         case CEE_LDIND_I8:
9914                                 dreg = alloc_lreg (cfg);
9915                                 break;
9916                         case CEE_LDIND_REF:
9917                                 dreg = alloc_ireg_ref (cfg);
9918                                 break;
9919                         default:
9920                                 dreg = alloc_preg (cfg);
9921                         }
9922
9923                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
9924                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
9925                         if (*ip == CEE_LDIND_R4)
9926                                 ins->type = cfg->r4_stack_type;
9927                         ins->flags |= ins_flag;
9928                         MONO_ADD_INS (cfg->cbb, ins);
9929                         *sp++ = ins;
9930                         if (ins_flag & MONO_INST_VOLATILE) {
9931                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
9932                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
9933                         }
9934                         ins_flag = 0;
9935                         ++ip;
9936                         break;
9937                 case CEE_STIND_REF:
9938                 case CEE_STIND_I1:
9939                 case CEE_STIND_I2:
9940                 case CEE_STIND_I4:
9941                 case CEE_STIND_I8:
9942                 case CEE_STIND_R4:
9943                 case CEE_STIND_R8:
9944                 case CEE_STIND_I:
9945                         CHECK_STACK (2);
9946                         sp -= 2;
9947
9948                         if (ins_flag & MONO_INST_VOLATILE) {
9949                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
9950                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
9951                         }
9952
9953                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
9954                         ins->flags |= ins_flag;
9955                         ins_flag = 0;
9956
9957                         MONO_ADD_INS (cfg->cbb, ins);
9958
9959                         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)))
9960                                 emit_write_barrier (cfg, sp [0], sp [1]);
9961
9962                         inline_costs += 1;
9963                         ++ip;
9964                         break;
9965
9966                 case CEE_MUL:
9967                         CHECK_STACK (2);
9968
9969                         MONO_INST_NEW (cfg, ins, (*ip));
9970                         sp -= 2;
9971                         ins->sreg1 = sp [0]->dreg;
9972                         ins->sreg2 = sp [1]->dreg;
9973                         type_from_op (cfg, ins, sp [0], sp [1]);
9974                         CHECK_TYPE (ins);
9975                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
9976
9977                         /* Use the immediate opcodes if possible */
9978                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
9979                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
9980                                 if (imm_opcode != -1) {
9981                                         ins->opcode = imm_opcode;
9982                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
9983                                         ins->sreg2 = -1;
9984
9985                                         NULLIFY_INS (sp [1]);
9986                                 }
9987                         }
9988
9989                         MONO_ADD_INS ((cfg)->cbb, (ins));
9990
9991                         *sp++ = mono_decompose_opcode (cfg, ins);
9992                         ip++;
9993                         break;
9994                 case CEE_ADD:
9995                 case CEE_SUB:
9996                 case CEE_DIV:
9997                 case CEE_DIV_UN:
9998                 case CEE_REM:
9999                 case CEE_REM_UN:
10000                 case CEE_AND:
10001                 case CEE_OR:
10002                 case CEE_XOR:
10003                 case CEE_SHL:
10004                 case CEE_SHR:
10005                 case CEE_SHR_UN:
10006                         CHECK_STACK (2);
10007
10008                         MONO_INST_NEW (cfg, ins, (*ip));
10009                         sp -= 2;
10010                         ins->sreg1 = sp [0]->dreg;
10011                         ins->sreg2 = sp [1]->dreg;
10012                         type_from_op (cfg, ins, sp [0], sp [1]);
10013                         CHECK_TYPE (ins);
10014                         add_widen_op (cfg, ins, &sp [0], &sp [1]);
10015                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
10016
10017                         /* FIXME: Pass opcode to is_inst_imm */
10018
10019                         /* Use the immediate opcodes if possible */
10020                         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)) {
10021                                 int imm_opcode;
10022
10023                                 imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
10024 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
10025                                 /* Keep emulated opcodes which are optimized away later */
10026                                 if ((ins->opcode == OP_IREM_UN || ins->opcode == OP_IDIV_UN_IMM) && (cfg->opt & (MONO_OPT_CONSPROP | MONO_OPT_COPYPROP)) && sp [1]->opcode == OP_ICONST && mono_is_power_of_two (sp [1]->inst_c0) >= 0) {
10027                                         imm_opcode = mono_op_to_op_imm (ins->opcode);
10028                                 }
10029 #endif
10030                                 if (imm_opcode != -1) {
10031                                         ins->opcode = imm_opcode;
10032                                         if (sp [1]->opcode == OP_I8CONST) {
10033 #if SIZEOF_REGISTER == 8
10034                                                 ins->inst_imm = sp [1]->inst_l;
10035 #else
10036                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
10037                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
10038 #endif
10039                                         }
10040                                         else
10041                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
10042                                         ins->sreg2 = -1;
10043
10044                                         /* Might be followed by an instruction added by add_widen_op */
10045                                         if (sp [1]->next == NULL)
10046                                                 NULLIFY_INS (sp [1]);
10047                                 }
10048                         }
10049                         MONO_ADD_INS ((cfg)->cbb, (ins));
10050
10051                         *sp++ = mono_decompose_opcode (cfg, ins);
10052                         ip++;
10053                         break;
10054                 case CEE_NEG:
10055                 case CEE_NOT:
10056                 case CEE_CONV_I1:
10057                 case CEE_CONV_I2:
10058                 case CEE_CONV_I4:
10059                 case CEE_CONV_R4:
10060                 case CEE_CONV_R8:
10061                 case CEE_CONV_U4:
10062                 case CEE_CONV_I8:
10063                 case CEE_CONV_U8:
10064                 case CEE_CONV_OVF_I8:
10065                 case CEE_CONV_OVF_U8:
10066                 case CEE_CONV_R_UN:
10067                         CHECK_STACK (1);
10068
10069                         /* Special case this earlier so we have long constants in the IR */
10070                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
10071                                 int data = sp [-1]->inst_c0;
10072                                 sp [-1]->opcode = OP_I8CONST;
10073                                 sp [-1]->type = STACK_I8;
10074 #if SIZEOF_REGISTER == 8
10075                                 if ((*ip) == CEE_CONV_U8)
10076                                         sp [-1]->inst_c0 = (guint32)data;
10077                                 else
10078                                         sp [-1]->inst_c0 = data;
10079 #else
10080                                 sp [-1]->inst_ls_word = data;
10081                                 if ((*ip) == CEE_CONV_U8)
10082                                         sp [-1]->inst_ms_word = 0;
10083                                 else
10084                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
10085 #endif
10086                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
10087                         }
10088                         else {
10089                                 ADD_UNOP (*ip);
10090                         }
10091                         ip++;
10092                         break;
10093                 case CEE_CONV_OVF_I4:
10094                 case CEE_CONV_OVF_I1:
10095                 case CEE_CONV_OVF_I2:
10096                 case CEE_CONV_OVF_I:
10097                 case CEE_CONV_OVF_U:
10098                         CHECK_STACK (1);
10099
10100                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10101                                 ADD_UNOP (CEE_CONV_OVF_I8);
10102                                 ADD_UNOP (*ip);
10103                         } else {
10104                                 ADD_UNOP (*ip);
10105                         }
10106                         ip++;
10107                         break;
10108                 case CEE_CONV_OVF_U1:
10109                 case CEE_CONV_OVF_U2:
10110                 case CEE_CONV_OVF_U4:
10111                         CHECK_STACK (1);
10112
10113                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10114                                 ADD_UNOP (CEE_CONV_OVF_U8);
10115                                 ADD_UNOP (*ip);
10116                         } else {
10117                                 ADD_UNOP (*ip);
10118                         }
10119                         ip++;
10120                         break;
10121                 case CEE_CONV_OVF_I1_UN:
10122                 case CEE_CONV_OVF_I2_UN:
10123                 case CEE_CONV_OVF_I4_UN:
10124                 case CEE_CONV_OVF_I8_UN:
10125                 case CEE_CONV_OVF_U1_UN:
10126                 case CEE_CONV_OVF_U2_UN:
10127                 case CEE_CONV_OVF_U4_UN:
10128                 case CEE_CONV_OVF_U8_UN:
10129                 case CEE_CONV_OVF_I_UN:
10130                 case CEE_CONV_OVF_U_UN:
10131                 case CEE_CONV_U2:
10132                 case CEE_CONV_U1:
10133                 case CEE_CONV_I:
10134                 case CEE_CONV_U:
10135                         CHECK_STACK (1);
10136                         ADD_UNOP (*ip);
10137                         CHECK_CFG_EXCEPTION;
10138                         ip++;
10139                         break;
10140                 case CEE_ADD_OVF:
10141                 case CEE_ADD_OVF_UN:
10142                 case CEE_MUL_OVF:
10143                 case CEE_MUL_OVF_UN:
10144                 case CEE_SUB_OVF:
10145                 case CEE_SUB_OVF_UN:
10146                         CHECK_STACK (2);
10147                         ADD_BINOP (*ip);
10148                         ip++;
10149                         break;
10150                 case CEE_CPOBJ:
10151                         GSHAREDVT_FAILURE (*ip);
10152                         CHECK_OPSIZE (5);
10153                         CHECK_STACK (2);
10154                         token = read32 (ip + 1);
10155                         klass = mini_get_class (method, token, generic_context);
10156                         CHECK_TYPELOAD (klass);
10157                         sp -= 2;
10158                         if (generic_class_is_reference_type (cfg, klass)) {
10159                                 MonoInst *store, *load;
10160                                 int dreg = alloc_ireg_ref (cfg);
10161
10162                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
10163                                 load->flags |= ins_flag;
10164                                 MONO_ADD_INS (cfg->cbb, load);
10165
10166                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
10167                                 store->flags |= ins_flag;
10168                                 MONO_ADD_INS (cfg->cbb, store);
10169
10170                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
10171                                         emit_write_barrier (cfg, sp [0], sp [1]);
10172                         } else {
10173                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10174                         }
10175                         ins_flag = 0;
10176                         ip += 5;
10177                         break;
10178                 case CEE_LDOBJ: {
10179                         int loc_index = -1;
10180                         int stloc_len = 0;
10181
10182                         CHECK_OPSIZE (5);
10183                         CHECK_STACK (1);
10184                         --sp;
10185                         token = read32 (ip + 1);
10186                         klass = mini_get_class (method, token, generic_context);
10187                         CHECK_TYPELOAD (klass);
10188
10189                         /* Optimize the common ldobj+stloc combination */
10190                         switch (ip [5]) {
10191                         case CEE_STLOC_S:
10192                                 loc_index = ip [6];
10193                                 stloc_len = 2;
10194                                 break;
10195                         case CEE_STLOC_0:
10196                         case CEE_STLOC_1:
10197                         case CEE_STLOC_2:
10198                         case CEE_STLOC_3:
10199                                 loc_index = ip [5] - CEE_STLOC_0;
10200                                 stloc_len = 1;
10201                                 break;
10202                         default:
10203                                 break;
10204                         }
10205
10206                         if ((loc_index != -1) && ip_in_bb (cfg, cfg->cbb, ip + 5)) {
10207                                 CHECK_LOCAL (loc_index);
10208
10209                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10210                                 ins->dreg = cfg->locals [loc_index]->dreg;
10211                                 ins->flags |= ins_flag;
10212                                 ip += 5;
10213                                 ip += stloc_len;
10214                                 if (ins_flag & MONO_INST_VOLATILE) {
10215                                         /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10216                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10217                                 }
10218                                 ins_flag = 0;
10219                                 break;
10220                         }
10221
10222                         /* Optimize the ldobj+stobj combination */
10223                         /* The reference case ends up being a load+store anyway */
10224                         /* Skip this if the operation is volatile. */
10225                         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)) {
10226                                 CHECK_STACK (1);
10227
10228                                 sp --;
10229
10230                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10231
10232                                 ip += 5 + 5;
10233                                 ins_flag = 0;
10234                                 break;
10235                         }
10236
10237                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10238                         ins->flags |= ins_flag;
10239                         *sp++ = ins;
10240
10241                         if (ins_flag & MONO_INST_VOLATILE) {
10242                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10243                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10244                         }
10245
10246                         ip += 5;
10247                         ins_flag = 0;
10248                         inline_costs += 1;
10249                         break;
10250                 }
10251                 case CEE_LDSTR:
10252                         CHECK_STACK_OVF (1);
10253                         CHECK_OPSIZE (5);
10254                         n = read32 (ip + 1);
10255
10256                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
10257                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
10258                                 ins->type = STACK_OBJ;
10259                                 *sp = ins;
10260                         }
10261                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
10262                                 MonoInst *iargs [1];
10263                                 char *str = mono_method_get_wrapper_data (method, n);
10264
10265                                 if (cfg->compile_aot)
10266                                         EMIT_NEW_LDSTRLITCONST (cfg, iargs [0], str);
10267                                 else
10268                                         EMIT_NEW_PCONST (cfg, iargs [0], str);
10269                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
10270                         } else {
10271                                 if (cfg->opt & MONO_OPT_SHARED) {
10272                                         MonoInst *iargs [3];
10273
10274                                         if (cfg->compile_aot) {
10275                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
10276                                         }
10277                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10278                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
10279                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
10280                                         *sp = mono_emit_jit_icall (cfg, mono_ldstr, iargs);
10281                                         mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
10282                                 } else {
10283                                         if (cfg->cbb->out_of_line) {
10284                                                 MonoInst *iargs [2];
10285
10286                                                 if (image == mono_defaults.corlib) {
10287                                                         /* 
10288                                                          * Avoid relocations in AOT and save some space by using a 
10289                                                          * version of helper_ldstr specialized to mscorlib.
10290                                                          */
10291                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
10292                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
10293                                                 } else {
10294                                                         /* Avoid creating the string object */
10295                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
10296                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
10297                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
10298                                                 }
10299                                         } 
10300                                         else
10301                                         if (cfg->compile_aot) {
10302                                                 NEW_LDSTRCONST (cfg, ins, image, n);
10303                                                 *sp = ins;
10304                                                 MONO_ADD_INS (cfg->cbb, ins);
10305                                         } 
10306                                         else {
10307                                                 NEW_PCONST (cfg, ins, NULL);
10308                                                 ins->type = STACK_OBJ;
10309                                                 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
10310                                                 if (!ins->inst_p0)
10311                                                         OUT_OF_MEMORY_FAILURE;
10312
10313                                                 *sp = ins;
10314                                                 MONO_ADD_INS (cfg->cbb, ins);
10315                                         }
10316                                 }
10317                         }
10318
10319                         sp++;
10320                         ip += 5;
10321                         break;
10322                 case CEE_NEWOBJ: {
10323                         MonoInst *iargs [2];
10324                         MonoMethodSignature *fsig;
10325                         MonoInst this_ins;
10326                         MonoInst *alloc;
10327                         MonoInst *vtable_arg = NULL;
10328
10329                         CHECK_OPSIZE (5);
10330                         token = read32 (ip + 1);
10331                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
10332                         if (!cmethod || mono_loader_get_last_error ())
10333                                 LOAD_ERROR;
10334                         fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
10335                         CHECK_CFG_ERROR;
10336
10337                         mono_save_token_info (cfg, image, token, cmethod);
10338
10339                         if (!mono_class_init (cmethod->klass))
10340                                 TYPE_LOAD_ERROR (cmethod->klass);
10341
10342                         context_used = mini_method_check_context_used (cfg, cmethod);
10343
10344                         if (mono_security_core_clr_enabled ())
10345                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
10346
10347                         if (cfg->generic_sharing_context && cmethod && cmethod->klass != method->klass && cmethod->klass->generic_class && mono_method_is_generic_sharable (cmethod, TRUE) && mono_class_needs_cctor_run (cmethod->klass, method)) {
10348                                 emit_generic_class_init (cfg, cmethod->klass);
10349                                 CHECK_TYPELOAD (cmethod->klass);
10350                         }
10351
10352                         /*
10353                         if (cfg->gsharedvt) {
10354                                 if (mini_is_gsharedvt_variable_signature (sig))
10355                                         GSHAREDVT_FAILURE (*ip);
10356                         }
10357                         */
10358
10359                         n = fsig->param_count;
10360                         CHECK_STACK (n);
10361
10362                         /* 
10363                          * Generate smaller code for the common newobj <exception> instruction in
10364                          * argument checking code.
10365                          */
10366                         if (cfg->cbb->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
10367                                 is_exception_class (cmethod->klass) && n <= 2 &&
10368                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
10369                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
10370                                 MonoInst *iargs [3];
10371
10372                                 sp -= n;
10373
10374                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
10375                                 switch (n) {
10376                                 case 0:
10377                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
10378                                         break;
10379                                 case 1:
10380                                         iargs [1] = sp [0];
10381                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
10382                                         break;
10383                                 case 2:
10384                                         iargs [1] = sp [0];
10385                                         iargs [2] = sp [1];
10386                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
10387                                         break;
10388                                 default:
10389                                         g_assert_not_reached ();
10390                                 }
10391
10392                                 ip += 5;
10393                                 inline_costs += 5;
10394                                 break;
10395                         }
10396
10397                         /* move the args to allow room for 'this' in the first position */
10398                         while (n--) {
10399                                 --sp;
10400                                 sp [1] = sp [0];
10401                         }
10402
10403                         /* check_call_signature () requires sp[0] to be set */
10404                         this_ins.type = STACK_OBJ;
10405                         sp [0] = &this_ins;
10406                         if (check_call_signature (cfg, fsig, sp))
10407                                 UNVERIFIED;
10408
10409                         iargs [0] = NULL;
10410
10411                         if (mini_class_is_system_array (cmethod->klass)) {
10412                                 *sp = emit_get_rgctx_method (cfg, context_used,
10413                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
10414
10415                                 /* Avoid varargs in the common case */
10416                                 if (fsig->param_count == 1)
10417                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
10418                                 else if (fsig->param_count == 2)
10419                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
10420                                 else if (fsig->param_count == 3)
10421                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
10422                                 else if (fsig->param_count == 4)
10423                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
10424                                 else
10425                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
10426                         } else if (cmethod->string_ctor) {
10427                                 g_assert (!context_used);
10428                                 g_assert (!vtable_arg);
10429                                 /* we simply pass a null pointer */
10430                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
10431                                 /* now call the string ctor */
10432                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
10433                         } else {
10434                                 if (cmethod->klass->valuetype) {
10435                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
10436                                         emit_init_rvar (cfg, iargs [0]->dreg, &cmethod->klass->byval_arg);
10437                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
10438
10439                                         alloc = NULL;
10440
10441                                         /* 
10442                                          * The code generated by mini_emit_virtual_call () expects
10443                                          * iargs [0] to be a boxed instance, but luckily the vcall
10444                                          * will be transformed into a normal call there.
10445                                          */
10446                                 } else if (context_used) {
10447                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
10448                                         *sp = alloc;
10449                                 } else {
10450                                         MonoVTable *vtable = NULL;
10451
10452                                         if (!cfg->compile_aot)
10453                                                 vtable = mono_class_vtable (cfg->domain, cmethod->klass);
10454                                         CHECK_TYPELOAD (cmethod->klass);
10455
10456                                         /*
10457                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
10458                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
10459                                          * As a workaround, we call class cctors before allocating objects.
10460                                          */
10461                                         if (mini_field_access_needs_cctor_run (cfg, method, cmethod->klass, vtable) && !(g_slist_find (class_inits, cmethod->klass))) {
10462                                                 emit_class_init (cfg, cmethod->klass);
10463                                                 if (cfg->verbose_level > 2)
10464                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
10465                                                 class_inits = g_slist_prepend (class_inits, cmethod->klass);
10466                                         }
10467
10468                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
10469                                         *sp = alloc;
10470                                 }
10471                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
10472
10473                                 if (alloc)
10474                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
10475
10476                                 /* Now call the actual ctor */
10477                                 handle_ctor_call (cfg, cmethod, fsig, context_used, sp, ip, &inline_costs);
10478                                 CHECK_CFG_EXCEPTION;
10479                         }
10480
10481                         if (alloc == NULL) {
10482                                 /* Valuetype */
10483                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
10484                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
10485                                 *sp++= ins;
10486                         } else {
10487                                 *sp++ = alloc;
10488                         }
10489                         
10490                         ip += 5;
10491                         inline_costs += 5;
10492                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip - header->code)))
10493                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10494                         break;
10495                 }
10496                 case CEE_CASTCLASS:
10497                         CHECK_STACK (1);
10498                         --sp;
10499                         CHECK_OPSIZE (5);
10500                         token = read32 (ip + 1);
10501                         klass = mini_get_class (method, token, generic_context);
10502                         CHECK_TYPELOAD (klass);
10503                         if (sp [0]->type != STACK_OBJ)
10504                                 UNVERIFIED;
10505
10506                         ins = handle_castclass (cfg, klass, *sp, ip, &inline_costs);
10507                         CHECK_CFG_EXCEPTION;
10508
10509                         *sp ++ = ins;
10510                         ip += 5;
10511                         break;
10512                 case CEE_ISINST: {
10513                         CHECK_STACK (1);
10514                         --sp;
10515                         CHECK_OPSIZE (5);
10516                         token = read32 (ip + 1);
10517                         klass = mini_get_class (method, token, generic_context);
10518                         CHECK_TYPELOAD (klass);
10519                         if (sp [0]->type != STACK_OBJ)
10520                                 UNVERIFIED;
10521  
10522                         context_used = mini_class_check_context_used (cfg, klass);
10523
10524                         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
10525                                 MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
10526                                 MonoInst *args [3];
10527                                 int idx;
10528
10529                                 /* obj */
10530                                 args [0] = *sp;
10531
10532                                 /* klass */
10533                                 EMIT_NEW_CLASSCONST (cfg, args [1], klass);
10534
10535                                 /* inline cache*/
10536                                 if (cfg->compile_aot) {
10537                                         idx = get_castclass_cache_idx (cfg);
10538                                         EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
10539                                 } else {
10540                                         EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
10541                                 }
10542
10543                                 *sp++ = mono_emit_method_call (cfg, mono_isinst, args, NULL);
10544                                 ip += 5;
10545                                 inline_costs += 2;
10546                         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
10547                                 MonoMethod *mono_isinst;
10548                                 MonoInst *iargs [1];
10549                                 int costs;
10550
10551                                 mono_isinst = mono_marshal_get_isinst (klass); 
10552                                 iargs [0] = sp [0];
10553
10554                                 costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), 
10555                                                                            iargs, ip, cfg->real_offset, TRUE);
10556                                 CHECK_CFG_EXCEPTION;
10557                                 g_assert (costs > 0);
10558                                 
10559                                 ip += 5;
10560                                 cfg->real_offset += 5;
10561
10562                                 *sp++= iargs [0];
10563
10564                                 inline_costs += costs;
10565                         }
10566                         else {
10567                                 ins = handle_isinst (cfg, klass, *sp, context_used);
10568                                 CHECK_CFG_EXCEPTION;
10569                                 *sp ++ = ins;
10570                                 ip += 5;
10571                         }
10572                         break;
10573                 }
10574                 case CEE_UNBOX_ANY: {
10575                         MonoInst *res, *addr;
10576
10577                         CHECK_STACK (1);
10578                         --sp;
10579                         CHECK_OPSIZE (5);
10580                         token = read32 (ip + 1);
10581                         klass = mini_get_class (method, token, generic_context);
10582                         CHECK_TYPELOAD (klass);
10583
10584                         mono_save_token_info (cfg, image, token, klass);
10585
10586                         context_used = mini_class_check_context_used (cfg, klass);
10587
10588                         if (mini_is_gsharedvt_klass (cfg, klass)) {
10589                                 res = handle_unbox_gsharedvt (cfg, klass, *sp);
10590                                 inline_costs += 2;
10591                         } else if (generic_class_is_reference_type (cfg, klass)) {
10592                                 res = handle_castclass (cfg, klass, *sp, ip, &inline_costs);
10593                                 CHECK_CFG_EXCEPTION;
10594                         } else if (mono_class_is_nullable (klass)) {
10595                                 res = handle_unbox_nullable (cfg, *sp, klass, context_used);
10596                         } else {
10597                                 addr = handle_unbox (cfg, klass, sp, context_used);
10598                                 /* LDOBJ */
10599                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
10600                                 res = ins;
10601                                 inline_costs += 2;
10602                         }
10603
10604                         *sp ++ = res;
10605                         ip += 5;
10606                         break;
10607                 }
10608                 case CEE_BOX: {
10609                         MonoInst *val;
10610                         MonoClass *enum_class;
10611                         MonoMethod *has_flag;
10612
10613                         CHECK_STACK (1);
10614                         --sp;
10615                         val = *sp;
10616                         CHECK_OPSIZE (5);
10617                         token = read32 (ip + 1);
10618                         klass = mini_get_class (method, token, generic_context);
10619                         CHECK_TYPELOAD (klass);
10620
10621                         mono_save_token_info (cfg, image, token, klass);
10622
10623                         context_used = mini_class_check_context_used (cfg, klass);
10624
10625                         if (generic_class_is_reference_type (cfg, klass)) {
10626                                 *sp++ = val;
10627                                 ip += 5;
10628                                 break;
10629                         }
10630
10631                         if (klass == mono_defaults.void_class)
10632                                 UNVERIFIED;
10633                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
10634                                 UNVERIFIED;
10635                         /* frequent check in generic code: box (struct), brtrue */
10636
10637                         /*
10638                          * Look for:
10639                          *
10640                          *   <push int/long ptr>
10641                          *   <push int/long>
10642                          *   box MyFlags
10643                          *   constrained. MyFlags
10644                          *   callvirt instace bool class [mscorlib] System.Enum::HasFlag (class [mscorlib] System.Enum)
10645                          *
10646                          * If we find this sequence and the operand types on box and constrained
10647                          * are equal, we can emit a specialized instruction sequence instead of
10648                          * the very slow HasFlag () call.
10649                          */
10650                         if ((cfg->opt & MONO_OPT_INTRINS) &&
10651                             /* Cheap checks first. */
10652                             ip + 5 + 6 + 5 < end &&
10653                             ip [5] == CEE_PREFIX1 &&
10654                             ip [6] == CEE_CONSTRAINED_ &&
10655                             ip [11] == CEE_CALLVIRT &&
10656                             ip_in_bb (cfg, cfg->cbb, ip + 5 + 6 + 5) &&
10657                             mono_class_is_enum (klass) &&
10658                             (enum_class = mini_get_class (method, read32 (ip + 7), generic_context)) &&
10659                             (has_flag = mini_get_method (cfg, method, read32 (ip + 12), NULL, generic_context)) &&
10660                             has_flag->klass == mono_defaults.enum_class &&
10661                             !strcmp (has_flag->name, "HasFlag") &&
10662                             has_flag->signature->hasthis &&
10663                             has_flag->signature->param_count == 1) {
10664                                 CHECK_TYPELOAD (enum_class);
10665
10666                                 if (enum_class == klass) {
10667                                         MonoInst *enum_this, *enum_flag;
10668
10669                                         ip += 5 + 6 + 5;
10670                                         --sp;
10671
10672                                         enum_this = sp [0];
10673                                         enum_flag = sp [1];
10674
10675                                         *sp++ = handle_enum_has_flag (cfg, klass, enum_this, enum_flag);
10676                                         break;
10677                                 }
10678                         }
10679
10680                         // FIXME: LLVM can't handle the inconsistent bb linking
10681                         if (!mono_class_is_nullable (klass) &&
10682                                 ip + 5 < end && ip_in_bb (cfg, cfg->cbb, ip + 5) &&
10683                                 (ip [5] == CEE_BRTRUE || 
10684                                  ip [5] == CEE_BRTRUE_S ||
10685                                  ip [5] == CEE_BRFALSE ||
10686                                  ip [5] == CEE_BRFALSE_S)) {
10687                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
10688                                 int dreg;
10689                                 MonoBasicBlock *true_bb, *false_bb;
10690
10691                                 ip += 5;
10692
10693                                 if (cfg->verbose_level > 3) {
10694                                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
10695                                         printf ("<box+brtrue opt>\n");
10696                                 }
10697
10698                                 switch (*ip) {
10699                                 case CEE_BRTRUE_S:
10700                                 case CEE_BRFALSE_S:
10701                                         CHECK_OPSIZE (2);
10702                                         ip++;
10703                                         target = ip + 1 + (signed char)(*ip);
10704                                         ip++;
10705                                         break;
10706                                 case CEE_BRTRUE:
10707                                 case CEE_BRFALSE:
10708                                         CHECK_OPSIZE (5);
10709                                         ip++;
10710                                         target = ip + 4 + (gint)(read32 (ip));
10711                                         ip += 4;
10712                                         break;
10713                                 default:
10714                                         g_assert_not_reached ();
10715                                 }
10716
10717                                 /* 
10718                                  * We need to link both bblocks, since it is needed for handling stack
10719                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
10720                                  * Branching to only one of them would lead to inconsistencies, so
10721                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
10722                                  */
10723                                 GET_BBLOCK (cfg, true_bb, target);
10724                                 GET_BBLOCK (cfg, false_bb, ip);
10725
10726                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
10727                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
10728
10729                                 if (sp != stack_start) {
10730                                         handle_stack_args (cfg, stack_start, sp - stack_start);
10731                                         sp = stack_start;
10732                                         CHECK_UNVERIFIABLE (cfg);
10733                                 }
10734
10735                                 if (COMPILE_LLVM (cfg)) {
10736                                         dreg = alloc_ireg (cfg);
10737                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
10738                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
10739
10740                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
10741                                 } else {
10742                                         /* The JIT can't eliminate the iconst+compare */
10743                                         MONO_INST_NEW (cfg, ins, OP_BR);
10744                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
10745                                         MONO_ADD_INS (cfg->cbb, ins);
10746                                 }
10747
10748                                 start_new_bblock = 1;
10749                                 break;
10750                         }
10751
10752                         *sp++ = handle_box (cfg, val, klass, context_used);
10753
10754                         CHECK_CFG_EXCEPTION;
10755                         ip += 5;
10756                         inline_costs += 1;
10757                         break;
10758                 }
10759                 case CEE_UNBOX: {
10760                         CHECK_STACK (1);
10761                         --sp;
10762                         CHECK_OPSIZE (5);
10763                         token = read32 (ip + 1);
10764                         klass = mini_get_class (method, token, generic_context);
10765                         CHECK_TYPELOAD (klass);
10766
10767                         mono_save_token_info (cfg, image, token, klass);
10768
10769                         context_used = mini_class_check_context_used (cfg, klass);
10770
10771                         if (mono_class_is_nullable (klass)) {
10772                                 MonoInst *val;
10773
10774                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
10775                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
10776
10777                                 *sp++= ins;
10778                         } else {
10779                                 ins = handle_unbox (cfg, klass, sp, context_used);
10780                                 *sp++ = ins;
10781                         }
10782                         ip += 5;
10783                         inline_costs += 2;
10784                         break;
10785                 }
10786                 case CEE_LDFLD:
10787                 case CEE_LDFLDA:
10788                 case CEE_STFLD:
10789                 case CEE_LDSFLD:
10790                 case CEE_LDSFLDA:
10791                 case CEE_STSFLD: {
10792                         MonoClassField *field;
10793 #ifndef DISABLE_REMOTING
10794                         int costs;
10795 #endif
10796                         guint foffset;
10797                         gboolean is_instance;
10798                         int op;
10799                         gpointer addr = NULL;
10800                         gboolean is_special_static;
10801                         MonoType *ftype;
10802                         MonoInst *store_val = NULL;
10803                         MonoInst *thread_ins;
10804
10805                         op = *ip;
10806                         is_instance = (op == CEE_LDFLD || op == CEE_LDFLDA || op == CEE_STFLD);
10807                         if (is_instance) {
10808                                 if (op == CEE_STFLD) {
10809                                         CHECK_STACK (2);
10810                                         sp -= 2;
10811                                         store_val = sp [1];
10812                                 } else {
10813                                         CHECK_STACK (1);
10814                                         --sp;
10815                                 }
10816                                 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
10817                                         UNVERIFIED;
10818                                 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
10819                                         UNVERIFIED;
10820                         } else {
10821                                 if (op == CEE_STSFLD) {
10822                                         CHECK_STACK (1);
10823                                         sp--;
10824                                         store_val = sp [0];
10825                                 }
10826                         }
10827
10828                         CHECK_OPSIZE (5);
10829                         token = read32 (ip + 1);
10830                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
10831                                 field = mono_method_get_wrapper_data (method, token);
10832                                 klass = field->parent;
10833                         }
10834                         else {
10835                                 field = mono_field_from_token_checked (image, token, &klass, generic_context, &cfg->error);
10836                                 CHECK_CFG_ERROR;
10837                         }
10838                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
10839                                 FIELD_ACCESS_FAILURE (method, field);
10840                         mono_class_init (klass);
10841
10842                         /* if the class is Critical then transparent code cannot access it's fields */
10843                         if (!is_instance && mono_security_core_clr_enabled ())
10844                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
10845
10846                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
10847                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
10848                         if (mono_security_core_clr_enabled ())
10849                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
10850                         */
10851
10852                         /*
10853                          * LDFLD etc. is usable on static fields as well, so convert those cases to
10854                          * the static case.
10855                          */
10856                         if (is_instance && field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
10857                                 switch (op) {
10858                                 case CEE_LDFLD:
10859                                         op = CEE_LDSFLD;
10860                                         break;
10861                                 case CEE_STFLD:
10862                                         op = CEE_STSFLD;
10863                                         break;
10864                                 case CEE_LDFLDA:
10865                                         op = CEE_LDSFLDA;
10866                                         break;
10867                                 default:
10868                                         g_assert_not_reached ();
10869                                 }
10870                                 is_instance = FALSE;
10871                         }
10872
10873                         context_used = mini_class_check_context_used (cfg, klass);
10874
10875                         /* INSTANCE CASE */
10876
10877                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
10878                         if (op == CEE_STFLD) {
10879                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
10880                                         UNVERIFIED;
10881 #ifndef DISABLE_REMOTING
10882                                 if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
10883                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
10884                                         MonoInst *iargs [5];
10885
10886                                         GSHAREDVT_FAILURE (op);
10887
10888                                         iargs [0] = sp [0];
10889                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10890                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
10891                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
10892                                                     field->offset);
10893                                         iargs [4] = sp [1];
10894
10895                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
10896                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
10897                                                                                            iargs, ip, cfg->real_offset, TRUE);
10898                                                 CHECK_CFG_EXCEPTION;
10899                                                 g_assert (costs > 0);
10900                                                       
10901                                                 cfg->real_offset += 5;
10902
10903                                                 inline_costs += costs;
10904                                         } else {
10905                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
10906                                         }
10907                                 } else
10908 #endif
10909                                 {
10910                                         MonoInst *store;
10911
10912                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
10913
10914                                         if (mini_is_gsharedvt_klass (cfg, klass)) {
10915                                                 MonoInst *offset_ins;
10916
10917                                                 context_used = mini_class_check_context_used (cfg, klass);
10918
10919                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10920                                                 dreg = alloc_ireg_mp (cfg);
10921                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10922                                                 /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
10923                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
10924                                         } else {
10925                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
10926                                         }
10927                                         if (sp [0]->opcode != OP_LDADDR)
10928                                                 store->flags |= MONO_INST_FAULT;
10929
10930                                 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)) {
10931                                         /* insert call to write barrier */
10932                                         MonoInst *ptr;
10933                                         int dreg;
10934
10935                                         dreg = alloc_ireg_mp (cfg);
10936                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
10937                                         emit_write_barrier (cfg, ptr, sp [1]);
10938                                 }
10939
10940                                         store->flags |= ins_flag;
10941                                 }
10942                                 ins_flag = 0;
10943                                 ip += 5;
10944                                 break;
10945                         }
10946
10947 #ifndef DISABLE_REMOTING
10948                         if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
10949                                 MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
10950                                 MonoInst *iargs [4];
10951
10952                                 GSHAREDVT_FAILURE (op);
10953
10954                                 iargs [0] = sp [0];
10955                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10956                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
10957                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
10958                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
10959                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
10960                                                                                    iargs, ip, cfg->real_offset, TRUE);
10961                                         CHECK_CFG_EXCEPTION;
10962                                         g_assert (costs > 0);
10963                                                       
10964                                         cfg->real_offset += 5;
10965
10966                                         *sp++ = iargs [0];
10967
10968                                         inline_costs += costs;
10969                                 } else {
10970                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
10971                                         *sp++ = ins;
10972                                 }
10973                         } else 
10974 #endif
10975                         if (is_instance) {
10976                                 if (sp [0]->type == STACK_VTYPE) {
10977                                         MonoInst *var;
10978
10979                                         /* Have to compute the address of the variable */
10980
10981                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
10982                                         if (!var)
10983                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
10984                                         else
10985                                                 g_assert (var->klass == klass);
10986                                         
10987                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
10988                                         sp [0] = ins;
10989                                 }
10990
10991                                 if (op == CEE_LDFLDA) {
10992                                         if (sp [0]->type == STACK_OBJ) {
10993                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
10994                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
10995                                         }
10996
10997                                         dreg = alloc_ireg_mp (cfg);
10998
10999                                         if (mini_is_gsharedvt_klass (cfg, klass)) {
11000                                                 MonoInst *offset_ins;
11001
11002                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11003                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11004                                         } else {
11005                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
11006                                         }
11007                                         ins->klass = mono_class_from_mono_type (field->type);
11008                                         ins->type = STACK_MP;
11009                                         *sp++ = ins;
11010                                 } else {
11011                                         MonoInst *load;
11012
11013                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
11014
11015                                         if (mini_is_gsharedvt_klass (cfg, klass)) {
11016                                                 MonoInst *offset_ins;
11017
11018                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11019                                                 dreg = alloc_ireg_mp (cfg);
11020                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11021                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
11022                                         } else {
11023                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
11024                                         }
11025                                         load->flags |= ins_flag;
11026                                         if (sp [0]->opcode != OP_LDADDR)
11027                                                 load->flags |= MONO_INST_FAULT;
11028                                         *sp++ = load;
11029                                 }
11030                         }
11031
11032                         if (is_instance) {
11033                                 ins_flag = 0;
11034                                 ip += 5;
11035                                 break;
11036                         }
11037
11038                         /* STATIC CASE */
11039                         context_used = mini_class_check_context_used (cfg, klass);
11040
11041                         ftype = mono_field_get_type (field);
11042
11043                         if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL)
11044                                 UNVERIFIED;
11045
11046                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
11047                          * to be called here.
11048                          */
11049                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
11050                                 mono_class_vtable (cfg->domain, klass);
11051                                 CHECK_TYPELOAD (klass);
11052                         }
11053                         mono_domain_lock (cfg->domain);
11054                         if (cfg->domain->special_static_fields)
11055                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
11056                         mono_domain_unlock (cfg->domain);
11057
11058                         is_special_static = mono_class_field_is_special_static (field);
11059
11060                         if (is_special_static && ((gsize)addr & 0x80000000) == 0)
11061                                 thread_ins = mono_get_thread_intrinsic (cfg);
11062                         else
11063                                 thread_ins = NULL;
11064
11065                         /* Generate IR to compute the field address */
11066                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && thread_ins && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
11067                                 /*
11068                                  * Fast access to TLS data
11069                                  * Inline version of get_thread_static_data () in
11070                                  * threads.c.
11071                                  */
11072                                 guint32 offset;
11073                                 int idx, static_data_reg, array_reg, dreg;
11074
11075                                 GSHAREDVT_FAILURE (op);
11076
11077                                 MONO_ADD_INS (cfg->cbb, thread_ins);
11078                                 static_data_reg = alloc_ireg (cfg);
11079                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
11080
11081                                 if (cfg->compile_aot) {
11082                                         int offset_reg, offset2_reg, idx_reg;
11083
11084                                         /* For TLS variables, this will return the TLS offset */
11085                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
11086                                         offset_reg = ins->dreg;
11087                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
11088                                         idx_reg = alloc_ireg (cfg);
11089                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, idx_reg, offset_reg, 0x3f);
11090                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
11091                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
11092                                         array_reg = alloc_ireg (cfg);
11093                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
11094                                         offset2_reg = alloc_ireg (cfg);
11095                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, offset2_reg, offset_reg, 6);
11096                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset2_reg, 0x1ffffff);
11097                                         dreg = alloc_ireg (cfg);
11098                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
11099                                 } else {
11100                                         offset = (gsize)addr & 0x7fffffff;
11101                                         idx = offset & 0x3f;
11102
11103                                         array_reg = alloc_ireg (cfg);
11104                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
11105                                         dreg = alloc_ireg (cfg);
11106                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, ((offset >> 6) & 0x1ffffff));
11107                                 }
11108                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
11109                                         (cfg->compile_aot && is_special_static) ||
11110                                         (context_used && is_special_static)) {
11111                                 MonoInst *iargs [2];
11112
11113                                 g_assert (field->parent);
11114                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11115                                 if (context_used) {
11116                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
11117                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
11118                                 } else {
11119                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11120                                 }
11121                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11122                         } else if (context_used) {
11123                                 MonoInst *static_data;
11124
11125                                 /*
11126                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
11127                                         method->klass->name_space, method->klass->name, method->name,
11128                                         depth, field->offset);
11129                                 */
11130
11131                                 if (mono_class_needs_cctor_run (klass, method))
11132                                         emit_generic_class_init (cfg, klass);
11133
11134                                 /*
11135                                  * The pointer we're computing here is
11136                                  *
11137                                  *   super_info.static_data + field->offset
11138                                  */
11139                                 static_data = emit_get_rgctx_klass (cfg, context_used,
11140                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
11141
11142                                 if (mini_is_gsharedvt_klass (cfg, klass)) {
11143                                         MonoInst *offset_ins;
11144
11145                                         offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11146                                         dreg = alloc_ireg_mp (cfg);
11147                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
11148                                 } else if (field->offset == 0) {
11149                                         ins = static_data;
11150                                 } else {
11151                                         int addr_reg = mono_alloc_preg (cfg);
11152                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
11153                                 }
11154                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
11155                                 MonoInst *iargs [2];
11156
11157                                 g_assert (field->parent);
11158                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11159                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11160                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11161                         } else {
11162                                 MonoVTable *vtable = NULL;
11163
11164                                 if (!cfg->compile_aot)
11165                                         vtable = mono_class_vtable (cfg->domain, klass);
11166                                 CHECK_TYPELOAD (klass);
11167
11168                                 if (!addr) {
11169                                         if (mini_field_access_needs_cctor_run (cfg, method, klass, vtable)) {
11170                                                 if (!(g_slist_find (class_inits, klass))) {
11171                                                         emit_class_init (cfg, klass);
11172                                                         if (cfg->verbose_level > 2)
11173                                                                 printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
11174                                                         class_inits = g_slist_prepend (class_inits, klass);
11175                                                 }
11176                                         } else {
11177                                                 if (cfg->run_cctors) {
11178                                                         MonoException *ex;
11179                                                         /* This makes so that inline cannot trigger */
11180                                                         /* .cctors: too many apps depend on them */
11181                                                         /* running with a specific order... */
11182                                                         g_assert (vtable);
11183                                                         if (! vtable->initialized)
11184                                                                 INLINE_FAILURE ("class init");
11185                                                         ex = mono_runtime_class_init_full (vtable, FALSE);
11186                                                         if (ex) {
11187                                                                 set_exception_object (cfg, ex);
11188                                                                 goto exception_exit;
11189                                                         }
11190                                                 }
11191                                         }
11192                                         if (cfg->compile_aot)
11193                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
11194                                         else {
11195                                                 g_assert (vtable);
11196                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11197                                                 g_assert (addr);
11198                                                 EMIT_NEW_PCONST (cfg, ins, addr);
11199                                         }
11200                                 } else {
11201                                         MonoInst *iargs [1];
11202                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
11203                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
11204                                 }
11205                         }
11206
11207                         /* Generate IR to do the actual load/store operation */
11208
11209                         if ((op == CEE_STFLD || op == CEE_STSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11210                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11211                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11212                         }
11213
11214                         if (op == CEE_LDSFLDA) {
11215                                 ins->klass = mono_class_from_mono_type (ftype);
11216                                 ins->type = STACK_PTR;
11217                                 *sp++ = ins;
11218                         } else if (op == CEE_STSFLD) {
11219                                 MonoInst *store;
11220
11221                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
11222                                 store->flags |= ins_flag;
11223                         } else {
11224                                 gboolean is_const = FALSE;
11225                                 MonoVTable *vtable = NULL;
11226                                 gpointer addr = NULL;
11227
11228                                 if (!context_used) {
11229                                         vtable = mono_class_vtable (cfg->domain, klass);
11230                                         CHECK_TYPELOAD (klass);
11231                                 }
11232                                 if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) ||
11233                                                 (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) {
11234                                         int ro_type = ftype->type;
11235                                         if (!addr)
11236                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11237                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
11238                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
11239                                         }
11240
11241                                         GSHAREDVT_FAILURE (op);
11242
11243                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
11244                                         is_const = TRUE;
11245                                         switch (ro_type) {
11246                                         case MONO_TYPE_BOOLEAN:
11247                                         case MONO_TYPE_U1:
11248                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
11249                                                 sp++;
11250                                                 break;
11251                                         case MONO_TYPE_I1:
11252                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
11253                                                 sp++;
11254                                                 break;                                          
11255                                         case MONO_TYPE_CHAR:
11256                                         case MONO_TYPE_U2:
11257                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
11258                                                 sp++;
11259                                                 break;
11260                                         case MONO_TYPE_I2:
11261                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
11262                                                 sp++;
11263                                                 break;
11264                                                 break;
11265                                         case MONO_TYPE_I4:
11266                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
11267                                                 sp++;
11268                                                 break;                                          
11269                                         case MONO_TYPE_U4:
11270                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
11271                                                 sp++;
11272                                                 break;
11273                                         case MONO_TYPE_I:
11274                                         case MONO_TYPE_U:
11275                                         case MONO_TYPE_PTR:
11276                                         case MONO_TYPE_FNPTR:
11277                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11278                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
11279                                                 sp++;
11280                                                 break;
11281                                         case MONO_TYPE_STRING:
11282                                         case MONO_TYPE_OBJECT:
11283                                         case MONO_TYPE_CLASS:
11284                                         case MONO_TYPE_SZARRAY:
11285                                         case MONO_TYPE_ARRAY:
11286                                                 if (!mono_gc_is_moving ()) {
11287                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11288                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
11289                                                         sp++;
11290                                                 } else {
11291                                                         is_const = FALSE;
11292                                                 }
11293                                                 break;
11294                                         case MONO_TYPE_I8:
11295                                         case MONO_TYPE_U8:
11296                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
11297                                                 sp++;
11298                                                 break;
11299                                         case MONO_TYPE_R4:
11300                                         case MONO_TYPE_R8:
11301                                         case MONO_TYPE_VALUETYPE:
11302                                         default:
11303                                                 is_const = FALSE;
11304                                                 break;
11305                                         }
11306                                 }
11307
11308                                 if (!is_const) {
11309                                         MonoInst *load;
11310
11311                                         CHECK_STACK_OVF (1);
11312
11313                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
11314                                         load->flags |= ins_flag;
11315                                         ins_flag = 0;
11316                                         *sp++ = load;
11317                                 }
11318                         }
11319
11320                         if ((op == CEE_LDFLD || op == CEE_LDSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11321                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
11322                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
11323                         }
11324
11325                         ins_flag = 0;
11326                         ip += 5;
11327                         break;
11328                 }
11329                 case CEE_STOBJ:
11330                         CHECK_STACK (2);
11331                         sp -= 2;
11332                         CHECK_OPSIZE (5);
11333                         token = read32 (ip + 1);
11334                         klass = mini_get_class (method, token, generic_context);
11335                         CHECK_TYPELOAD (klass);
11336                         if (ins_flag & MONO_INST_VOLATILE) {
11337                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11338                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11339                         }
11340                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
11341                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
11342                         ins->flags |= ins_flag;
11343                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
11344                                         generic_class_is_reference_type (cfg, klass)) {
11345                                 /* insert call to write barrier */
11346                                 emit_write_barrier (cfg, sp [0], sp [1]);
11347                         }
11348                         ins_flag = 0;
11349                         ip += 5;
11350                         inline_costs += 1;
11351                         break;
11352
11353                         /*
11354                          * Array opcodes
11355                          */
11356                 case CEE_NEWARR: {
11357                         MonoInst *len_ins;
11358                         const char *data_ptr;
11359                         int data_size = 0;
11360                         guint32 field_token;
11361
11362                         CHECK_STACK (1);
11363                         --sp;
11364
11365                         CHECK_OPSIZE (5);
11366                         token = read32 (ip + 1);
11367
11368                         klass = mini_get_class (method, token, generic_context);
11369                         CHECK_TYPELOAD (klass);
11370
11371                         context_used = mini_class_check_context_used (cfg, klass);
11372
11373                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
11374                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_OVF_U4);
11375                                 ins->sreg1 = sp [0]->dreg;
11376                                 ins->type = STACK_I4;
11377                                 ins->dreg = alloc_ireg (cfg);
11378                                 MONO_ADD_INS (cfg->cbb, ins);
11379                                 *sp = mono_decompose_opcode (cfg, ins);
11380                         }
11381
11382                         if (context_used) {
11383                                 MonoInst *args [3];
11384                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11385                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
11386
11387                                 /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
11388
11389                                 /* vtable */
11390                                 args [0] = emit_get_rgctx_klass (cfg, context_used,
11391                                         array_class, MONO_RGCTX_INFO_VTABLE);
11392                                 /* array len */
11393                                 args [1] = sp [0];
11394
11395                                 if (managed_alloc)
11396                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
11397                                 else
11398                                         ins = mono_emit_jit_icall (cfg, mono_array_new_specific, args);
11399                         } else {
11400                                 if (cfg->opt & MONO_OPT_SHARED) {
11401                                         /* Decompose now to avoid problems with references to the domainvar */
11402                                         MonoInst *iargs [3];
11403
11404                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11405                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11406                                         iargs [2] = sp [0];
11407
11408                                         ins = mono_emit_jit_icall (cfg, mono_array_new, iargs);
11409                                 } else {
11410                                         /* Decompose later since it is needed by abcrem */
11411                                         MonoClass *array_type = mono_array_class_get (klass, 1);
11412                                         mono_class_vtable (cfg->domain, array_type);
11413                                         CHECK_TYPELOAD (array_type);
11414
11415                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
11416                                         ins->dreg = alloc_ireg_ref (cfg);
11417                                         ins->sreg1 = sp [0]->dreg;
11418                                         ins->inst_newa_class = klass;
11419                                         ins->type = STACK_OBJ;
11420                                         ins->klass = array_type;
11421                                         MONO_ADD_INS (cfg->cbb, ins);
11422                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11423                                         cfg->cbb->has_array_access = TRUE;
11424
11425                                         /* Needed so mono_emit_load_get_addr () gets called */
11426                                         mono_get_got_var (cfg);
11427                                 }
11428                         }
11429
11430                         len_ins = sp [0];
11431                         ip += 5;
11432                         *sp++ = ins;
11433                         inline_costs += 1;
11434
11435                         /* 
11436                          * we inline/optimize the initialization sequence if possible.
11437                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
11438                          * for small sizes open code the memcpy
11439                          * ensure the rva field is big enough
11440                          */
11441                         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))) {
11442                                 MonoMethod *memcpy_method = get_memcpy_method ();
11443                                 MonoInst *iargs [3];
11444                                 int add_reg = alloc_ireg_mp (cfg);
11445
11446                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, MONO_STRUCT_OFFSET (MonoArray, vector));
11447                                 if (cfg->compile_aot) {
11448                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
11449                                 } else {
11450                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
11451                                 }
11452                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
11453                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
11454                                 ip += 11;
11455                         }
11456
11457                         break;
11458                 }
11459                 case CEE_LDLEN:
11460                         CHECK_STACK (1);
11461                         --sp;
11462                         if (sp [0]->type != STACK_OBJ)
11463                                 UNVERIFIED;
11464
11465                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
11466                         ins->dreg = alloc_preg (cfg);
11467                         ins->sreg1 = sp [0]->dreg;
11468                         ins->type = STACK_I4;
11469                         /* This flag will be inherited by the decomposition */
11470                         ins->flags |= MONO_INST_FAULT;
11471                         MONO_ADD_INS (cfg->cbb, ins);
11472                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11473                         cfg->cbb->has_array_access = TRUE;
11474                         ip ++;
11475                         *sp++ = ins;
11476                         break;
11477                 case CEE_LDELEMA:
11478                         CHECK_STACK (2);
11479                         sp -= 2;
11480                         CHECK_OPSIZE (5);
11481                         if (sp [0]->type != STACK_OBJ)
11482                                 UNVERIFIED;
11483
11484                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11485
11486                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11487                         CHECK_TYPELOAD (klass);
11488                         /* we need to make sure that this array is exactly the type it needs
11489                          * to be for correctness. the wrappers are lax with their usage
11490                          * so we need to ignore them here
11491                          */
11492                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
11493                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11494                                 mini_emit_check_array_type (cfg, sp [0], array_class);
11495                                 CHECK_TYPELOAD (array_class);
11496                         }
11497
11498                         readonly = FALSE;
11499                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11500                         *sp++ = ins;
11501                         ip += 5;
11502                         break;
11503                 case CEE_LDELEM:
11504                 case CEE_LDELEM_I1:
11505                 case CEE_LDELEM_U1:
11506                 case CEE_LDELEM_I2:
11507                 case CEE_LDELEM_U2:
11508                 case CEE_LDELEM_I4:
11509                 case CEE_LDELEM_U4:
11510                 case CEE_LDELEM_I8:
11511                 case CEE_LDELEM_I:
11512                 case CEE_LDELEM_R4:
11513                 case CEE_LDELEM_R8:
11514                 case CEE_LDELEM_REF: {
11515                         MonoInst *addr;
11516
11517                         CHECK_STACK (2);
11518                         sp -= 2;
11519
11520                         if (*ip == CEE_LDELEM) {
11521                                 CHECK_OPSIZE (5);
11522                                 token = read32 (ip + 1);
11523                                 klass = mini_get_class (method, token, generic_context);
11524                                 CHECK_TYPELOAD (klass);
11525                                 mono_class_init (klass);
11526                         }
11527                         else
11528                                 klass = array_access_to_klass (*ip);
11529
11530                         if (sp [0]->type != STACK_OBJ)
11531                                 UNVERIFIED;
11532
11533                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11534
11535                         if (mini_is_gsharedvt_variable_klass (cfg, klass)) {
11536                                 // FIXME-VT: OP_ICONST optimization
11537                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11538                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11539                                 ins->opcode = OP_LOADV_MEMBASE;
11540                         } else if (sp [1]->opcode == OP_ICONST) {
11541                                 int array_reg = sp [0]->dreg;
11542                                 int index_reg = sp [1]->dreg;
11543                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
11544
11545                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
11546                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
11547                         } else {
11548                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11549                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11550                         }
11551                         *sp++ = ins;
11552                         if (*ip == CEE_LDELEM)
11553                                 ip += 5;
11554                         else
11555                                 ++ip;
11556                         break;
11557                 }
11558                 case CEE_STELEM_I:
11559                 case CEE_STELEM_I1:
11560                 case CEE_STELEM_I2:
11561                 case CEE_STELEM_I4:
11562                 case CEE_STELEM_I8:
11563                 case CEE_STELEM_R4:
11564                 case CEE_STELEM_R8:
11565                 case CEE_STELEM_REF:
11566                 case CEE_STELEM: {
11567                         CHECK_STACK (3);
11568                         sp -= 3;
11569
11570                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11571
11572                         if (*ip == CEE_STELEM) {
11573                                 CHECK_OPSIZE (5);
11574                                 token = read32 (ip + 1);
11575                                 klass = mini_get_class (method, token, generic_context);
11576                                 CHECK_TYPELOAD (klass);
11577                                 mono_class_init (klass);
11578                         }
11579                         else
11580                                 klass = array_access_to_klass (*ip);
11581
11582                         if (sp [0]->type != STACK_OBJ)
11583                                 UNVERIFIED;
11584
11585                         emit_array_store (cfg, klass, sp, TRUE);
11586
11587                         if (*ip == CEE_STELEM)
11588                                 ip += 5;
11589                         else
11590                                 ++ip;
11591                         inline_costs += 1;
11592                         break;
11593                 }
11594                 case CEE_CKFINITE: {
11595                         CHECK_STACK (1);
11596                         --sp;
11597
11598                         MONO_INST_NEW (cfg, ins, OP_CKFINITE);
11599                         ins->sreg1 = sp [0]->dreg;
11600                         ins->dreg = alloc_freg (cfg);
11601                         ins->type = STACK_R8;
11602                         MONO_ADD_INS (cfg->cbb, ins);
11603
11604                         *sp++ = mono_decompose_opcode (cfg, ins);
11605
11606                         ++ip;
11607                         break;
11608                 }
11609                 case CEE_REFANYVAL: {
11610                         MonoInst *src_var, *src;
11611
11612                         int klass_reg = alloc_preg (cfg);
11613                         int dreg = alloc_preg (cfg);
11614
11615                         GSHAREDVT_FAILURE (*ip);
11616
11617                         CHECK_STACK (1);
11618                         MONO_INST_NEW (cfg, ins, *ip);
11619                         --sp;
11620                         CHECK_OPSIZE (5);
11621                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11622                         CHECK_TYPELOAD (klass);
11623
11624                         context_used = mini_class_check_context_used (cfg, klass);
11625
11626                         // FIXME:
11627                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
11628                         if (!src_var)
11629                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
11630                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
11631                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass));
11632
11633                         if (context_used) {
11634                                 MonoInst *klass_ins;
11635
11636                                 klass_ins = emit_get_rgctx_klass (cfg, context_used,
11637                                                 klass, MONO_RGCTX_INFO_KLASS);
11638
11639                                 // FIXME:
11640                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
11641                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
11642                         } else {
11643                                 mini_emit_class_check (cfg, klass_reg, klass);
11644                         }
11645                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value));
11646                         ins->type = STACK_MP;
11647                         ins->klass = klass;
11648                         *sp++ = ins;
11649                         ip += 5;
11650                         break;
11651                 }
11652                 case CEE_MKREFANY: {
11653                         MonoInst *loc, *addr;
11654
11655                         GSHAREDVT_FAILURE (*ip);
11656
11657                         CHECK_STACK (1);
11658                         MONO_INST_NEW (cfg, ins, *ip);
11659                         --sp;
11660                         CHECK_OPSIZE (5);
11661                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11662                         CHECK_TYPELOAD (klass);
11663
11664                         context_used = mini_class_check_context_used (cfg, klass);
11665
11666                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
11667                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
11668
11669                         if (context_used) {
11670                                 MonoInst *const_ins;
11671                                 int type_reg = alloc_preg (cfg);
11672
11673                                 const_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
11674                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
11675                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11676                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11677                         } else if (cfg->compile_aot) {
11678                                 int const_reg = alloc_preg (cfg);
11679                                 int type_reg = alloc_preg (cfg);
11680
11681                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
11682                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
11683                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11684                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11685                         } else {
11686                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), &klass->byval_arg);
11687                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), klass);
11688                         }
11689                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
11690
11691                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
11692                         ins->type = STACK_VTYPE;
11693                         ins->klass = mono_defaults.typed_reference_class;
11694                         *sp++ = ins;
11695                         ip += 5;
11696                         break;
11697                 }
11698                 case CEE_LDTOKEN: {
11699                         gpointer handle;
11700                         MonoClass *handle_class;
11701
11702                         CHECK_STACK_OVF (1);
11703
11704                         CHECK_OPSIZE (5);
11705                         n = read32 (ip + 1);
11706
11707                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
11708                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
11709                                 handle = mono_method_get_wrapper_data (method, n);
11710                                 handle_class = mono_method_get_wrapper_data (method, n + 1);
11711                                 if (handle_class == mono_defaults.typehandle_class)
11712                                         handle = &((MonoClass*)handle)->byval_arg;
11713                         }
11714                         else {
11715                                 handle = mono_ldtoken_checked (image, n, &handle_class, generic_context, &cfg->error);
11716                                 CHECK_CFG_ERROR;
11717                         }
11718                         if (!handle)
11719                                 LOAD_ERROR;
11720                         mono_class_init (handle_class);
11721                         if (cfg->generic_sharing_context) {
11722                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
11723                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
11724                                         /* This case handles ldtoken
11725                                            of an open type, like for
11726                                            typeof(Gen<>). */
11727                                         context_used = 0;
11728                                 } else if (handle_class == mono_defaults.typehandle_class) {
11729                                         context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type (handle));
11730                                 } else if (handle_class == mono_defaults.fieldhandle_class)
11731                                         context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
11732                                 else if (handle_class == mono_defaults.methodhandle_class)
11733                                         context_used = mini_method_check_context_used (cfg, handle);
11734                                 else
11735                                         g_assert_not_reached ();
11736                         }
11737
11738                         if ((cfg->opt & MONO_OPT_SHARED) &&
11739                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
11740                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
11741                                 MonoInst *addr, *vtvar, *iargs [3];
11742                                 int method_context_used;
11743
11744                                 method_context_used = mini_method_check_context_used (cfg, method);
11745
11746                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
11747
11748                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
11749                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
11750                                 if (method_context_used) {
11751                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
11752                                                 method, MONO_RGCTX_INFO_METHOD);
11753                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
11754                                 } else {
11755                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
11756                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
11757                                 }
11758                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11759
11760                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11761
11762                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11763                         } else {
11764                                 if ((ip + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 5) && 
11765                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
11766                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
11767                                         (cmethod->klass == mono_defaults.systemtype_class) &&
11768                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
11769                                         MonoClass *tclass = mono_class_from_mono_type (handle);
11770
11771                                         mono_class_init (tclass);
11772                                         if (context_used) {
11773                                                 ins = emit_get_rgctx_klass (cfg, context_used,
11774                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
11775                                         } else if (cfg->compile_aot) {
11776                                                 if (method->wrapper_type) {
11777                                                         mono_error_init (&error); //got to do it since there are multiple conditionals below
11778                                                         if (mono_class_get_checked (tclass->image, tclass->type_token, &error) == tclass && !generic_context) {
11779                                                                 /* Special case for static synchronized wrappers */
11780                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
11781                                                         } else {
11782                                                                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
11783                                                                 /* FIXME: n is not a normal token */
11784                                                                 DISABLE_AOT (cfg);
11785                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11786                                                         }
11787                                                 } else {
11788                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
11789                                                 }
11790                                         } else {
11791                                                 EMIT_NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
11792                                         }
11793                                         ins->type = STACK_OBJ;
11794                                         ins->klass = cmethod->klass;
11795                                         ip += 5;
11796                                 } else {
11797                                         MonoInst *addr, *vtvar;
11798
11799                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
11800
11801                                         if (context_used) {
11802                                                 if (handle_class == mono_defaults.typehandle_class) {
11803                                                         ins = emit_get_rgctx_klass (cfg, context_used,
11804                                                                         mono_class_from_mono_type (handle),
11805                                                                         MONO_RGCTX_INFO_TYPE);
11806                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
11807                                                         ins = emit_get_rgctx_method (cfg, context_used,
11808                                                                         handle, MONO_RGCTX_INFO_METHOD);
11809                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
11810                                                         ins = emit_get_rgctx_field (cfg, context_used,
11811                                                                         handle, MONO_RGCTX_INFO_CLASS_FIELD);
11812                                                 } else {
11813                                                         g_assert_not_reached ();
11814                                                 }
11815                                         } else if (cfg->compile_aot) {
11816                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n, generic_context);
11817                                         } else {
11818                                                 EMIT_NEW_PCONST (cfg, ins, handle);
11819                                         }
11820                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11821                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11822                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11823                                 }
11824                         }
11825
11826                         *sp++ = ins;
11827                         ip += 5;
11828                         break;
11829                 }
11830                 case CEE_THROW:
11831                         CHECK_STACK (1);
11832                         MONO_INST_NEW (cfg, ins, OP_THROW);
11833                         --sp;
11834                         ins->sreg1 = sp [0]->dreg;
11835                         ip++;
11836                         cfg->cbb->out_of_line = TRUE;
11837                         MONO_ADD_INS (cfg->cbb, ins);
11838                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
11839                         MONO_ADD_INS (cfg->cbb, ins);
11840                         sp = stack_start;
11841                         
11842                         link_bblock (cfg, cfg->cbb, end_bblock);
11843                         start_new_bblock = 1;
11844                         break;
11845                 case CEE_ENDFINALLY:
11846                         /* mono_save_seq_point_info () depends on this */
11847                         if (sp != stack_start)
11848                                 emit_seq_point (cfg, method, ip, FALSE, FALSE);
11849                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
11850                         MONO_ADD_INS (cfg->cbb, ins);
11851                         ip++;
11852                         start_new_bblock = 1;
11853
11854                         /*
11855                          * Control will leave the method so empty the stack, otherwise
11856                          * the next basic block will start with a nonempty stack.
11857                          */
11858                         while (sp != stack_start) {
11859                                 sp--;
11860                         }
11861                         break;
11862                 case CEE_LEAVE:
11863                 case CEE_LEAVE_S: {
11864                         GList *handlers;
11865
11866                         if (*ip == CEE_LEAVE) {
11867                                 CHECK_OPSIZE (5);
11868                                 target = ip + 5 + (gint32)read32(ip + 1);
11869                         } else {
11870                                 CHECK_OPSIZE (2);
11871                                 target = ip + 2 + (signed char)(ip [1]);
11872                         }
11873
11874                         /* empty the stack */
11875                         while (sp != stack_start) {
11876                                 sp--;
11877                         }
11878
11879                         /* 
11880                          * If this leave statement is in a catch block, check for a
11881                          * pending exception, and rethrow it if necessary.
11882                          * We avoid doing this in runtime invoke wrappers, since those are called
11883                          * by native code which excepts the wrapper to catch all exceptions.
11884                          */
11885                         for (i = 0; i < header->num_clauses; ++i) {
11886                                 MonoExceptionClause *clause = &header->clauses [i];
11887
11888                                 /* 
11889                                  * Use <= in the final comparison to handle clauses with multiple
11890                                  * leave statements, like in bug #78024.
11891                                  * The ordering of the exception clauses guarantees that we find the
11892                                  * innermost clause.
11893                                  */
11894                                 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) {
11895                                         MonoInst *exc_ins;
11896                                         MonoBasicBlock *dont_throw;
11897
11898                                         /*
11899                                           MonoInst *load;
11900
11901                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
11902                                         */
11903
11904                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
11905
11906                                         NEW_BBLOCK (cfg, dont_throw);
11907
11908                                         /*
11909                                          * Currently, we always rethrow the abort exception, despite the 
11910                                          * fact that this is not correct. See thread6.cs for an example. 
11911                                          * But propagating the abort exception is more important than 
11912                                          * getting the sematics right.
11913                                          */
11914                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
11915                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
11916                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
11917
11918                                         MONO_START_BB (cfg, dont_throw);
11919                                 }
11920                         }
11921
11922                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
11923                                 GList *tmp;
11924                                 MonoExceptionClause *clause;
11925
11926                                 for (tmp = handlers; tmp; tmp = tmp->next) {
11927                                         clause = tmp->data;
11928                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
11929                                         g_assert (tblock);
11930                                         link_bblock (cfg, cfg->cbb, tblock);
11931                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
11932                                         ins->inst_target_bb = tblock;
11933                                         ins->inst_eh_block = clause;
11934                                         MONO_ADD_INS (cfg->cbb, ins);
11935                                         cfg->cbb->has_call_handler = 1;
11936                                         if (COMPILE_LLVM (cfg)) {
11937                                                 MonoBasicBlock *target_bb;
11938
11939                                                 /* 
11940                                                  * Link the finally bblock with the target, since it will
11941                                                  * conceptually branch there.
11942                                                  * FIXME: Have to link the bblock containing the endfinally.
11943                                                  */
11944                                                 GET_BBLOCK (cfg, target_bb, target);
11945                                                 link_bblock (cfg, tblock, target_bb);
11946                                         }
11947                                 }
11948                                 g_list_free (handlers);
11949                         } 
11950
11951                         MONO_INST_NEW (cfg, ins, OP_BR);
11952                         MONO_ADD_INS (cfg->cbb, ins);
11953                         GET_BBLOCK (cfg, tblock, target);
11954                         link_bblock (cfg, cfg->cbb, tblock);
11955                         ins->inst_target_bb = tblock;
11956                         start_new_bblock = 1;
11957
11958                         if (*ip == CEE_LEAVE)
11959                                 ip += 5;
11960                         else
11961                                 ip += 2;
11962
11963                         break;
11964                 }
11965
11966                         /*
11967                          * Mono specific opcodes
11968                          */
11969                 case MONO_CUSTOM_PREFIX: {
11970
11971                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
11972
11973                         CHECK_OPSIZE (2);
11974                         switch (ip [1]) {
11975                         case CEE_MONO_ICALL: {
11976                                 gpointer func;
11977                                 MonoJitICallInfo *info;
11978
11979                                 token = read32 (ip + 2);
11980                                 func = mono_method_get_wrapper_data (method, token);
11981                                 info = mono_find_jit_icall_by_addr (func);
11982                                 if (!info)
11983                                         g_error ("Could not find icall address in wrapper %s", mono_method_full_name (method, 1));
11984                                 g_assert (info);
11985
11986                                 CHECK_STACK (info->sig->param_count);
11987                                 sp -= info->sig->param_count;
11988
11989                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
11990                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
11991                                         *sp++ = ins;
11992
11993                                 ip += 6;
11994                                 inline_costs += 10 * num_calls++;
11995
11996                                 break;
11997                         }
11998                         case CEE_MONO_LDPTR_CARD_TABLE: {
11999                                 int shift_bits;
12000                                 gpointer card_mask;
12001                                 CHECK_STACK_OVF (1);
12002
12003                                 if (cfg->compile_aot)
12004                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
12005                                 else
12006                                         EMIT_NEW_PCONST (cfg, ins, mono_gc_get_card_table (&shift_bits, &card_mask));
12007
12008                                 *sp++ = ins;
12009                                 ip += 2;
12010                                 inline_costs += 10 * num_calls++;
12011                                 break;
12012                         }
12013                         case CEE_MONO_LDPTR_NURSERY_START: {
12014                                 int shift_bits;
12015                                 size_t size;
12016                                 CHECK_STACK_OVF (1);
12017
12018                                 if (cfg->compile_aot)
12019                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_GC_NURSERY_START, NULL);
12020                                 else
12021                                         EMIT_NEW_PCONST (cfg, ins, mono_gc_get_nursery (&shift_bits, &size));
12022
12023                                 *sp++ = ins;
12024                                 ip += 2;
12025                                 inline_costs += 10 * num_calls++;
12026                                 break;
12027                         }
12028                         case CEE_MONO_LDPTR_INT_REQ_FLAG: {
12029                                 CHECK_STACK_OVF (1);
12030
12031                                 if (cfg->compile_aot)
12032                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
12033                                 else
12034                                         EMIT_NEW_PCONST (cfg, ins, mono_thread_interruption_request_flag ());
12035
12036                                 *sp++ = ins;
12037                                 ip += 2;
12038                                 inline_costs += 10 * num_calls++;
12039                                 break;
12040                         }
12041                         case CEE_MONO_LDPTR: {
12042                                 gpointer ptr;
12043
12044                                 CHECK_STACK_OVF (1);
12045                                 CHECK_OPSIZE (6);
12046                                 token = read32 (ip + 2);
12047
12048                                 ptr = mono_method_get_wrapper_data (method, token);
12049                                 EMIT_NEW_PCONST (cfg, ins, ptr);
12050                                 *sp++ = ins;
12051                                 ip += 6;
12052                                 inline_costs += 10 * num_calls++;
12053                                 /* Can't embed random pointers into AOT code */
12054                                 DISABLE_AOT (cfg);
12055                                 break;
12056                         }
12057                         case CEE_MONO_JIT_ICALL_ADDR: {
12058                                 MonoJitICallInfo *callinfo;
12059                                 gpointer ptr;
12060
12061                                 CHECK_STACK_OVF (1);
12062                                 CHECK_OPSIZE (6);
12063                                 token = read32 (ip + 2);
12064
12065                                 ptr = mono_method_get_wrapper_data (method, token);
12066                                 callinfo = mono_find_jit_icall_by_addr (ptr);
12067                                 g_assert (callinfo);
12068                                 EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
12069                                 *sp++ = ins;
12070                                 ip += 6;
12071                                 inline_costs += 10 * num_calls++;
12072                                 break;
12073                         }
12074                         case CEE_MONO_ICALL_ADDR: {
12075                                 MonoMethod *cmethod;
12076                                 gpointer ptr;
12077
12078                                 CHECK_STACK_OVF (1);
12079                                 CHECK_OPSIZE (6);
12080                                 token = read32 (ip + 2);
12081
12082                                 cmethod = mono_method_get_wrapper_data (method, token);
12083
12084                                 if (cfg->compile_aot) {
12085                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
12086                                 } else {
12087                                         ptr = mono_lookup_internal_call (cmethod);
12088                                         g_assert (ptr);
12089                                         EMIT_NEW_PCONST (cfg, ins, ptr);
12090                                 }
12091                                 *sp++ = ins;
12092                                 ip += 6;
12093                                 break;
12094                         }
12095                         case CEE_MONO_VTADDR: {
12096                                 MonoInst *src_var, *src;
12097
12098                                 CHECK_STACK (1);
12099                                 --sp;
12100
12101                                 // FIXME:
12102                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12103                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
12104                                 *sp++ = src;
12105                                 ip += 2;
12106                                 break;
12107                         }
12108                         case CEE_MONO_NEWOBJ: {
12109                                 MonoInst *iargs [2];
12110
12111                                 CHECK_STACK_OVF (1);
12112                                 CHECK_OPSIZE (6);
12113                                 token = read32 (ip + 2);
12114                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12115                                 mono_class_init (klass);
12116                                 NEW_DOMAINCONST (cfg, iargs [0]);
12117                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
12118                                 NEW_CLASSCONST (cfg, iargs [1], klass);
12119                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
12120                                 *sp++ = mono_emit_jit_icall (cfg, mono_object_new, iargs);
12121                                 ip += 6;
12122                                 inline_costs += 10 * num_calls++;
12123                                 break;
12124                         }
12125                         case CEE_MONO_OBJADDR:
12126                                 CHECK_STACK (1);
12127                                 --sp;
12128                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
12129                                 ins->dreg = alloc_ireg_mp (cfg);
12130                                 ins->sreg1 = sp [0]->dreg;
12131                                 ins->type = STACK_MP;
12132                                 MONO_ADD_INS (cfg->cbb, ins);
12133                                 *sp++ = ins;
12134                                 ip += 2;
12135                                 break;
12136                         case CEE_MONO_LDNATIVEOBJ:
12137                                 /*
12138                                  * Similar to LDOBJ, but instead load the unmanaged 
12139                                  * representation of the vtype to the stack.
12140                                  */
12141                                 CHECK_STACK (1);
12142                                 CHECK_OPSIZE (6);
12143                                 --sp;
12144                                 token = read32 (ip + 2);
12145                                 klass = mono_method_get_wrapper_data (method, token);
12146                                 g_assert (klass->valuetype);
12147                                 mono_class_init (klass);
12148
12149                                 {
12150                                         MonoInst *src, *dest, *temp;
12151
12152                                         src = sp [0];
12153                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
12154                                         temp->backend.is_pinvoke = 1;
12155                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
12156                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
12157
12158                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
12159                                         dest->type = STACK_VTYPE;
12160                                         dest->klass = klass;
12161
12162                                         *sp ++ = dest;
12163                                         ip += 6;
12164                                 }
12165                                 break;
12166                         case CEE_MONO_RETOBJ: {
12167                                 /*
12168                                  * Same as RET, but return the native representation of a vtype
12169                                  * to the caller.
12170                                  */
12171                                 g_assert (cfg->ret);
12172                                 g_assert (mono_method_signature (method)->pinvoke); 
12173                                 CHECK_STACK (1);
12174                                 --sp;
12175                                 
12176                                 CHECK_OPSIZE (6);
12177                                 token = read32 (ip + 2);    
12178                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12179
12180                                 if (!cfg->vret_addr) {
12181                                         g_assert (cfg->ret_var_is_local);
12182
12183                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
12184                                 } else {
12185                                         EMIT_NEW_RETLOADA (cfg, ins);
12186                                 }
12187                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
12188                                 
12189                                 if (sp != stack_start)
12190                                         UNVERIFIED;
12191                                 
12192                                 MONO_INST_NEW (cfg, ins, OP_BR);
12193                                 ins->inst_target_bb = end_bblock;
12194                                 MONO_ADD_INS (cfg->cbb, ins);
12195                                 link_bblock (cfg, cfg->cbb, end_bblock);
12196                                 start_new_bblock = 1;
12197                                 ip += 6;
12198                                 break;
12199                         }
12200                         case CEE_MONO_CISINST:
12201                         case CEE_MONO_CCASTCLASS: {
12202                                 int token;
12203                                 CHECK_STACK (1);
12204                                 --sp;
12205                                 CHECK_OPSIZE (6);
12206                                 token = read32 (ip + 2);
12207                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12208                                 if (ip [1] == CEE_MONO_CISINST)
12209                                         ins = handle_cisinst (cfg, klass, sp [0]);
12210                                 else
12211                                         ins = handle_ccastclass (cfg, klass, sp [0]);
12212                                 *sp++ = ins;
12213                                 ip += 6;
12214                                 break;
12215                         }
12216                         case CEE_MONO_SAVE_LMF:
12217                         case CEE_MONO_RESTORE_LMF:
12218 #ifdef MONO_ARCH_HAVE_LMF_OPS
12219                                 MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_SAVE_LMF) ? OP_SAVE_LMF : OP_RESTORE_LMF);
12220                                 MONO_ADD_INS (cfg->cbb, ins);
12221                                 cfg->need_lmf_area = TRUE;
12222 #endif
12223                                 ip += 2;
12224                                 break;
12225                         case CEE_MONO_CLASSCONST:
12226                                 CHECK_STACK_OVF (1);
12227                                 CHECK_OPSIZE (6);
12228                                 token = read32 (ip + 2);
12229                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
12230                                 *sp++ = ins;
12231                                 ip += 6;
12232                                 inline_costs += 10 * num_calls++;
12233                                 break;
12234                         case CEE_MONO_NOT_TAKEN:
12235                                 cfg->cbb->out_of_line = TRUE;
12236                                 ip += 2;
12237                                 break;
12238                         case CEE_MONO_TLS: {
12239                                 int key;
12240
12241                                 CHECK_STACK_OVF (1);
12242                                 CHECK_OPSIZE (6);
12243                                 key = (gint32)read32 (ip + 2);
12244                                 g_assert (key < TLS_KEY_NUM);
12245
12246                                 ins = mono_create_tls_get (cfg, key);
12247                                 if (!ins) {
12248                                         if (cfg->compile_aot) {
12249                                                 DISABLE_AOT (cfg);
12250                                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
12251                                                 ins->dreg = alloc_preg (cfg);
12252                                                 ins->type = STACK_PTR;
12253                                         } else {
12254                                                 g_assert_not_reached ();
12255                                         }
12256                                 }
12257                                 ins->type = STACK_PTR;
12258                                 MONO_ADD_INS (cfg->cbb, ins);
12259                                 *sp++ = ins;
12260                                 ip += 6;
12261                                 break;
12262                         }
12263                         case CEE_MONO_DYN_CALL: {
12264                                 MonoCallInst *call;
12265
12266                                 /* It would be easier to call a trampoline, but that would put an
12267                                  * extra frame on the stack, confusing exception handling. So
12268                                  * implement it inline using an opcode for now.
12269                                  */
12270
12271                                 if (!cfg->dyn_call_var) {
12272                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12273                                         /* prevent it from being register allocated */
12274                                         cfg->dyn_call_var->flags |= MONO_INST_VOLATILE;
12275                                 }
12276
12277                                 /* Has to use a call inst since it local regalloc expects it */
12278                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
12279                                 ins = (MonoInst*)call;
12280                                 sp -= 2;
12281                                 ins->sreg1 = sp [0]->dreg;
12282                                 ins->sreg2 = sp [1]->dreg;
12283                                 MONO_ADD_INS (cfg->cbb, ins);
12284
12285                                 cfg->param_area = MAX (cfg->param_area, MONO_ARCH_DYN_CALL_PARAM_AREA);
12286
12287                                 ip += 2;
12288                                 inline_costs += 10 * num_calls++;
12289
12290                                 break;
12291                         }
12292                         case CEE_MONO_MEMORY_BARRIER: {
12293                                 CHECK_OPSIZE (6);
12294                                 emit_memory_barrier (cfg, (int)read32 (ip + 2));
12295                                 ip += 6;
12296                                 break;
12297                         }
12298                         case CEE_MONO_JIT_ATTACH: {
12299                                 MonoInst *args [16], *domain_ins;
12300                                 MonoInst *ad_ins, *jit_tls_ins;
12301                                 MonoBasicBlock *next_bb = NULL, *call_bb = NULL;
12302
12303                                 cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12304
12305                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12306                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12307
12308                                 ad_ins = mono_get_domain_intrinsic (cfg);
12309                                 jit_tls_ins = mono_get_jit_tls_intrinsic (cfg);
12310
12311                                 if (MONO_ARCH_HAVE_TLS_GET && ad_ins && jit_tls_ins) {
12312                                         NEW_BBLOCK (cfg, next_bb);
12313                                         NEW_BBLOCK (cfg, call_bb);
12314
12315                                         if (cfg->compile_aot) {
12316                                                 /* AOT code is only used in the root domain */
12317                                                 EMIT_NEW_PCONST (cfg, domain_ins, NULL);
12318                                         } else {
12319                                                 EMIT_NEW_PCONST (cfg, domain_ins, cfg->domain);
12320                                         }
12321                                         MONO_ADD_INS (cfg->cbb, ad_ins);
12322                                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, ad_ins->dreg, domain_ins->dreg);
12323                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, call_bb);
12324
12325                                         MONO_ADD_INS (cfg->cbb, jit_tls_ins);
12326                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, jit_tls_ins->dreg, 0);
12327                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, call_bb);
12328
12329                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, next_bb);
12330                                         MONO_START_BB (cfg, call_bb);
12331                                 }
12332
12333                                 if (cfg->compile_aot) {
12334                                         /* AOT code is only used in the root domain */
12335                                         EMIT_NEW_PCONST (cfg, args [0], NULL);
12336                                 } else {
12337                                         EMIT_NEW_PCONST (cfg, args [0], cfg->domain);
12338                                 }
12339                                 ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
12340                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12341
12342                                 if (next_bb)
12343                                         MONO_START_BB (cfg, next_bb);
12344                                 ip += 2;
12345                                 break;
12346                         }
12347                         case CEE_MONO_JIT_DETACH: {
12348                                 MonoInst *args [16];
12349
12350                                 /* Restore the original domain */
12351                                 dreg = alloc_ireg (cfg);
12352                                 EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->orig_domain_var->dreg);
12353                                 mono_emit_jit_icall (cfg, mono_jit_set_domain, args);
12354                                 ip += 2;
12355                                 break;
12356                         }
12357                         default:
12358                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
12359                                 break;
12360                         }
12361                         break;
12362                 }
12363
12364                 case CEE_PREFIX1: {
12365                         CHECK_OPSIZE (2);
12366                         switch (ip [1]) {
12367                         case CEE_ARGLIST: {
12368                                 /* somewhat similar to LDTOKEN */
12369                                 MonoInst *addr, *vtvar;
12370                                 CHECK_STACK_OVF (1);
12371                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
12372
12373                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12374                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
12375
12376                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12377                                 ins->type = STACK_VTYPE;
12378                                 ins->klass = mono_defaults.argumenthandle_class;
12379                                 *sp++ = ins;
12380                                 ip += 2;
12381                                 break;
12382                         }
12383                         case CEE_CEQ:
12384                         case CEE_CGT:
12385                         case CEE_CGT_UN:
12386                         case CEE_CLT:
12387                         case CEE_CLT_UN: {
12388                                 MonoInst *cmp, *arg1, *arg2;
12389
12390                                 CHECK_STACK (2);
12391                                 sp -= 2;
12392                                 arg1 = sp [0];
12393                                 arg2 = sp [1];
12394
12395                                 /*
12396                                  * The following transforms:
12397                                  *    CEE_CEQ    into OP_CEQ
12398                                  *    CEE_CGT    into OP_CGT
12399                                  *    CEE_CGT_UN into OP_CGT_UN
12400                                  *    CEE_CLT    into OP_CLT
12401                                  *    CEE_CLT_UN into OP_CLT_UN
12402                                  */
12403                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
12404
12405                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
12406                                 cmp->sreg1 = arg1->dreg;
12407                                 cmp->sreg2 = arg2->dreg;
12408                                 type_from_op (cfg, cmp, arg1, arg2);
12409                                 CHECK_TYPE (cmp);
12410                                 add_widen_op (cfg, cmp, &arg1, &arg2);
12411                                 if ((arg1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((arg1->type == STACK_PTR) || (arg1->type == STACK_OBJ) || (arg1->type == STACK_MP))))
12412                                         cmp->opcode = OP_LCOMPARE;
12413                                 else if (arg1->type == STACK_R4)
12414                                         cmp->opcode = OP_RCOMPARE;
12415                                 else if (arg1->type == STACK_R8)
12416                                         cmp->opcode = OP_FCOMPARE;
12417                                 else
12418                                         cmp->opcode = OP_ICOMPARE;
12419                                 MONO_ADD_INS (cfg->cbb, cmp);
12420                                 ins->type = STACK_I4;
12421                                 ins->dreg = alloc_dreg (cfg, ins->type);
12422                                 type_from_op (cfg, ins, arg1, arg2);
12423
12424                                 if (cmp->opcode == OP_FCOMPARE || cmp->opcode == OP_RCOMPARE) {
12425                                         /*
12426                                          * The backends expect the fceq opcodes to do the
12427                                          * comparison too.
12428                                          */
12429                                         ins->sreg1 = cmp->sreg1;
12430                                         ins->sreg2 = cmp->sreg2;
12431                                         NULLIFY_INS (cmp);
12432                                 }
12433                                 MONO_ADD_INS (cfg->cbb, ins);
12434                                 *sp++ = ins;
12435                                 ip += 2;
12436                                 break;
12437                         }
12438                         case CEE_LDFTN: {
12439                                 MonoInst *argconst;
12440                                 MonoMethod *cil_method;
12441
12442                                 CHECK_STACK_OVF (1);
12443                                 CHECK_OPSIZE (6);
12444                                 n = read32 (ip + 2);
12445                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12446                                 if (!cmethod || mono_loader_get_last_error ())
12447                                         LOAD_ERROR;
12448                                 mono_class_init (cmethod->klass);
12449
12450                                 mono_save_token_info (cfg, image, n, cmethod);
12451
12452                                 context_used = mini_method_check_context_used (cfg, cmethod);
12453
12454                                 cil_method = cmethod;
12455                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
12456                                         METHOD_ACCESS_FAILURE (method, cil_method);
12457
12458                                 if (mono_security_core_clr_enabled ())
12459                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
12460
12461                                 /* 
12462                                  * Optimize the common case of ldftn+delegate creation
12463                                  */
12464                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
12465                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12466                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12467                                                 MonoInst *target_ins, *handle_ins;
12468                                                 MonoMethod *invoke;
12469                                                 int invoke_context_used;
12470
12471                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12472                                                 if (!invoke || !mono_method_signature (invoke))
12473                                                         LOAD_ERROR;
12474
12475                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12476
12477                                                 target_ins = sp [-1];
12478
12479                                                 if (mono_security_core_clr_enabled ())
12480                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
12481
12482                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
12483                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
12484                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
12485                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
12486                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
12487                                                         }
12488                                                 }
12489
12490                                                 /* FIXME: SGEN support */
12491                                                 if (invoke_context_used == 0) {
12492                                                         ip += 6;
12493                                                         if (cfg->verbose_level > 3)
12494                                                                 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));
12495                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, FALSE))) {
12496                                                                 sp --;
12497                                                                 *sp = handle_ins;
12498                                                                 CHECK_CFG_EXCEPTION;
12499                                                                 ip += 5;
12500                                                                 sp ++;
12501                                                                 break;
12502                                                         }
12503                                                         ip -= 6;
12504                                                 }
12505                                         }
12506                                 }
12507
12508                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
12509                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
12510                                 *sp++ = ins;
12511                                 
12512                                 ip += 6;
12513                                 inline_costs += 10 * num_calls++;
12514                                 break;
12515                         }
12516                         case CEE_LDVIRTFTN: {
12517                                 MonoInst *args [2];
12518
12519                                 CHECK_STACK (1);
12520                                 CHECK_OPSIZE (6);
12521                                 n = read32 (ip + 2);
12522                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12523                                 if (!cmethod || mono_loader_get_last_error ())
12524                                         LOAD_ERROR;
12525                                 mono_class_init (cmethod->klass);
12526  
12527                                 context_used = mini_method_check_context_used (cfg, cmethod);
12528
12529                                 if (mono_security_core_clr_enabled ())
12530                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
12531
12532                                 /*
12533                                  * Optimize the common case of ldvirtftn+delegate creation
12534                                  */
12535                                 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)) {
12536                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12537                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12538                                                 MonoInst *target_ins, *handle_ins;
12539                                                 MonoMethod *invoke;
12540                                                 int invoke_context_used;
12541                                                 gboolean is_virtual = cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL;
12542
12543                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12544                                                 if (!invoke || !mono_method_signature (invoke))
12545                                                         LOAD_ERROR;
12546
12547                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12548
12549                                                 target_ins = sp [-1];
12550
12551                                                 if (mono_security_core_clr_enabled ())
12552                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
12553
12554                                                 /* FIXME: SGEN support */
12555                                                 if (invoke_context_used == 0) {
12556                                                         ip += 6;
12557                                                         if (cfg->verbose_level > 3)
12558                                                                 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));
12559                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, is_virtual))) {
12560                                                                 sp -= 2;
12561                                                                 *sp = handle_ins;
12562                                                                 CHECK_CFG_EXCEPTION;
12563                                                                 ip += 5;
12564                                                                 sp ++;
12565                                                                 break;
12566                                                         }
12567                                                         ip -= 6;
12568                                                 }
12569                                         }
12570                                 }
12571
12572                                 --sp;
12573                                 args [0] = *sp;
12574
12575                                 args [1] = emit_get_rgctx_method (cfg, context_used,
12576                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
12577
12578                                 if (context_used)
12579                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
12580                                 else
12581                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
12582
12583                                 ip += 6;
12584                                 inline_costs += 10 * num_calls++;
12585                                 break;
12586                         }
12587                         case CEE_LDARG:
12588                                 CHECK_STACK_OVF (1);
12589                                 CHECK_OPSIZE (4);
12590                                 n = read16 (ip + 2);
12591                                 CHECK_ARG (n);
12592                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
12593                                 *sp++ = ins;
12594                                 ip += 4;
12595                                 break;
12596                         case CEE_LDARGA:
12597                                 CHECK_STACK_OVF (1);
12598                                 CHECK_OPSIZE (4);
12599                                 n = read16 (ip + 2);
12600                                 CHECK_ARG (n);
12601                                 NEW_ARGLOADA (cfg, ins, n);
12602                                 MONO_ADD_INS (cfg->cbb, ins);
12603                                 *sp++ = ins;
12604                                 ip += 4;
12605                                 break;
12606                         case CEE_STARG:
12607                                 CHECK_STACK (1);
12608                                 --sp;
12609                                 CHECK_OPSIZE (4);
12610                                 n = read16 (ip + 2);
12611                                 CHECK_ARG (n);
12612                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
12613                                         UNVERIFIED;
12614                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
12615                                 ip += 4;
12616                                 break;
12617                         case CEE_LDLOC:
12618                                 CHECK_STACK_OVF (1);
12619                                 CHECK_OPSIZE (4);
12620                                 n = read16 (ip + 2);
12621                                 CHECK_LOCAL (n);
12622                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
12623                                 *sp++ = ins;
12624                                 ip += 4;
12625                                 break;
12626                         case CEE_LDLOCA: {
12627                                 unsigned char *tmp_ip;
12628                                 CHECK_STACK_OVF (1);
12629                                 CHECK_OPSIZE (4);
12630                                 n = read16 (ip + 2);
12631                                 CHECK_LOCAL (n);
12632
12633                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
12634                                         ip = tmp_ip;
12635                                         inline_costs += 1;
12636                                         break;
12637                                 }                       
12638                                 
12639                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
12640                                 *sp++ = ins;
12641                                 ip += 4;
12642                                 break;
12643                         }
12644                         case CEE_STLOC:
12645                                 CHECK_STACK (1);
12646                                 --sp;
12647                                 CHECK_OPSIZE (4);
12648                                 n = read16 (ip + 2);
12649                                 CHECK_LOCAL (n);
12650                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
12651                                         UNVERIFIED;
12652                                 emit_stloc_ir (cfg, sp, header, n);
12653                                 ip += 4;
12654                                 inline_costs += 1;
12655                                 break;
12656                         case CEE_LOCALLOC:
12657                                 CHECK_STACK (1);
12658                                 --sp;
12659                                 if (sp != stack_start) 
12660                                         UNVERIFIED;
12661                                 if (cfg->method != method) 
12662                                         /* 
12663                                          * Inlining this into a loop in a parent could lead to 
12664                                          * stack overflows which is different behavior than the
12665                                          * non-inlined case, thus disable inlining in this case.
12666                                          */
12667                                         INLINE_FAILURE("localloc");
12668
12669                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
12670                                 ins->dreg = alloc_preg (cfg);
12671                                 ins->sreg1 = sp [0]->dreg;
12672                                 ins->type = STACK_PTR;
12673                                 MONO_ADD_INS (cfg->cbb, ins);
12674
12675                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12676                                 if (init_locals)
12677                                         ins->flags |= MONO_INST_INIT;
12678
12679                                 *sp++ = ins;
12680                                 ip += 2;
12681                                 break;
12682                         case CEE_ENDFILTER: {
12683                                 MonoExceptionClause *clause, *nearest;
12684                                 int cc;
12685
12686                                 CHECK_STACK (1);
12687                                 --sp;
12688                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
12689                                         UNVERIFIED;
12690                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
12691                                 ins->sreg1 = (*sp)->dreg;
12692                                 MONO_ADD_INS (cfg->cbb, ins);
12693                                 start_new_bblock = 1;
12694                                 ip += 2;
12695
12696                                 nearest = NULL;
12697                                 for (cc = 0; cc < header->num_clauses; ++cc) {
12698                                         clause = &header->clauses [cc];
12699                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
12700                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
12701                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset)))
12702                                                 nearest = clause;
12703                                 }
12704                                 g_assert (nearest);
12705                                 if ((ip - header->code) != nearest->handler_offset)
12706                                         UNVERIFIED;
12707
12708                                 break;
12709                         }
12710                         case CEE_UNALIGNED_:
12711                                 ins_flag |= MONO_INST_UNALIGNED;
12712                                 /* FIXME: record alignment? we can assume 1 for now */
12713                                 CHECK_OPSIZE (3);
12714                                 ip += 3;
12715                                 break;
12716                         case CEE_VOLATILE_:
12717                                 ins_flag |= MONO_INST_VOLATILE;
12718                                 ip += 2;
12719                                 break;
12720                         case CEE_TAIL_:
12721                                 ins_flag   |= MONO_INST_TAILCALL;
12722                                 cfg->flags |= MONO_CFG_HAS_TAIL;
12723                                 /* Can't inline tail calls at this time */
12724                                 inline_costs += 100000;
12725                                 ip += 2;
12726                                 break;
12727                         case CEE_INITOBJ:
12728                                 CHECK_STACK (1);
12729                                 --sp;
12730                                 CHECK_OPSIZE (6);
12731                                 token = read32 (ip + 2);
12732                                 klass = mini_get_class (method, token, generic_context);
12733                                 CHECK_TYPELOAD (klass);
12734                                 if (generic_class_is_reference_type (cfg, klass))
12735                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
12736                                 else
12737                                         mini_emit_initobj (cfg, *sp, NULL, klass);
12738                                 ip += 6;
12739                                 inline_costs += 1;
12740                                 break;
12741                         case CEE_CONSTRAINED_:
12742                                 CHECK_OPSIZE (6);
12743                                 token = read32 (ip + 2);
12744                                 constrained_class = mini_get_class (method, token, generic_context);
12745                                 CHECK_TYPELOAD (constrained_class);
12746                                 ip += 6;
12747                                 break;
12748                         case CEE_CPBLK:
12749                         case CEE_INITBLK: {
12750                                 MonoInst *iargs [3];
12751                                 CHECK_STACK (3);
12752                                 sp -= 3;
12753
12754                                 /* Skip optimized paths for volatile operations. */
12755                                 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)) {
12756                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
12757                                 } 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)) {
12758                                         /* emit_memset only works when val == 0 */
12759                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
12760                                 } else {
12761                                         MonoInst *call;
12762                                         iargs [0] = sp [0];
12763                                         iargs [1] = sp [1];
12764                                         iargs [2] = sp [2];
12765                                         if (ip [1] == CEE_CPBLK) {
12766                                                 /*
12767                                                  * FIXME: It's unclear whether we should be emitting both the acquire
12768                                                  * and release barriers for cpblk. It is technically both a load and
12769                                                  * store operation, so it seems like that's the sensible thing to do.
12770                                                  *
12771                                                  * FIXME: We emit full barriers on both sides of the operation for
12772                                                  * simplicity. We should have a separate atomic memcpy method instead.
12773                                                  */
12774                                                 MonoMethod *memcpy_method = get_memcpy_method ();
12775
12776                                                 if (ins_flag & MONO_INST_VOLATILE)
12777                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12778
12779                                                 call = mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
12780                                                 call->flags |= ins_flag;
12781
12782                                                 if (ins_flag & MONO_INST_VOLATILE)
12783                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12784                                         } else {
12785                                                 MonoMethod *memset_method = get_memset_method ();
12786                                                 if (ins_flag & MONO_INST_VOLATILE) {
12787                                                         /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
12788                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
12789                                                 }
12790                                                 call = mono_emit_method_call (cfg, memset_method, iargs, NULL);
12791                                                 call->flags |= ins_flag;
12792                                         }
12793                                 }
12794                                 ip += 2;
12795                                 ins_flag = 0;
12796                                 inline_costs += 1;
12797                                 break;
12798                         }
12799                         case CEE_NO_:
12800                                 CHECK_OPSIZE (3);
12801                                 if (ip [2] & 0x1)
12802                                         ins_flag |= MONO_INST_NOTYPECHECK;
12803                                 if (ip [2] & 0x2)
12804                                         ins_flag |= MONO_INST_NORANGECHECK;
12805                                 /* we ignore the no-nullcheck for now since we
12806                                  * really do it explicitly only when doing callvirt->call
12807                                  */
12808                                 ip += 3;
12809                                 break;
12810                         case CEE_RETHROW: {
12811                                 MonoInst *load;
12812                                 int handler_offset = -1;
12813
12814                                 for (i = 0; i < header->num_clauses; ++i) {
12815                                         MonoExceptionClause *clause = &header->clauses [i];
12816                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
12817                                                 handler_offset = clause->handler_offset;
12818                                                 break;
12819                                         }
12820                                 }
12821
12822                                 cfg->cbb->flags |= BB_EXCEPTION_UNSAFE;
12823
12824                                 if (handler_offset == -1)
12825                                         UNVERIFIED;
12826
12827                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
12828                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
12829                                 ins->sreg1 = load->dreg;
12830                                 MONO_ADD_INS (cfg->cbb, ins);
12831
12832                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
12833                                 MONO_ADD_INS (cfg->cbb, ins);
12834
12835                                 sp = stack_start;
12836                                 link_bblock (cfg, cfg->cbb, end_bblock);
12837                                 start_new_bblock = 1;
12838                                 ip += 2;
12839                                 break;
12840                         }
12841                         case CEE_SIZEOF: {
12842                                 guint32 val;
12843                                 int ialign;
12844
12845                                 CHECK_STACK_OVF (1);
12846                                 CHECK_OPSIZE (6);
12847                                 token = read32 (ip + 2);
12848                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !image_is_dynamic (method->klass->image) && !generic_context) {
12849                                         MonoType *type = mono_type_create_from_typespec_checked (image, token, &cfg->error);
12850                                         CHECK_CFG_ERROR;
12851
12852                                         val = mono_type_size (type, &ialign);
12853                                 } else {
12854                                         MonoClass *klass = mini_get_class (method, token, generic_context);
12855                                         CHECK_TYPELOAD (klass);
12856
12857                                         val = mono_type_size (&klass->byval_arg, &ialign);
12858
12859                                         if (mini_is_gsharedvt_klass (cfg, klass))
12860                                                 GSHAREDVT_FAILURE (*ip);
12861                                 }
12862                                 EMIT_NEW_ICONST (cfg, ins, val);
12863                                 *sp++= ins;
12864                                 ip += 6;
12865                                 break;
12866                         }
12867                         case CEE_REFANYTYPE: {
12868                                 MonoInst *src_var, *src;
12869
12870                                 GSHAREDVT_FAILURE (*ip);
12871
12872                                 CHECK_STACK (1);
12873                                 --sp;
12874
12875                                 // FIXME:
12876                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12877                                 if (!src_var)
12878                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
12879                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
12880                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type));
12881                                 *sp++ = ins;
12882                                 ip += 2;
12883                                 break;
12884                         }
12885                         case CEE_READONLY_:
12886                                 readonly = TRUE;
12887                                 ip += 2;
12888                                 break;
12889
12890                         case CEE_UNUSED56:
12891                         case CEE_UNUSED57:
12892                         case CEE_UNUSED70:
12893                         case CEE_UNUSED:
12894                         case CEE_UNUSED99:
12895                                 UNVERIFIED;
12896                                 
12897                         default:
12898                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
12899                                 UNVERIFIED;
12900                         }
12901                         break;
12902                 }
12903                 case CEE_UNUSED58:
12904                 case CEE_UNUSED1:
12905                         UNVERIFIED;
12906
12907                 default:
12908                         g_warning ("opcode 0x%02x not handled", *ip);
12909                         UNVERIFIED;
12910                 }
12911         }
12912         if (start_new_bblock != 1)
12913                 UNVERIFIED;
12914
12915         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
12916         if (cfg->cbb->next_bb) {
12917                 /* This could already be set because of inlining, #693905 */
12918                 MonoBasicBlock *bb = cfg->cbb;
12919
12920                 while (bb->next_bb)
12921                         bb = bb->next_bb;
12922                 bb->next_bb = end_bblock;
12923         } else {
12924                 cfg->cbb->next_bb = end_bblock;
12925         }
12926
12927         if (cfg->method == method && cfg->domainvar) {
12928                 MonoInst *store;
12929                 MonoInst *get_domain;
12930
12931                 cfg->cbb = init_localsbb;
12932
12933                 if ((get_domain = mono_get_domain_intrinsic (cfg))) {
12934                         MONO_ADD_INS (cfg->cbb, get_domain);
12935                 } else {
12936                         get_domain = mono_emit_jit_icall (cfg, mono_domain_get, NULL);
12937                 }
12938                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
12939                 MONO_ADD_INS (cfg->cbb, store);
12940         }
12941
12942 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
12943         if (cfg->compile_aot)
12944                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
12945                 mono_get_got_var (cfg);
12946 #endif
12947
12948         if (cfg->method == method && cfg->got_var)
12949                 mono_emit_load_got_addr (cfg);
12950
12951         if (init_localsbb) {
12952                 cfg->cbb = init_localsbb;
12953                 cfg->ip = NULL;
12954                 for (i = 0; i < header->num_locals; ++i) {
12955                         emit_init_local (cfg, i, header->locals [i], init_locals);
12956                 }
12957         }
12958
12959         if (cfg->init_ref_vars && cfg->method == method) {
12960                 /* Emit initialization for ref vars */
12961                 // FIXME: Avoid duplication initialization for IL locals.
12962                 for (i = 0; i < cfg->num_varinfo; ++i) {
12963                         MonoInst *ins = cfg->varinfo [i];
12964
12965                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
12966                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
12967                 }
12968         }
12969
12970         if (cfg->lmf_var && cfg->method == method) {
12971                 cfg->cbb = init_localsbb;
12972                 emit_push_lmf (cfg);
12973         }
12974
12975         cfg->cbb = init_localsbb;
12976         emit_instrumentation_call (cfg, mono_profiler_method_enter);
12977
12978         if (seq_points) {
12979                 MonoBasicBlock *bb;
12980
12981                 /*
12982                  * Make seq points at backward branch targets interruptable.
12983                  */
12984                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
12985                         if (bb->code && bb->in_count > 1 && bb->code->opcode == OP_SEQ_POINT)
12986                                 bb->code->flags |= MONO_INST_SINGLE_STEP_LOC;
12987         }
12988
12989         /* Add a sequence point for method entry/exit events */
12990         if (seq_points && cfg->gen_sdb_seq_points) {
12991                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
12992                 MONO_ADD_INS (init_localsbb, ins);
12993                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
12994                 MONO_ADD_INS (cfg->bb_exit, ins);
12995         }
12996
12997         /*
12998          * Add seq points for IL offsets which have line number info, but wasn't generated a seq point during JITting because
12999          * the code they refer to was dead (#11880).
13000          */
13001         if (sym_seq_points) {
13002                 for (i = 0; i < header->code_size; ++i) {
13003                         if (mono_bitset_test_fast (seq_point_locs, i) && !mono_bitset_test_fast (seq_point_set_locs, i)) {
13004                                 MonoInst *ins;
13005
13006                                 NEW_SEQ_POINT (cfg, ins, i, FALSE);
13007                                 mono_add_seq_point (cfg, NULL, ins, SEQ_POINT_NATIVE_OFFSET_DEAD_CODE);
13008                         }
13009                 }
13010         }
13011
13012         cfg->ip = NULL;
13013
13014         if (cfg->method == method) {
13015                 MonoBasicBlock *bb;
13016                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13017                         bb->region = mono_find_block_region (cfg, bb->real_offset);
13018                         if (cfg->spvars)
13019                                 mono_create_spvar_for_region (cfg, bb->region);
13020                         if (cfg->verbose_level > 2)
13021                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
13022                 }
13023         }
13024
13025         if (inline_costs < 0) {
13026                 char *mname;
13027
13028                 /* Method is too large */
13029                 mname = mono_method_full_name (method, TRUE);
13030                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
13031                 cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
13032                 g_free (mname);
13033         }
13034
13035         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
13036                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
13037
13038         goto cleanup;
13039
13040 mono_error_exit:
13041         g_assert (!mono_error_ok (&cfg->error));
13042         goto cleanup;
13043  
13044  exception_exit:
13045         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
13046         goto cleanup;
13047
13048  unverified:
13049         set_exception_type_from_invalid_il (cfg, method, ip);
13050         goto cleanup;
13051
13052  cleanup:
13053         g_slist_free (class_inits);
13054         mono_basic_block_free (original_bb);
13055         cfg->dont_inline = g_list_remove (cfg->dont_inline, method);
13056         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
13057         if (cfg->exception_type)
13058                 return -1;
13059         else
13060                 return inline_costs;
13061 }
13062
13063 static int
13064 store_membase_reg_to_store_membase_imm (int opcode)
13065 {
13066         switch (opcode) {
13067         case OP_STORE_MEMBASE_REG:
13068                 return OP_STORE_MEMBASE_IMM;
13069         case OP_STOREI1_MEMBASE_REG:
13070                 return OP_STOREI1_MEMBASE_IMM;
13071         case OP_STOREI2_MEMBASE_REG:
13072                 return OP_STOREI2_MEMBASE_IMM;
13073         case OP_STOREI4_MEMBASE_REG:
13074                 return OP_STOREI4_MEMBASE_IMM;
13075         case OP_STOREI8_MEMBASE_REG:
13076                 return OP_STOREI8_MEMBASE_IMM;
13077         default:
13078                 g_assert_not_reached ();
13079         }
13080
13081         return -1;
13082 }               
13083
13084 int
13085 mono_op_to_op_imm (int opcode)
13086 {
13087         switch (opcode) {
13088         case OP_IADD:
13089                 return OP_IADD_IMM;
13090         case OP_ISUB:
13091                 return OP_ISUB_IMM;
13092         case OP_IDIV:
13093                 return OP_IDIV_IMM;
13094         case OP_IDIV_UN:
13095                 return OP_IDIV_UN_IMM;
13096         case OP_IREM:
13097                 return OP_IREM_IMM;
13098         case OP_IREM_UN:
13099                 return OP_IREM_UN_IMM;
13100         case OP_IMUL:
13101                 return OP_IMUL_IMM;
13102         case OP_IAND:
13103                 return OP_IAND_IMM;
13104         case OP_IOR:
13105                 return OP_IOR_IMM;
13106         case OP_IXOR:
13107                 return OP_IXOR_IMM;
13108         case OP_ISHL:
13109                 return OP_ISHL_IMM;
13110         case OP_ISHR:
13111                 return OP_ISHR_IMM;
13112         case OP_ISHR_UN:
13113                 return OP_ISHR_UN_IMM;
13114
13115         case OP_LADD:
13116                 return OP_LADD_IMM;
13117         case OP_LSUB:
13118                 return OP_LSUB_IMM;
13119         case OP_LAND:
13120                 return OP_LAND_IMM;
13121         case OP_LOR:
13122                 return OP_LOR_IMM;
13123         case OP_LXOR:
13124                 return OP_LXOR_IMM;
13125         case OP_LSHL:
13126                 return OP_LSHL_IMM;
13127         case OP_LSHR:
13128                 return OP_LSHR_IMM;
13129         case OP_LSHR_UN:
13130                 return OP_LSHR_UN_IMM;
13131 #if SIZEOF_REGISTER == 8
13132         case OP_LREM:
13133                 return OP_LREM_IMM;
13134 #endif
13135
13136         case OP_COMPARE:
13137                 return OP_COMPARE_IMM;
13138         case OP_ICOMPARE:
13139                 return OP_ICOMPARE_IMM;
13140         case OP_LCOMPARE:
13141                 return OP_LCOMPARE_IMM;
13142
13143         case OP_STORE_MEMBASE_REG:
13144                 return OP_STORE_MEMBASE_IMM;
13145         case OP_STOREI1_MEMBASE_REG:
13146                 return OP_STOREI1_MEMBASE_IMM;
13147         case OP_STOREI2_MEMBASE_REG:
13148                 return OP_STOREI2_MEMBASE_IMM;
13149         case OP_STOREI4_MEMBASE_REG:
13150                 return OP_STOREI4_MEMBASE_IMM;
13151
13152 #if defined(TARGET_X86) || defined (TARGET_AMD64)
13153         case OP_X86_PUSH:
13154                 return OP_X86_PUSH_IMM;
13155         case OP_X86_COMPARE_MEMBASE_REG:
13156                 return OP_X86_COMPARE_MEMBASE_IMM;
13157 #endif
13158 #if defined(TARGET_AMD64)
13159         case OP_AMD64_ICOMPARE_MEMBASE_REG:
13160                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13161 #endif
13162         case OP_VOIDCALL_REG:
13163                 return OP_VOIDCALL;
13164         case OP_CALL_REG:
13165                 return OP_CALL;
13166         case OP_LCALL_REG:
13167                 return OP_LCALL;
13168         case OP_FCALL_REG:
13169                 return OP_FCALL;
13170         case OP_LOCALLOC:
13171                 return OP_LOCALLOC_IMM;
13172         }
13173
13174         return -1;
13175 }
13176
13177 static int
13178 ldind_to_load_membase (int opcode)
13179 {
13180         switch (opcode) {
13181         case CEE_LDIND_I1:
13182                 return OP_LOADI1_MEMBASE;
13183         case CEE_LDIND_U1:
13184                 return OP_LOADU1_MEMBASE;
13185         case CEE_LDIND_I2:
13186                 return OP_LOADI2_MEMBASE;
13187         case CEE_LDIND_U2:
13188                 return OP_LOADU2_MEMBASE;
13189         case CEE_LDIND_I4:
13190                 return OP_LOADI4_MEMBASE;
13191         case CEE_LDIND_U4:
13192                 return OP_LOADU4_MEMBASE;
13193         case CEE_LDIND_I:
13194                 return OP_LOAD_MEMBASE;
13195         case CEE_LDIND_REF:
13196                 return OP_LOAD_MEMBASE;
13197         case CEE_LDIND_I8:
13198                 return OP_LOADI8_MEMBASE;
13199         case CEE_LDIND_R4:
13200                 return OP_LOADR4_MEMBASE;
13201         case CEE_LDIND_R8:
13202                 return OP_LOADR8_MEMBASE;
13203         default:
13204                 g_assert_not_reached ();
13205         }
13206
13207         return -1;
13208 }
13209
13210 static int
13211 stind_to_store_membase (int opcode)
13212 {
13213         switch (opcode) {
13214         case CEE_STIND_I1:
13215                 return OP_STOREI1_MEMBASE_REG;
13216         case CEE_STIND_I2:
13217                 return OP_STOREI2_MEMBASE_REG;
13218         case CEE_STIND_I4:
13219                 return OP_STOREI4_MEMBASE_REG;
13220         case CEE_STIND_I:
13221         case CEE_STIND_REF:
13222                 return OP_STORE_MEMBASE_REG;
13223         case CEE_STIND_I8:
13224                 return OP_STOREI8_MEMBASE_REG;
13225         case CEE_STIND_R4:
13226                 return OP_STORER4_MEMBASE_REG;
13227         case CEE_STIND_R8:
13228                 return OP_STORER8_MEMBASE_REG;
13229         default:
13230                 g_assert_not_reached ();
13231         }
13232
13233         return -1;
13234 }
13235
13236 int
13237 mono_load_membase_to_load_mem (int opcode)
13238 {
13239         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
13240 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13241         switch (opcode) {
13242         case OP_LOAD_MEMBASE:
13243                 return OP_LOAD_MEM;
13244         case OP_LOADU1_MEMBASE:
13245                 return OP_LOADU1_MEM;
13246         case OP_LOADU2_MEMBASE:
13247                 return OP_LOADU2_MEM;
13248         case OP_LOADI4_MEMBASE:
13249                 return OP_LOADI4_MEM;
13250         case OP_LOADU4_MEMBASE:
13251                 return OP_LOADU4_MEM;
13252 #if SIZEOF_REGISTER == 8
13253         case OP_LOADI8_MEMBASE:
13254                 return OP_LOADI8_MEM;
13255 #endif
13256         }
13257 #endif
13258
13259         return -1;
13260 }
13261
13262 static inline int
13263 op_to_op_dest_membase (int store_opcode, int opcode)
13264 {
13265 #if defined(TARGET_X86)
13266         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
13267                 return -1;
13268
13269         switch (opcode) {
13270         case OP_IADD:
13271                 return OP_X86_ADD_MEMBASE_REG;
13272         case OP_ISUB:
13273                 return OP_X86_SUB_MEMBASE_REG;
13274         case OP_IAND:
13275                 return OP_X86_AND_MEMBASE_REG;
13276         case OP_IOR:
13277                 return OP_X86_OR_MEMBASE_REG;
13278         case OP_IXOR:
13279                 return OP_X86_XOR_MEMBASE_REG;
13280         case OP_ADD_IMM:
13281         case OP_IADD_IMM:
13282                 return OP_X86_ADD_MEMBASE_IMM;
13283         case OP_SUB_IMM:
13284         case OP_ISUB_IMM:
13285                 return OP_X86_SUB_MEMBASE_IMM;
13286         case OP_AND_IMM:
13287         case OP_IAND_IMM:
13288                 return OP_X86_AND_MEMBASE_IMM;
13289         case OP_OR_IMM:
13290         case OP_IOR_IMM:
13291                 return OP_X86_OR_MEMBASE_IMM;
13292         case OP_XOR_IMM:
13293         case OP_IXOR_IMM:
13294                 return OP_X86_XOR_MEMBASE_IMM;
13295         case OP_MOVE:
13296                 return OP_NOP;
13297         }
13298 #endif
13299
13300 #if defined(TARGET_AMD64)
13301         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
13302                 return -1;
13303
13304         switch (opcode) {
13305         case OP_IADD:
13306                 return OP_X86_ADD_MEMBASE_REG;
13307         case OP_ISUB:
13308                 return OP_X86_SUB_MEMBASE_REG;
13309         case OP_IAND:
13310                 return OP_X86_AND_MEMBASE_REG;
13311         case OP_IOR:
13312                 return OP_X86_OR_MEMBASE_REG;
13313         case OP_IXOR:
13314                 return OP_X86_XOR_MEMBASE_REG;
13315         case OP_IADD_IMM:
13316                 return OP_X86_ADD_MEMBASE_IMM;
13317         case OP_ISUB_IMM:
13318                 return OP_X86_SUB_MEMBASE_IMM;
13319         case OP_IAND_IMM:
13320                 return OP_X86_AND_MEMBASE_IMM;
13321         case OP_IOR_IMM:
13322                 return OP_X86_OR_MEMBASE_IMM;
13323         case OP_IXOR_IMM:
13324                 return OP_X86_XOR_MEMBASE_IMM;
13325         case OP_LADD:
13326                 return OP_AMD64_ADD_MEMBASE_REG;
13327         case OP_LSUB:
13328                 return OP_AMD64_SUB_MEMBASE_REG;
13329         case OP_LAND:
13330                 return OP_AMD64_AND_MEMBASE_REG;
13331         case OP_LOR:
13332                 return OP_AMD64_OR_MEMBASE_REG;
13333         case OP_LXOR:
13334                 return OP_AMD64_XOR_MEMBASE_REG;
13335         case OP_ADD_IMM:
13336         case OP_LADD_IMM:
13337                 return OP_AMD64_ADD_MEMBASE_IMM;
13338         case OP_SUB_IMM:
13339         case OP_LSUB_IMM:
13340                 return OP_AMD64_SUB_MEMBASE_IMM;
13341         case OP_AND_IMM:
13342         case OP_LAND_IMM:
13343                 return OP_AMD64_AND_MEMBASE_IMM;
13344         case OP_OR_IMM:
13345         case OP_LOR_IMM:
13346                 return OP_AMD64_OR_MEMBASE_IMM;
13347         case OP_XOR_IMM:
13348         case OP_LXOR_IMM:
13349                 return OP_AMD64_XOR_MEMBASE_IMM;
13350         case OP_MOVE:
13351                 return OP_NOP;
13352         }
13353 #endif
13354
13355         return -1;
13356 }
13357
13358 static inline int
13359 op_to_op_store_membase (int store_opcode, int opcode)
13360 {
13361 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13362         switch (opcode) {
13363         case OP_ICEQ:
13364                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13365                         return OP_X86_SETEQ_MEMBASE;
13366         case OP_CNE:
13367                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13368                         return OP_X86_SETNE_MEMBASE;
13369         }
13370 #endif
13371
13372         return -1;
13373 }
13374
13375 static inline int
13376 op_to_op_src1_membase (int load_opcode, int opcode)
13377 {
13378 #ifdef TARGET_X86
13379         /* FIXME: This has sign extension issues */
13380         /*
13381         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13382                 return OP_X86_COMPARE_MEMBASE8_IMM;
13383         */
13384
13385         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13386                 return -1;
13387
13388         switch (opcode) {
13389         case OP_X86_PUSH:
13390                 return OP_X86_PUSH_MEMBASE;
13391         case OP_COMPARE_IMM:
13392         case OP_ICOMPARE_IMM:
13393                 return OP_X86_COMPARE_MEMBASE_IMM;
13394         case OP_COMPARE:
13395         case OP_ICOMPARE:
13396                 return OP_X86_COMPARE_MEMBASE_REG;
13397         }
13398 #endif
13399
13400 #ifdef TARGET_AMD64
13401         /* FIXME: This has sign extension issues */
13402         /*
13403         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13404                 return OP_X86_COMPARE_MEMBASE8_IMM;
13405         */
13406
13407         switch (opcode) {
13408         case OP_X86_PUSH:
13409 #ifdef __mono_ilp32__
13410                 if (load_opcode == OP_LOADI8_MEMBASE)
13411 #else
13412                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13413 #endif
13414                         return OP_X86_PUSH_MEMBASE;
13415                 break;
13416                 /* FIXME: This only works for 32 bit immediates
13417         case OP_COMPARE_IMM:
13418         case OP_LCOMPARE_IMM:
13419                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13420                         return OP_AMD64_COMPARE_MEMBASE_IMM;
13421                 */
13422         case OP_ICOMPARE_IMM:
13423                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13424                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13425                 break;
13426         case OP_COMPARE:
13427         case OP_LCOMPARE:
13428 #ifdef __mono_ilp32__
13429                 if (load_opcode == OP_LOAD_MEMBASE)
13430                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13431                 if (load_opcode == OP_LOADI8_MEMBASE)
13432 #else
13433                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13434 #endif
13435                         return OP_AMD64_COMPARE_MEMBASE_REG;
13436                 break;
13437         case OP_ICOMPARE:
13438                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13439                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13440                 break;
13441         }
13442 #endif
13443
13444         return -1;
13445 }
13446
13447 static inline int
13448 op_to_op_src2_membase (int load_opcode, int opcode)
13449 {
13450 #ifdef TARGET_X86
13451         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13452                 return -1;
13453         
13454         switch (opcode) {
13455         case OP_COMPARE:
13456         case OP_ICOMPARE:
13457                 return OP_X86_COMPARE_REG_MEMBASE;
13458         case OP_IADD:
13459                 return OP_X86_ADD_REG_MEMBASE;
13460         case OP_ISUB:
13461                 return OP_X86_SUB_REG_MEMBASE;
13462         case OP_IAND:
13463                 return OP_X86_AND_REG_MEMBASE;
13464         case OP_IOR:
13465                 return OP_X86_OR_REG_MEMBASE;
13466         case OP_IXOR:
13467                 return OP_X86_XOR_REG_MEMBASE;
13468         }
13469 #endif
13470
13471 #ifdef TARGET_AMD64
13472 #ifdef __mono_ilp32__
13473         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE) ) {
13474 #else
13475         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)) {
13476 #endif
13477                 switch (opcode) {
13478                 case OP_ICOMPARE:
13479                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
13480                 case OP_IADD:
13481                         return OP_X86_ADD_REG_MEMBASE;
13482                 case OP_ISUB:
13483                         return OP_X86_SUB_REG_MEMBASE;
13484                 case OP_IAND:
13485                         return OP_X86_AND_REG_MEMBASE;
13486                 case OP_IOR:
13487                         return OP_X86_OR_REG_MEMBASE;
13488                 case OP_IXOR:
13489                         return OP_X86_XOR_REG_MEMBASE;
13490                 }
13491 #ifdef __mono_ilp32__
13492         } else if (load_opcode == OP_LOADI8_MEMBASE) {
13493 #else
13494         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE)) {
13495 #endif
13496                 switch (opcode) {
13497                 case OP_COMPARE:
13498                 case OP_LCOMPARE:
13499                         return OP_AMD64_COMPARE_REG_MEMBASE;
13500                 case OP_LADD:
13501                         return OP_AMD64_ADD_REG_MEMBASE;
13502                 case OP_LSUB:
13503                         return OP_AMD64_SUB_REG_MEMBASE;
13504                 case OP_LAND:
13505                         return OP_AMD64_AND_REG_MEMBASE;
13506                 case OP_LOR:
13507                         return OP_AMD64_OR_REG_MEMBASE;
13508                 case OP_LXOR:
13509                         return OP_AMD64_XOR_REG_MEMBASE;
13510                 }
13511         }
13512 #endif
13513
13514         return -1;
13515 }
13516
13517 int
13518 mono_op_to_op_imm_noemul (int opcode)
13519 {
13520         switch (opcode) {
13521 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
13522         case OP_LSHR:
13523         case OP_LSHL:
13524         case OP_LSHR_UN:
13525                 return -1;
13526 #endif
13527 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
13528         case OP_IDIV:
13529         case OP_IDIV_UN:
13530         case OP_IREM:
13531         case OP_IREM_UN:
13532                 return -1;
13533 #endif
13534 #if defined(MONO_ARCH_EMULATE_MUL_DIV)
13535         case OP_IMUL:
13536                 return -1;
13537 #endif
13538         default:
13539                 return mono_op_to_op_imm (opcode);
13540         }
13541 }
13542
13543 /**
13544  * mono_handle_global_vregs:
13545  *
13546  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
13547  * for them.
13548  */
13549 void
13550 mono_handle_global_vregs (MonoCompile *cfg)
13551 {
13552         gint32 *vreg_to_bb;
13553         MonoBasicBlock *bb;
13554         int i, pos;
13555
13556         vreg_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
13557
13558 #ifdef MONO_ARCH_SIMD_INTRINSICS
13559         if (cfg->uses_simd_intrinsics)
13560                 mono_simd_simplify_indirection (cfg);
13561 #endif
13562
13563         /* Find local vregs used in more than one bb */
13564         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13565                 MonoInst *ins = bb->code;       
13566                 int block_num = bb->block_num;
13567
13568                 if (cfg->verbose_level > 2)
13569                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
13570
13571                 cfg->cbb = bb;
13572                 for (; ins; ins = ins->next) {
13573                         const char *spec = INS_INFO (ins->opcode);
13574                         int regtype = 0, regindex;
13575                         gint32 prev_bb;
13576
13577                         if (G_UNLIKELY (cfg->verbose_level > 2))
13578                                 mono_print_ins (ins);
13579
13580                         g_assert (ins->opcode >= MONO_CEE_LAST);
13581
13582                         for (regindex = 0; regindex < 4; regindex ++) {
13583                                 int vreg = 0;
13584
13585                                 if (regindex == 0) {
13586                                         regtype = spec [MONO_INST_DEST];
13587                                         if (regtype == ' ')
13588                                                 continue;
13589                                         vreg = ins->dreg;
13590                                 } else if (regindex == 1) {
13591                                         regtype = spec [MONO_INST_SRC1];
13592                                         if (regtype == ' ')
13593                                                 continue;
13594                                         vreg = ins->sreg1;
13595                                 } else if (regindex == 2) {
13596                                         regtype = spec [MONO_INST_SRC2];
13597                                         if (regtype == ' ')
13598                                                 continue;
13599                                         vreg = ins->sreg2;
13600                                 } else if (regindex == 3) {
13601                                         regtype = spec [MONO_INST_SRC3];
13602                                         if (regtype == ' ')
13603                                                 continue;
13604                                         vreg = ins->sreg3;
13605                                 }
13606
13607 #if SIZEOF_REGISTER == 4
13608                                 /* In the LLVM case, the long opcodes are not decomposed */
13609                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
13610                                         /*
13611                                          * Since some instructions reference the original long vreg,
13612                                          * and some reference the two component vregs, it is quite hard
13613                                          * to determine when it needs to be global. So be conservative.
13614                                          */
13615                                         if (!get_vreg_to_inst (cfg, vreg)) {
13616                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13617
13618                                                 if (cfg->verbose_level > 2)
13619                                                         printf ("LONG VREG R%d made global.\n", vreg);
13620                                         }
13621
13622                                         /*
13623                                          * Make the component vregs volatile since the optimizations can
13624                                          * get confused otherwise.
13625                                          */
13626                                         get_vreg_to_inst (cfg, vreg + 1)->flags |= MONO_INST_VOLATILE;
13627                                         get_vreg_to_inst (cfg, vreg + 2)->flags |= MONO_INST_VOLATILE;
13628                                 }
13629 #endif
13630
13631                                 g_assert (vreg != -1);
13632
13633                                 prev_bb = vreg_to_bb [vreg];
13634                                 if (prev_bb == 0) {
13635                                         /* 0 is a valid block num */
13636                                         vreg_to_bb [vreg] = block_num + 1;
13637                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
13638                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
13639                                                 continue;
13640
13641                                         if (!get_vreg_to_inst (cfg, vreg)) {
13642                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13643                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
13644
13645                                                 switch (regtype) {
13646                                                 case 'i':
13647                                                         if (vreg_is_ref (cfg, vreg))
13648                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg);
13649                                                         else
13650                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
13651                                                         break;
13652                                                 case 'l':
13653                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13654                                                         break;
13655                                                 case 'f':
13656                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
13657                                                         break;
13658                                                 case 'v':
13659                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
13660                                                         break;
13661                                                 default:
13662                                                         g_assert_not_reached ();
13663                                                 }
13664                                         }
13665
13666                                         /* Flag as having been used in more than one bb */
13667                                         vreg_to_bb [vreg] = -1;
13668                                 }
13669                         }
13670                 }
13671         }
13672
13673         /* If a variable is used in only one bblock, convert it into a local vreg */
13674         for (i = 0; i < cfg->num_varinfo; i++) {
13675                 MonoInst *var = cfg->varinfo [i];
13676                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
13677
13678                 switch (var->type) {
13679                 case STACK_I4:
13680                 case STACK_OBJ:
13681                 case STACK_PTR:
13682                 case STACK_MP:
13683                 case STACK_VTYPE:
13684 #if SIZEOF_REGISTER == 8
13685                 case STACK_I8:
13686 #endif
13687 #if !defined(TARGET_X86)
13688                 /* Enabling this screws up the fp stack on x86 */
13689                 case STACK_R8:
13690 #endif
13691                         if (mono_arch_is_soft_float ())
13692                                 break;
13693
13694                         /* Arguments are implicitly global */
13695                         /* Putting R4 vars into registers doesn't work currently */
13696                         /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
13697                         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) {
13698                                 /* 
13699                                  * Make that the variable's liveness interval doesn't contain a call, since
13700                                  * that would cause the lvreg to be spilled, making the whole optimization
13701                                  * useless.
13702                                  */
13703                                 /* This is too slow for JIT compilation */
13704 #if 0
13705                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
13706                                         MonoInst *ins;
13707                                         int def_index, call_index, ins_index;
13708                                         gboolean spilled = FALSE;
13709
13710                                         def_index = -1;
13711                                         call_index = -1;
13712                                         ins_index = 0;
13713                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
13714                                                 const char *spec = INS_INFO (ins->opcode);
13715
13716                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
13717                                                         def_index = ins_index;
13718
13719                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
13720                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
13721                                                         if (call_index > def_index) {
13722                                                                 spilled = TRUE;
13723                                                                 break;
13724                                                         }
13725                                                 }
13726
13727                                                 if (MONO_IS_CALL (ins))
13728                                                         call_index = ins_index;
13729
13730                                                 ins_index ++;
13731                                         }
13732
13733                                         if (spilled)
13734                                                 break;
13735                                 }
13736 #endif
13737
13738                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13739                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
13740                                 var->flags |= MONO_INST_IS_DEAD;
13741                                 cfg->vreg_to_inst [var->dreg] = NULL;
13742                         }
13743                         break;
13744                 }
13745         }
13746
13747         /* 
13748          * Compress the varinfo and vars tables so the liveness computation is faster and
13749          * takes up less space.
13750          */
13751         pos = 0;
13752         for (i = 0; i < cfg->num_varinfo; ++i) {
13753                 MonoInst *var = cfg->varinfo [i];
13754                 if (pos < i && cfg->locals_start == i)
13755                         cfg->locals_start = pos;
13756                 if (!(var->flags & MONO_INST_IS_DEAD)) {
13757                         if (pos < i) {
13758                                 cfg->varinfo [pos] = cfg->varinfo [i];
13759                                 cfg->varinfo [pos]->inst_c0 = pos;
13760                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
13761                                 cfg->vars [pos].idx = pos;
13762 #if SIZEOF_REGISTER == 4
13763                                 if (cfg->varinfo [pos]->type == STACK_I8) {
13764                                         /* Modify the two component vars too */
13765                                         MonoInst *var1;
13766
13767                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 1);
13768                                         var1->inst_c0 = pos;
13769                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 2);
13770                                         var1->inst_c0 = pos;
13771                                 }
13772 #endif
13773                         }
13774                         pos ++;
13775                 }
13776         }
13777         cfg->num_varinfo = pos;
13778         if (cfg->locals_start > cfg->num_varinfo)
13779                 cfg->locals_start = cfg->num_varinfo;
13780 }
13781
13782 /**
13783  * mono_spill_global_vars:
13784  *
13785  *   Generate spill code for variables which are not allocated to registers, 
13786  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
13787  * code is generated which could be optimized by the local optimization passes.
13788  */
13789 void
13790 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
13791 {
13792         MonoBasicBlock *bb;
13793         char spec2 [16];
13794         int orig_next_vreg;
13795         guint32 *vreg_to_lvreg;
13796         guint32 *lvregs;
13797         guint32 i, lvregs_len;
13798         gboolean dest_has_lvreg = FALSE;
13799         guint32 stacktypes [128];
13800         MonoInst **live_range_start, **live_range_end;
13801         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
13802         int *gsharedvt_vreg_to_idx = NULL;
13803
13804         *need_local_opts = FALSE;
13805
13806         memset (spec2, 0, sizeof (spec2));
13807
13808         /* FIXME: Move this function to mini.c */
13809         stacktypes ['i'] = STACK_PTR;
13810         stacktypes ['l'] = STACK_I8;
13811         stacktypes ['f'] = STACK_R8;
13812 #ifdef MONO_ARCH_SIMD_INTRINSICS
13813         stacktypes ['x'] = STACK_VTYPE;
13814 #endif
13815
13816 #if SIZEOF_REGISTER == 4
13817         /* Create MonoInsts for longs */
13818         for (i = 0; i < cfg->num_varinfo; i++) {
13819                 MonoInst *ins = cfg->varinfo [i];
13820
13821                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
13822                         switch (ins->type) {
13823                         case STACK_R8:
13824                         case STACK_I8: {
13825                                 MonoInst *tree;
13826
13827                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
13828                                         break;
13829
13830                                 g_assert (ins->opcode == OP_REGOFFSET);
13831
13832                                 tree = get_vreg_to_inst (cfg, ins->dreg + 1);
13833                                 g_assert (tree);
13834                                 tree->opcode = OP_REGOFFSET;
13835                                 tree->inst_basereg = ins->inst_basereg;
13836                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
13837
13838                                 tree = get_vreg_to_inst (cfg, ins->dreg + 2);
13839                                 g_assert (tree);
13840                                 tree->opcode = OP_REGOFFSET;
13841                                 tree->inst_basereg = ins->inst_basereg;
13842                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
13843                                 break;
13844                         }
13845                         default:
13846                                 break;
13847                         }
13848                 }
13849         }
13850 #endif
13851
13852         if (cfg->compute_gc_maps) {
13853                 /* registers need liveness info even for !non refs */
13854                 for (i = 0; i < cfg->num_varinfo; i++) {
13855                         MonoInst *ins = cfg->varinfo [i];
13856
13857                         if (ins->opcode == OP_REGVAR)
13858                                 ins->flags |= MONO_INST_GC_TRACK;
13859                 }
13860         }
13861
13862         if (cfg->gsharedvt) {
13863                 gsharedvt_vreg_to_idx = mono_mempool_alloc0 (cfg->mempool, sizeof (int) * cfg->next_vreg);
13864
13865                 for (i = 0; i < cfg->num_varinfo; ++i) {
13866                         MonoInst *ins = cfg->varinfo [i];
13867                         int idx;
13868
13869                         if (mini_is_gsharedvt_variable_type (cfg, ins->inst_vtype)) {
13870                                 if (i >= cfg->locals_start) {
13871                                         /* Local */
13872                                         idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
13873                                         gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
13874                                         ins->opcode = OP_GSHAREDVT_LOCAL;
13875                                         ins->inst_imm = idx;
13876                                 } else {
13877                                         /* Arg */
13878                                         gsharedvt_vreg_to_idx [ins->dreg] = -1;
13879                                         ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
13880                                 }
13881                         }
13882                 }
13883         }
13884                 
13885         /* FIXME: widening and truncation */
13886
13887         /*
13888          * As an optimization, when a variable allocated to the stack is first loaded into 
13889          * an lvreg, we will remember the lvreg and use it the next time instead of loading
13890          * the variable again.
13891          */
13892         orig_next_vreg = cfg->next_vreg;
13893         vreg_to_lvreg = mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
13894         lvregs = mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
13895         lvregs_len = 0;
13896
13897         /* 
13898          * These arrays contain the first and last instructions accessing a given
13899          * variable.
13900          * Since we emit bblocks in the same order we process them here, and we
13901          * don't split live ranges, these will precisely describe the live range of
13902          * the variable, i.e. the instruction range where a valid value can be found
13903          * in the variables location.
13904          * The live range is computed using the liveness info computed by the liveness pass.
13905          * We can't use vmv->range, since that is an abstract live range, and we need
13906          * one which is instruction precise.
13907          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
13908          */
13909         /* FIXME: Only do this if debugging info is requested */
13910         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
13911         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
13912         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
13913         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
13914         
13915         /* Add spill loads/stores */
13916         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13917                 MonoInst *ins;
13918
13919                 if (cfg->verbose_level > 2)
13920                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
13921
13922                 /* Clear vreg_to_lvreg array */
13923                 for (i = 0; i < lvregs_len; i++)
13924                         vreg_to_lvreg [lvregs [i]] = 0;
13925                 lvregs_len = 0;
13926
13927                 cfg->cbb = bb;
13928                 MONO_BB_FOR_EACH_INS (bb, ins) {
13929                         const char *spec = INS_INFO (ins->opcode);
13930                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
13931                         gboolean store, no_lvreg;
13932                         int sregs [MONO_MAX_SRC_REGS];
13933
13934                         if (G_UNLIKELY (cfg->verbose_level > 2))
13935                                 mono_print_ins (ins);
13936
13937                         if (ins->opcode == OP_NOP)
13938                                 continue;
13939
13940                         /* 
13941                          * We handle LDADDR here as well, since it can only be decomposed
13942                          * when variable addresses are known.
13943                          */
13944                         if (ins->opcode == OP_LDADDR) {
13945                                 MonoInst *var = ins->inst_p0;
13946
13947                                 if (var->opcode == OP_VTARG_ADDR) {
13948                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
13949                                         MonoInst *vtaddr = var->inst_left;
13950                                         if (vtaddr->opcode == OP_REGVAR) {
13951                                                 ins->opcode = OP_MOVE;
13952                                                 ins->sreg1 = vtaddr->dreg;
13953                                         }
13954                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
13955                                                 ins->opcode = OP_LOAD_MEMBASE;
13956                                                 ins->inst_basereg = vtaddr->inst_basereg;
13957                                                 ins->inst_offset = vtaddr->inst_offset;
13958                                         } else
13959                                                 NOT_IMPLEMENTED;
13960                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg] < 0) {
13961                                         /* gsharedvt arg passed by ref */
13962                                         g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
13963
13964                                         ins->opcode = OP_LOAD_MEMBASE;
13965                                         ins->inst_basereg = var->inst_basereg;
13966                                         ins->inst_offset = var->inst_offset;
13967                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg]) {
13968                                         MonoInst *load, *load2, *load3;
13969                                         int idx = gsharedvt_vreg_to_idx [var->dreg] - 1;
13970                                         int reg1, reg2, reg3;
13971                                         MonoInst *info_var = cfg->gsharedvt_info_var;
13972                                         MonoInst *locals_var = cfg->gsharedvt_locals_var;
13973
13974                                         /*
13975                                          * gsharedvt local.
13976                                          * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
13977                                          */
13978
13979                                         g_assert (var->opcode == OP_GSHAREDVT_LOCAL);
13980
13981                                         g_assert (info_var);
13982                                         g_assert (locals_var);
13983
13984                                         /* Mark the instruction used to compute the locals var as used */
13985                                         cfg->gsharedvt_locals_var_ins = NULL;
13986
13987                                         /* Load the offset */
13988                                         if (info_var->opcode == OP_REGOFFSET) {
13989                                                 reg1 = alloc_ireg (cfg);
13990                                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, reg1, info_var->inst_basereg, info_var->inst_offset);
13991                                         } else if (info_var->opcode == OP_REGVAR) {
13992                                                 load = NULL;
13993                                                 reg1 = info_var->dreg;
13994                                         } else {
13995                                                 g_assert_not_reached ();
13996                                         }
13997                                         reg2 = alloc_ireg (cfg);
13998                                         NEW_LOAD_MEMBASE (cfg, load2, OP_LOADI4_MEMBASE, reg2, reg1, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
13999                                         /* Load the locals area address */
14000                                         reg3 = alloc_ireg (cfg);
14001                                         if (locals_var->opcode == OP_REGOFFSET) {
14002                                                 NEW_LOAD_MEMBASE (cfg, load3, OP_LOAD_MEMBASE, reg3, locals_var->inst_basereg, locals_var->inst_offset);
14003                                         } else if (locals_var->opcode == OP_REGVAR) {
14004                                                 NEW_UNALU (cfg, load3, OP_MOVE, reg3, locals_var->dreg);
14005                                         } else {
14006                                                 g_assert_not_reached ();
14007                                         }
14008                                         /* Compute the address */
14009                                         ins->opcode = OP_PADD;
14010                                         ins->sreg1 = reg3;
14011                                         ins->sreg2 = reg2;
14012
14013                                         mono_bblock_insert_before_ins (bb, ins, load3);
14014                                         mono_bblock_insert_before_ins (bb, load3, load2);
14015                                         if (load)
14016                                                 mono_bblock_insert_before_ins (bb, load2, load);
14017                                 } else {
14018                                         g_assert (var->opcode == OP_REGOFFSET);
14019
14020                                         ins->opcode = OP_ADD_IMM;
14021                                         ins->sreg1 = var->inst_basereg;
14022                                         ins->inst_imm = var->inst_offset;
14023                                 }
14024
14025                                 *need_local_opts = TRUE;
14026                                 spec = INS_INFO (ins->opcode);
14027                         }
14028
14029                         if (ins->opcode < MONO_CEE_LAST) {
14030                                 mono_print_ins (ins);
14031                                 g_assert_not_reached ();
14032                         }
14033
14034                         /*
14035                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
14036                          * src register.
14037                          * FIXME:
14038                          */
14039                         if (MONO_IS_STORE_MEMBASE (ins)) {
14040                                 tmp_reg = ins->dreg;
14041                                 ins->dreg = ins->sreg2;
14042                                 ins->sreg2 = tmp_reg;
14043                                 store = TRUE;
14044
14045                                 spec2 [MONO_INST_DEST] = ' ';
14046                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14047                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14048                                 spec2 [MONO_INST_SRC3] = ' ';
14049                                 spec = spec2;
14050                         } else if (MONO_IS_STORE_MEMINDEX (ins))
14051                                 g_assert_not_reached ();
14052                         else
14053                                 store = FALSE;
14054                         no_lvreg = FALSE;
14055
14056                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
14057                                 printf ("\t %.3s %d", spec, ins->dreg);
14058                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
14059                                 for (srcindex = 0; srcindex < num_sregs; ++srcindex)
14060                                         printf (" %d", sregs [srcindex]);
14061                                 printf ("\n");
14062                         }
14063
14064                         /***************/
14065                         /*    DREG     */
14066                         /***************/
14067                         regtype = spec [MONO_INST_DEST];
14068                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
14069                         prev_dreg = -1;
14070
14071                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
14072                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
14073                                 MonoInst *store_ins;
14074                                 int store_opcode;
14075                                 MonoInst *def_ins = ins;
14076                                 int dreg = ins->dreg; /* The original vreg */
14077
14078                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
14079
14080                                 if (var->opcode == OP_REGVAR) {
14081                                         ins->dreg = var->dreg;
14082                                 } 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)) {
14083                                         /* 
14084                                          * Instead of emitting a load+store, use a _membase opcode.
14085                                          */
14086                                         g_assert (var->opcode == OP_REGOFFSET);
14087                                         if (ins->opcode == OP_MOVE) {
14088                                                 NULLIFY_INS (ins);
14089                                                 def_ins = NULL;
14090                                         } else {
14091                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
14092                                                 ins->inst_basereg = var->inst_basereg;
14093                                                 ins->inst_offset = var->inst_offset;
14094                                                 ins->dreg = -1;
14095                                         }
14096                                         spec = INS_INFO (ins->opcode);
14097                                 } else {
14098                                         guint32 lvreg;
14099
14100                                         g_assert (var->opcode == OP_REGOFFSET);
14101
14102                                         prev_dreg = ins->dreg;
14103
14104                                         /* Invalidate any previous lvreg for this vreg */
14105                                         vreg_to_lvreg [ins->dreg] = 0;
14106
14107                                         lvreg = 0;
14108
14109                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
14110                                                 regtype = 'l';
14111                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
14112                                         }
14113
14114                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
14115
14116 #if SIZEOF_REGISTER != 8
14117                                         if (regtype == 'l') {
14118                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET, ins->dreg + 1);
14119                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14120                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET, ins->dreg + 2);
14121                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14122                                                 def_ins = store_ins;
14123                                         }
14124                                         else
14125 #endif
14126                                         {
14127                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
14128
14129                                                 /* Try to fuse the store into the instruction itself */
14130                                                 /* FIXME: Add more instructions */
14131                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
14132                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
14133                                                         ins->inst_imm = ins->inst_c0;
14134                                                         ins->inst_destbasereg = var->inst_basereg;
14135                                                         ins->inst_offset = var->inst_offset;
14136                                                         spec = INS_INFO (ins->opcode);
14137                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE) || (ins->opcode == OP_RMOVE))) {
14138                                                         ins->opcode = store_opcode;
14139                                                         ins->inst_destbasereg = var->inst_basereg;
14140                                                         ins->inst_offset = var->inst_offset;
14141
14142                                                         no_lvreg = TRUE;
14143
14144                                                         tmp_reg = ins->dreg;
14145                                                         ins->dreg = ins->sreg2;
14146                                                         ins->sreg2 = tmp_reg;
14147                                                         store = TRUE;
14148
14149                                                         spec2 [MONO_INST_DEST] = ' ';
14150                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14151                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14152                                                         spec2 [MONO_INST_SRC3] = ' ';
14153                                                         spec = spec2;
14154                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
14155                                                         // FIXME: The backends expect the base reg to be in inst_basereg
14156                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
14157                                                         ins->dreg = -1;
14158                                                         ins->inst_basereg = var->inst_basereg;
14159                                                         ins->inst_offset = var->inst_offset;
14160                                                         spec = INS_INFO (ins->opcode);
14161                                                 } else {
14162                                                         /* printf ("INS: "); mono_print_ins (ins); */
14163                                                         /* Create a store instruction */
14164                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
14165
14166                                                         /* Insert it after the instruction */
14167                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
14168
14169                                                         def_ins = store_ins;
14170
14171                                                         /* 
14172                                                          * We can't assign ins->dreg to var->dreg here, since the
14173                                                          * sregs could use it. So set a flag, and do it after
14174                                                          * the sregs.
14175                                                          */
14176                                                         if ((!MONO_ARCH_USE_FPSTACK || ((store_opcode != OP_STORER8_MEMBASE_REG) && (store_opcode != OP_STORER4_MEMBASE_REG))) && !((var)->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT)))
14177                                                                 dest_has_lvreg = TRUE;
14178                                                 }
14179                                         }
14180                                 }
14181
14182                                 if (def_ins && !live_range_start [dreg]) {
14183                                         live_range_start [dreg] = def_ins;
14184                                         live_range_start_bb [dreg] = bb;
14185                                 }
14186
14187                                 if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) {
14188                                         MonoInst *tmp;
14189
14190                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
14191                                         tmp->inst_c1 = dreg;
14192                                         mono_bblock_insert_after_ins (bb, def_ins, tmp);
14193                                 }
14194                         }
14195
14196                         /************/
14197                         /*  SREGS   */
14198                         /************/
14199                         num_sregs = mono_inst_get_src_registers (ins, sregs);
14200                         for (srcindex = 0; srcindex < 3; ++srcindex) {
14201                                 regtype = spec [MONO_INST_SRC1 + srcindex];
14202                                 sreg = sregs [srcindex];
14203
14204                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
14205                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
14206                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
14207                                         MonoInst *use_ins = ins;
14208                                         MonoInst *load_ins;
14209                                         guint32 load_opcode;
14210
14211                                         if (var->opcode == OP_REGVAR) {
14212                                                 sregs [srcindex] = var->dreg;
14213                                                 //mono_inst_set_src_registers (ins, sregs);
14214                                                 live_range_end [sreg] = use_ins;
14215                                                 live_range_end_bb [sreg] = bb;
14216
14217                                                 if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14218                                                         MonoInst *tmp;
14219
14220                                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14221                                                         /* var->dreg is a hreg */
14222                                                         tmp->inst_c1 = sreg;
14223                                                         mono_bblock_insert_after_ins (bb, ins, tmp);
14224                                                 }
14225
14226                                                 continue;
14227                                         }
14228
14229                                         g_assert (var->opcode == OP_REGOFFSET);
14230                                                 
14231                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
14232
14233                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
14234
14235                                         if (vreg_to_lvreg [sreg]) {
14236                                                 g_assert (vreg_to_lvreg [sreg] != -1);
14237
14238                                                 /* The variable is already loaded to an lvreg */
14239                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14240                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
14241                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
14242                                                 //mono_inst_set_src_registers (ins, sregs);
14243                                                 continue;
14244                                         }
14245
14246                                         /* Try to fuse the load into the instruction */
14247                                         if ((srcindex == 0) && (op_to_op_src1_membase (load_opcode, ins->opcode) != -1)) {
14248                                                 ins->opcode = op_to_op_src1_membase (load_opcode, ins->opcode);
14249                                                 sregs [0] = var->inst_basereg;
14250                                                 //mono_inst_set_src_registers (ins, sregs);
14251                                                 ins->inst_offset = var->inst_offset;
14252                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (load_opcode, ins->opcode) != -1)) {
14253                                                 ins->opcode = op_to_op_src2_membase (load_opcode, ins->opcode);
14254                                                 sregs [1] = var->inst_basereg;
14255                                                 //mono_inst_set_src_registers (ins, sregs);
14256                                                 ins->inst_offset = var->inst_offset;
14257                                         } else {
14258                                                 if (MONO_IS_REAL_MOVE (ins)) {
14259                                                         ins->opcode = OP_NOP;
14260                                                         sreg = ins->dreg;
14261                                                 } else {
14262                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
14263
14264                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
14265
14266                                                         if ((!MONO_ARCH_USE_FPSTACK || ((load_opcode != OP_LOADR8_MEMBASE) && (load_opcode != OP_LOADR4_MEMBASE))) && !((var)->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT)) && !no_lvreg) {
14267                                                                 if (var->dreg == prev_dreg) {
14268                                                                         /*
14269                                                                          * sreg refers to the value loaded by the load
14270                                                                          * emitted below, but we need to use ins->dreg
14271                                                                          * since it refers to the store emitted earlier.
14272                                                                          */
14273                                                                         sreg = ins->dreg;
14274                                                                 }
14275                                                                 g_assert (sreg != -1);
14276                                                                 vreg_to_lvreg [var->dreg] = sreg;
14277                                                                 g_assert (lvregs_len < 1024);
14278                                                                 lvregs [lvregs_len ++] = var->dreg;
14279                                                         }
14280                                                 }
14281
14282                                                 sregs [srcindex] = sreg;
14283                                                 //mono_inst_set_src_registers (ins, sregs);
14284
14285 #if SIZEOF_REGISTER != 8
14286                                                 if (regtype == 'l') {
14287                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 2, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
14288                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14289                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 1, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
14290                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14291                                                         use_ins = load_ins;
14292                                                 }
14293                                                 else
14294 #endif
14295                                                 {
14296 #if SIZEOF_REGISTER == 4
14297                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
14298 #endif
14299                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
14300                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14301                                                         use_ins = load_ins;
14302                                                 }
14303                                         }
14304
14305                                         if (var->dreg < orig_next_vreg) {
14306                                                 live_range_end [var->dreg] = use_ins;
14307                                                 live_range_end_bb [var->dreg] = bb;
14308                                         }
14309
14310                                         if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14311                                                 MonoInst *tmp;
14312
14313                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14314                                                 tmp->inst_c1 = var->dreg;
14315                                                 mono_bblock_insert_after_ins (bb, ins, tmp);
14316                                         }
14317                                 }
14318                         }
14319                         mono_inst_set_src_registers (ins, sregs);
14320
14321                         if (dest_has_lvreg) {
14322                                 g_assert (ins->dreg != -1);
14323                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
14324                                 g_assert (lvregs_len < 1024);
14325                                 lvregs [lvregs_len ++] = prev_dreg;
14326                                 dest_has_lvreg = FALSE;
14327                         }
14328
14329                         if (store) {
14330                                 tmp_reg = ins->dreg;
14331                                 ins->dreg = ins->sreg2;
14332                                 ins->sreg2 = tmp_reg;
14333                         }
14334
14335                         if (MONO_IS_CALL (ins)) {
14336                                 /* Clear vreg_to_lvreg array */
14337                                 for (i = 0; i < lvregs_len; i++)
14338                                         vreg_to_lvreg [lvregs [i]] = 0;
14339                                 lvregs_len = 0;
14340                         } else if (ins->opcode == OP_NOP) {
14341                                 ins->dreg = -1;
14342                                 MONO_INST_NULLIFY_SREGS (ins);
14343                         }
14344
14345                         if (cfg->verbose_level > 2)
14346                                 mono_print_ins_index (1, ins);
14347                 }
14348
14349                 /* Extend the live range based on the liveness info */
14350                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
14351                         for (i = 0; i < cfg->num_varinfo; i ++) {
14352                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
14353
14354                                 if (vreg_is_volatile (cfg, vi->vreg))
14355                                         /* The liveness info is incomplete */
14356                                         continue;
14357
14358                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
14359                                         /* Live from at least the first ins of this bb */
14360                                         live_range_start [vi->vreg] = bb->code;
14361                                         live_range_start_bb [vi->vreg] = bb;
14362                                 }
14363
14364                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
14365                                         /* Live at least until the last ins of this bb */
14366                                         live_range_end [vi->vreg] = bb->last_ins;
14367                                         live_range_end_bb [vi->vreg] = bb;
14368                                 }
14369                         }
14370                 }
14371         }
14372         
14373 #ifdef MONO_ARCH_HAVE_LIVERANGE_OPS
14374         /*
14375          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
14376          * by storing the current native offset into MonoMethodVar->live_range_start/end.
14377          */
14378         if (cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
14379                 for (i = 0; i < cfg->num_varinfo; ++i) {
14380                         int vreg = MONO_VARINFO (cfg, i)->vreg;
14381                         MonoInst *ins;
14382
14383                         if (live_range_start [vreg]) {
14384                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
14385                                 ins->inst_c0 = i;
14386                                 ins->inst_c1 = vreg;
14387                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
14388                         }
14389                         if (live_range_end [vreg]) {
14390                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
14391                                 ins->inst_c0 = i;
14392                                 ins->inst_c1 = vreg;
14393                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
14394                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
14395                                 else
14396                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
14397                         }
14398                 }
14399         }
14400 #endif
14401
14402         if (cfg->gsharedvt_locals_var_ins) {
14403                 /* Nullify if unused */
14404                 cfg->gsharedvt_locals_var_ins->opcode = OP_PCONST;
14405                 cfg->gsharedvt_locals_var_ins->inst_imm = 0;
14406         }
14407
14408         g_free (live_range_start);
14409         g_free (live_range_end);
14410         g_free (live_range_start_bb);
14411         g_free (live_range_end_bb);
14412 }
14413
14414 /**
14415  * FIXME:
14416  * - use 'iadd' instead of 'int_add'
14417  * - handling ovf opcodes: decompose in method_to_ir.
14418  * - unify iregs/fregs
14419  *   -> partly done, the missing parts are:
14420  *   - a more complete unification would involve unifying the hregs as well, so
14421  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
14422  *     would no longer map to the machine hregs, so the code generators would need to
14423  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
14424  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
14425  *     fp/non-fp branches speeds it up by about 15%.
14426  * - use sext/zext opcodes instead of shifts
14427  * - add OP_ICALL
14428  * - get rid of TEMPLOADs if possible and use vregs instead
14429  * - clean up usage of OP_P/OP_ opcodes
14430  * - cleanup usage of DUMMY_USE
14431  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
14432  *   stack
14433  * - set the stack type and allocate a dreg in the EMIT_NEW macros
14434  * - get rid of all the <foo>2 stuff when the new JIT is ready.
14435  * - make sure handle_stack_args () is called before the branch is emitted
14436  * - when the new IR is done, get rid of all unused stuff
14437  * - COMPARE/BEQ as separate instructions or unify them ?
14438  *   - keeping them separate allows specialized compare instructions like
14439  *     compare_imm, compare_membase
14440  *   - most back ends unify fp compare+branch, fp compare+ceq
14441  * - integrate mono_save_args into inline_method
14442  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
14443  * - handle long shift opts on 32 bit platforms somehow: they require 
14444  *   3 sregs (2 for arg1 and 1 for arg2)
14445  * - make byref a 'normal' type.
14446  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
14447  *   variable if needed.
14448  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
14449  *   like inline_method.
14450  * - remove inlining restrictions
14451  * - fix LNEG and enable cfold of INEG
14452  * - generalize x86 optimizations like ldelema as a peephole optimization
14453  * - add store_mem_imm for amd64
14454  * - optimize the loading of the interruption flag in the managed->native wrappers
14455  * - avoid special handling of OP_NOP in passes
14456  * - move code inserting instructions into one function/macro.
14457  * - try a coalescing phase after liveness analysis
14458  * - add float -> vreg conversion + local optimizations on !x86
14459  * - figure out how to handle decomposed branches during optimizations, ie.
14460  *   compare+branch, op_jump_table+op_br etc.
14461  * - promote RuntimeXHandles to vregs
14462  * - vtype cleanups:
14463  *   - add a NEW_VARLOADA_VREG macro
14464  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
14465  *   accessing vtype fields.
14466  * - get rid of I8CONST on 64 bit platforms
14467  * - dealing with the increase in code size due to branches created during opcode
14468  *   decomposition:
14469  *   - use extended basic blocks
14470  *     - all parts of the JIT
14471  *     - handle_global_vregs () && local regalloc
14472  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
14473  * - sources of increase in code size:
14474  *   - vtypes
14475  *   - long compares
14476  *   - isinst and castclass
14477  *   - lvregs not allocated to global registers even if used multiple times
14478  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
14479  *   meaningful.
14480  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
14481  * - add all micro optimizations from the old JIT
14482  * - put tree optimizations into the deadce pass
14483  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
14484  *   specific function.
14485  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
14486  *   fcompare + branchCC.
14487  * - create a helper function for allocating a stack slot, taking into account 
14488  *   MONO_CFG_HAS_SPILLUP.
14489  * - merge r68207.
14490  * - merge the ia64 switch changes.
14491  * - optimize mono_regstate2_alloc_int/float.
14492  * - fix the pessimistic handling of variables accessed in exception handler blocks.
14493  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
14494  *   parts of the tree could be separated by other instructions, killing the tree
14495  *   arguments, or stores killing loads etc. Also, should we fold loads into other
14496  *   instructions if the result of the load is used multiple times ?
14497  * - make the REM_IMM optimization in mini-x86.c arch-independent.
14498  * - LAST MERGE: 108395.
14499  * - when returning vtypes in registers, generate IR and append it to the end of the
14500  *   last bb instead of doing it in the epilog.
14501  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
14502  */
14503
14504 /*
14505
14506 NOTES
14507 -----
14508
14509 - When to decompose opcodes:
14510   - earlier: this makes some optimizations hard to implement, since the low level IR
14511   no longer contains the neccessary information. But it is easier to do.
14512   - later: harder to implement, enables more optimizations.
14513 - Branches inside bblocks:
14514   - created when decomposing complex opcodes. 
14515     - branches to another bblock: harmless, but not tracked by the branch 
14516       optimizations, so need to branch to a label at the start of the bblock.
14517     - branches to inside the same bblock: very problematic, trips up the local
14518       reg allocator. Can be fixed by spitting the current bblock, but that is a
14519       complex operation, since some local vregs can become global vregs etc.
14520 - Local/global vregs:
14521   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
14522     local register allocator.
14523   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
14524     structure, created by mono_create_var (). Assigned to hregs or the stack by
14525     the global register allocator.
14526 - When to do optimizations like alu->alu_imm:
14527   - earlier -> saves work later on since the IR will be smaller/simpler
14528   - later -> can work on more instructions
14529 - Handling of valuetypes:
14530   - When a vtype is pushed on the stack, a new temporary is created, an 
14531     instruction computing its address (LDADDR) is emitted and pushed on
14532     the stack. Need to optimize cases when the vtype is used immediately as in
14533     argument passing, stloc etc.
14534 - Instead of the to_end stuff in the old JIT, simply call the function handling
14535   the values on the stack before emitting the last instruction of the bb.
14536 */
14537
14538 #endif /* DISABLE_JIT */