Merge pull request #1605 from iainx/cov-install-coverage-filter
[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/gc-internal.h>
53 #include <mono/metadata/security-manager.h>
54 #include <mono/metadata/threads-types.h>
55 #include <mono/metadata/security-core-clr.h>
56 #include <mono/metadata/monitor.h>
57 #include <mono/metadata/profiler-private.h>
58 #include <mono/metadata/profiler.h>
59 #include <mono/metadata/debug-mono-symfile.h>
60 #include <mono/utils/mono-compiler.h>
61 #include <mono/utils/mono-memory-model.h>
62 #include <mono/metadata/mono-basic-block.h>
63
64 #include "trace.h"
65
66 #include "ir-emit.h"
67
68 #include "jit-icalls.h"
69 #include "jit.h"
70 #include "debugger-agent.h"
71 #include "seq-points.h"
72
73 #define BRANCH_COST 10
74 #define INLINE_LENGTH_LIMIT 20
75
76 /* These have 'cfg' as an implicit argument */
77 #define INLINE_FAILURE(msg) do {                                                                        \
78         if ((cfg->method != cfg->current_method) && (cfg->current_method->wrapper_type == MONO_WRAPPER_NONE)) { \
79                 inline_failure (cfg, msg);                                                                              \
80                 goto exception_exit;                                                                                    \
81         } \
82         } while (0)
83 #define CHECK_CFG_EXCEPTION do {\
84                 if (cfg->exception_type != MONO_EXCEPTION_NONE) \
85                         goto exception_exit;                                            \
86         } while (0)
87 #define METHOD_ACCESS_FAILURE(method, cmethod) do {                     \
88                 method_access_failure ((cfg), (method), (cmethod));                     \
89                 goto exception_exit;                                                                            \
90         } while (0)
91 #define FIELD_ACCESS_FAILURE(method, field) do {                                        \
92                 field_access_failure ((cfg), (method), (field));                        \
93                 goto exception_exit;    \
94         } while (0)
95 #define GENERIC_SHARING_FAILURE(opcode) do {            \
96                 if (cfg->gshared) {                                                                     \
97                         gshared_failure (cfg, opcode, __FILE__, __LINE__);      \
98                         goto exception_exit;    \
99                 }                       \
100         } while (0)
101 #define GSHAREDVT_FAILURE(opcode) do {          \
102         if (cfg->gsharedvt) {                                                                                           \
103                 gsharedvt_failure (cfg, opcode, __FILE__, __LINE__);                    \
104                 goto exception_exit;                                                                                    \
105         }                                                                                                                                       \
106         } while (0)
107 #define OUT_OF_MEMORY_FAILURE do {      \
108                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_OUT_OF_MEMORY);             \
109                 goto exception_exit;    \
110         } while (0)
111 #define DISABLE_AOT(cfg) do { \
112                 if ((cfg)->verbose_level >= 2)                                            \
113                         printf ("AOT disabled: %s:%d\n", __FILE__, __LINE__);   \
114                 (cfg)->disable_aot = TRUE;                                                        \
115         } while (0)
116 #define LOAD_ERROR do { \
117                 break_on_unverified ();                                                         \
118                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD); \
119                 goto exception_exit;                                                                    \
120         } while (0)
121
122 #define TYPE_LOAD_ERROR(klass) do { \
123                 cfg->exception_ptr = klass; \
124                 LOAD_ERROR;                                     \
125         } while (0)
126
127 #define CHECK_CFG_ERROR do {\
128                 if (!mono_error_ok (&cfg->error)) { \
129                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);        \
130                         goto mono_error_exit; \
131                 } \
132         } while (0)
133
134 /* Determine whenever 'ins' represents a load of the 'this' argument */
135 #define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && ((ins)->opcode == OP_MOVE) && ((ins)->sreg1 == cfg->args [0]->dreg))
136
137 static int ldind_to_load_membase (int opcode);
138 static int stind_to_store_membase (int opcode);
139
140 int mono_op_to_op_imm (int opcode);
141 int mono_op_to_op_imm_noemul (int opcode);
142
143 MONO_API MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
144
145 static int inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
146                                                   guchar *ip, guint real_offset, gboolean inline_always, MonoBasicBlock **out_cbb);
147
148 /* helper methods signatures */
149 static MonoMethodSignature *helper_sig_class_init_trampoline;
150 static MonoMethodSignature *helper_sig_domain_get;
151 static MonoMethodSignature *helper_sig_generic_class_init_trampoline;
152 static MonoMethodSignature *helper_sig_generic_class_init_trampoline_llvm;
153 static MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline;
154 static MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline;
155 static MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline_llvm;
156 static MonoMethodSignature *helper_sig_monitor_enter_v4_trampoline_llvm;
157
158 /*
159  * Instruction metadata
160  */
161 #ifdef MINI_OP
162 #undef MINI_OP
163 #endif
164 #ifdef MINI_OP3
165 #undef MINI_OP3
166 #endif
167 #define MINI_OP(a,b,dest,src1,src2) dest, src1, src2, ' ',
168 #define MINI_OP3(a,b,dest,src1,src2,src3) dest, src1, src2, src3,
169 #define NONE ' '
170 #define IREG 'i'
171 #define FREG 'f'
172 #define VREG 'v'
173 #define XREG 'x'
174 #if SIZEOF_REGISTER == 8 && SIZEOF_REGISTER == SIZEOF_VOID_P
175 #define LREG IREG
176 #else
177 #define LREG 'l'
178 #endif
179 /* keep in sync with the enum in mini.h */
180 const char
181 ins_info[] = {
182 #include "mini-ops.h"
183 };
184 #undef MINI_OP
185 #undef MINI_OP3
186
187 #define MINI_OP(a,b,dest,src1,src2) ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0)),
188 #define MINI_OP3(a,b,dest,src1,src2,src3) ((src3) != NONE ? 3 : ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0))),
189 /* 
190  * This should contain the index of the last sreg + 1. This is not the same
191  * as the number of sregs for opcodes like IA64_CMP_EQ_IMM.
192  */
193 const gint8 ins_sreg_counts[] = {
194 #include "mini-ops.h"
195 };
196 #undef MINI_OP
197 #undef MINI_OP3
198
199 #define MONO_INIT_VARINFO(vi,id) do { \
200         (vi)->range.first_use.pos.bid = 0xffff; \
201         (vi)->reg = -1; \
202         (vi)->idx = (id); \
203 } while (0)
204
205 guint32
206 mono_alloc_ireg (MonoCompile *cfg)
207 {
208         return alloc_ireg (cfg);
209 }
210
211 guint32
212 mono_alloc_lreg (MonoCompile *cfg)
213 {
214         return alloc_lreg (cfg);
215 }
216
217 guint32
218 mono_alloc_freg (MonoCompile *cfg)
219 {
220         return alloc_freg (cfg);
221 }
222
223 guint32
224 mono_alloc_preg (MonoCompile *cfg)
225 {
226         return alloc_preg (cfg);
227 }
228
229 guint32
230 mono_alloc_dreg (MonoCompile *cfg, MonoStackType stack_type)
231 {
232         return alloc_dreg (cfg, stack_type);
233 }
234
235 /*
236  * mono_alloc_ireg_ref:
237  *
238  *   Allocate an IREG, and mark it as holding a GC ref.
239  */
240 guint32
241 mono_alloc_ireg_ref (MonoCompile *cfg)
242 {
243         return alloc_ireg_ref (cfg);
244 }
245
246 /*
247  * mono_alloc_ireg_mp:
248  *
249  *   Allocate an IREG, and mark it as holding a managed pointer.
250  */
251 guint32
252 mono_alloc_ireg_mp (MonoCompile *cfg)
253 {
254         return alloc_ireg_mp (cfg);
255 }
256
257 /*
258  * mono_alloc_ireg_copy:
259  *
260  *   Allocate an IREG with the same GC type as VREG.
261  */
262 guint32
263 mono_alloc_ireg_copy (MonoCompile *cfg, guint32 vreg)
264 {
265         if (vreg_is_ref (cfg, vreg))
266                 return alloc_ireg_ref (cfg);
267         else if (vreg_is_mp (cfg, vreg))
268                 return alloc_ireg_mp (cfg);
269         else
270                 return alloc_ireg (cfg);
271 }
272
273 guint
274 mono_type_to_regmove (MonoCompile *cfg, MonoType *type)
275 {
276         if (type->byref)
277                 return OP_MOVE;
278
279         type = mini_replace_type (type);
280 handle_enum:
281         switch (type->type) {
282         case MONO_TYPE_I1:
283         case MONO_TYPE_U1:
284         case MONO_TYPE_BOOLEAN:
285                 return OP_MOVE;
286         case MONO_TYPE_I2:
287         case MONO_TYPE_U2:
288         case MONO_TYPE_CHAR:
289                 return OP_MOVE;
290         case MONO_TYPE_I4:
291         case MONO_TYPE_U4:
292                 return OP_MOVE;
293         case MONO_TYPE_I:
294         case MONO_TYPE_U:
295         case MONO_TYPE_PTR:
296         case MONO_TYPE_FNPTR:
297                 return OP_MOVE;
298         case MONO_TYPE_CLASS:
299         case MONO_TYPE_STRING:
300         case MONO_TYPE_OBJECT:
301         case MONO_TYPE_SZARRAY:
302         case MONO_TYPE_ARRAY:    
303                 return OP_MOVE;
304         case MONO_TYPE_I8:
305         case MONO_TYPE_U8:
306 #if SIZEOF_REGISTER == 8
307                 return OP_MOVE;
308 #else
309                 return OP_LMOVE;
310 #endif
311         case MONO_TYPE_R4:
312                 return cfg->r4fp ? OP_RMOVE : OP_FMOVE;
313         case MONO_TYPE_R8:
314                 return OP_FMOVE;
315         case MONO_TYPE_VALUETYPE:
316                 if (type->data.klass->enumtype) {
317                         type = mono_class_enum_basetype (type->data.klass);
318                         goto handle_enum;
319                 }
320                 if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
321                         return OP_XMOVE;
322                 return OP_VMOVE;
323         case MONO_TYPE_TYPEDBYREF:
324                 return OP_VMOVE;
325         case MONO_TYPE_GENERICINST:
326                 type = &type->data.generic_class->container_class->byval_arg;
327                 goto handle_enum;
328         case MONO_TYPE_VAR:
329         case MONO_TYPE_MVAR:
330                 g_assert (cfg->generic_sharing_context);
331                 if (mini_type_var_is_vt (cfg, type))
332                         return OP_VMOVE;
333                 else
334                         return OP_MOVE;
335         default:
336                 g_error ("unknown type 0x%02x in type_to_regstore", type->type);
337         }
338         return -1;
339 }
340
341 void
342 mono_print_bb (MonoBasicBlock *bb, const char *msg)
343 {
344         int i;
345         MonoInst *tree;
346
347         printf ("\n%s %d: [IN: ", msg, bb->block_num);
348         for (i = 0; i < bb->in_count; ++i)
349                 printf (" BB%d(%d)", bb->in_bb [i]->block_num, bb->in_bb [i]->dfn);
350         printf (", OUT: ");
351         for (i = 0; i < bb->out_count; ++i)
352                 printf (" BB%d(%d)", bb->out_bb [i]->block_num, bb->out_bb [i]->dfn);
353         printf (" ]\n");
354         for (tree = bb->code; tree; tree = tree->next)
355                 mono_print_ins_index (-1, tree);
356 }
357
358 void
359 mono_create_helper_signatures (void)
360 {
361         helper_sig_domain_get = mono_create_icall_signature ("ptr");
362         helper_sig_class_init_trampoline = mono_create_icall_signature ("void");
363         helper_sig_generic_class_init_trampoline = mono_create_icall_signature ("void");
364         helper_sig_generic_class_init_trampoline_llvm = mono_create_icall_signature ("void ptr");
365         helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
366         helper_sig_monitor_enter_exit_trampoline = mono_create_icall_signature ("void");
367         helper_sig_monitor_enter_exit_trampoline_llvm = mono_create_icall_signature ("void object");
368         helper_sig_monitor_enter_v4_trampoline_llvm = mono_create_icall_signature ("void object ptr");
369 }
370
371 static MONO_NEVER_INLINE void
372 break_on_unverified (void)
373 {
374         if (mini_get_debug_options ()->break_on_unverified)
375                 G_BREAKPOINT ();
376 }
377
378 static MONO_NEVER_INLINE void
379 method_access_failure (MonoCompile *cfg, MonoMethod *method, MonoMethod *cil_method)
380 {
381         char *method_fname = mono_method_full_name (method, TRUE);
382         char *cil_method_fname = mono_method_full_name (cil_method, TRUE);
383         mono_cfg_set_exception (cfg, MONO_EXCEPTION_METHOD_ACCESS);
384         cfg->exception_message = g_strdup_printf ("Method `%s' is inaccessible from method `%s'\n", cil_method_fname, method_fname);
385         g_free (method_fname);
386         g_free (cil_method_fname);
387 }
388
389 static MONO_NEVER_INLINE void
390 field_access_failure (MonoCompile *cfg, MonoMethod *method, MonoClassField *field)
391 {
392         char *method_fname = mono_method_full_name (method, TRUE);
393         char *field_fname = mono_field_full_name (field);
394         mono_cfg_set_exception (cfg, MONO_EXCEPTION_FIELD_ACCESS);
395         cfg->exception_message = g_strdup_printf ("Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname);
396         g_free (method_fname);
397         g_free (field_fname);
398 }
399
400 static MONO_NEVER_INLINE void
401 inline_failure (MonoCompile *cfg, const char *msg)
402 {
403         if (cfg->verbose_level >= 2)
404                 printf ("inline failed: %s\n", msg);
405         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INLINE_FAILED);
406 }
407
408 static MONO_NEVER_INLINE void
409 gshared_failure (MonoCompile *cfg, int opcode, const char *file, int line)
410 {
411         if (cfg->verbose_level > 2)                                                                                     \
412                 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__);
413         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
414 }
415
416 static MONO_NEVER_INLINE void
417 gsharedvt_failure (MonoCompile *cfg, int opcode, const char *file, int line)
418 {
419         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);
420         if (cfg->verbose_level >= 2)
421                 printf ("%s\n", cfg->exception_message);
422         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
423 }
424
425 /*
426  * When using gsharedvt, some instatiations might be verifiable, and some might be not. i.e. 
427  * foo<T> (int i) { ldarg.0; box T; }
428  */
429 #define UNVERIFIED do { \
430         if (cfg->gsharedvt) { \
431                 if (cfg->verbose_level > 2)                                                                     \
432                         printf ("gsharedvt method failed to verify, falling back to instantiation.\n"); \
433                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED); \
434                 goto exception_exit;                                                                                    \
435         }                                                                                                                                       \
436         break_on_unverified ();                                                                                         \
437         goto unverified;                                                                                                        \
438 } while (0)
439
440 #define GET_BBLOCK(cfg,tblock,ip) do {  \
441                 (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
442                 if (!(tblock)) {        \
443                         if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
444             NEW_BBLOCK (cfg, (tblock)); \
445                         (tblock)->cil_code = (ip);      \
446                         ADD_BBLOCK (cfg, (tblock));     \
447                 } \
448         } while (0)
449
450 #if defined(TARGET_X86) || defined(TARGET_AMD64)
451 #define EMIT_NEW_X86_LEA(cfg,dest,sr1,sr2,shift,imm) do { \
452                 MONO_INST_NEW (cfg, dest, OP_X86_LEA); \
453                 (dest)->dreg = alloc_ireg_mp ((cfg)); \
454                 (dest)->sreg1 = (sr1); \
455                 (dest)->sreg2 = (sr2); \
456                 (dest)->inst_imm = (imm); \
457                 (dest)->backend.shift_amount = (shift); \
458                 MONO_ADD_INS ((cfg)->cbb, (dest)); \
459         } while (0)
460 #endif
461
462 /* Emit conversions so both operands of a binary opcode are of the same type */
463 static void
464 add_widen_op (MonoCompile *cfg, MonoInst *ins, MonoInst **arg1_ref, MonoInst **arg2_ref)
465 {
466         MonoInst *arg1 = *arg1_ref;
467         MonoInst *arg2 = *arg2_ref;
468
469         if (cfg->r4fp &&
470                 ((arg1->type == STACK_R4 && arg2->type == STACK_R8) ||
471                  (arg1->type == STACK_R8 && arg2->type == STACK_R4))) {
472                 MonoInst *conv;
473
474                 /* Mixing r4/r8 is allowed by the spec */
475                 if (arg1->type == STACK_R4) {
476                         int dreg = alloc_freg (cfg);
477
478                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg1->dreg);
479                         conv->type = STACK_R8;
480                         ins->sreg1 = dreg;
481                         *arg1_ref = conv;
482                 }
483                 if (arg2->type == STACK_R4) {
484                         int dreg = alloc_freg (cfg);
485
486                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg2->dreg);
487                         conv->type = STACK_R8;
488                         ins->sreg2 = dreg;
489                         *arg2_ref = conv;
490                 }
491         }
492
493 #if SIZEOF_REGISTER == 8
494         /* FIXME: Need to add many more cases */
495         if ((arg1)->type == STACK_PTR && (arg2)->type == STACK_I4) {
496                 MonoInst *widen;
497
498                 int dr = alloc_preg (cfg);
499                 EMIT_NEW_UNALU (cfg, widen, OP_SEXT_I4, dr, (arg2)->dreg);
500                 (ins)->sreg2 = widen->dreg;
501         }
502 #endif
503 }
504
505 #define ADD_BINOP(op) do {      \
506                 MONO_INST_NEW (cfg, ins, (op)); \
507                 sp -= 2;        \
508                 ins->sreg1 = sp [0]->dreg;      \
509                 ins->sreg2 = sp [1]->dreg;      \
510                 type_from_op (cfg, ins, sp [0], sp [1]);        \
511                 CHECK_TYPE (ins);       \
512                 /* Have to insert a widening op */               \
513         add_widen_op (cfg, ins, &sp [0], &sp [1]);               \
514         ins->dreg = alloc_dreg ((cfg), (ins)->type); \
515         MONO_ADD_INS ((cfg)->cbb, (ins)); \
516         *sp++ = mono_decompose_opcode ((cfg), (ins), &bblock);  \
517         } while (0)
518
519 #define ADD_UNOP(op) do {       \
520                 MONO_INST_NEW (cfg, ins, (op)); \
521                 sp--;   \
522                 ins->sreg1 = sp [0]->dreg;      \
523                 type_from_op (cfg, ins, sp [0], NULL);  \
524                 CHECK_TYPE (ins);       \
525         (ins)->dreg = alloc_dreg ((cfg), (ins)->type); \
526         MONO_ADD_INS ((cfg)->cbb, (ins)); \
527                 *sp++ = mono_decompose_opcode (cfg, ins, &bblock);      \
528         } while (0)
529
530 #define ADD_BINCOND(next_block) do {    \
531                 MonoInst *cmp;  \
532                 sp -= 2; \
533                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
534                 cmp->sreg1 = sp [0]->dreg;      \
535                 cmp->sreg2 = sp [1]->dreg;      \
536                 type_from_op (cfg, cmp, sp [0], sp [1]);        \
537                 CHECK_TYPE (cmp);       \
538                 add_widen_op (cfg, cmp, &sp [0], &sp [1]);                                              \
539                 type_from_op (cfg, ins, sp [0], sp [1]);                                                        \
540                 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);      \
541                 GET_BBLOCK (cfg, tblock, target);               \
542                 link_bblock (cfg, bblock, tblock);      \
543                 ins->inst_true_bb = tblock;     \
544                 if ((next_block)) {     \
545                         link_bblock (cfg, bblock, (next_block));        \
546                         ins->inst_false_bb = (next_block);      \
547                         start_new_bblock = 1;   \
548                 } else {        \
549                         GET_BBLOCK (cfg, tblock, ip);           \
550                         link_bblock (cfg, bblock, tblock);      \
551                         ins->inst_false_bb = tblock;    \
552                         start_new_bblock = 2;   \
553                 }       \
554                 if (sp != stack_start) {                                                                        \
555                     handle_stack_args (cfg, stack_start, sp - stack_start); \
556                         CHECK_UNVERIFIABLE (cfg); \
557                 } \
558         MONO_ADD_INS (bblock, cmp); \
559                 MONO_ADD_INS (bblock, ins);     \
560         } while (0)
561
562 /* *
563  * link_bblock: Links two basic blocks
564  *
565  * links two basic blocks in the control flow graph, the 'from'
566  * argument is the starting block and the 'to' argument is the block
567  * the control flow ends to after 'from'.
568  */
569 static void
570 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
571 {
572         MonoBasicBlock **newa;
573         int i, found;
574
575 #if 0
576         if (from->cil_code) {
577                 if (to->cil_code)
578                         printf ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
579                 else
580                         printf ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
581         } else {
582                 if (to->cil_code)
583                         printf ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
584                 else
585                         printf ("edge from entry to exit\n");
586         }
587 #endif
588
589         found = FALSE;
590         for (i = 0; i < from->out_count; ++i) {
591                 if (to == from->out_bb [i]) {
592                         found = TRUE;
593                         break;
594                 }
595         }
596         if (!found) {
597                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
598                 for (i = 0; i < from->out_count; ++i) {
599                         newa [i] = from->out_bb [i];
600                 }
601                 newa [i] = to;
602                 from->out_count++;
603                 from->out_bb = newa;
604         }
605
606         found = FALSE;
607         for (i = 0; i < to->in_count; ++i) {
608                 if (from == to->in_bb [i]) {
609                         found = TRUE;
610                         break;
611                 }
612         }
613         if (!found) {
614                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
615                 for (i = 0; i < to->in_count; ++i) {
616                         newa [i] = to->in_bb [i];
617                 }
618                 newa [i] = from;
619                 to->in_count++;
620                 to->in_bb = newa;
621         }
622 }
623
624 void
625 mono_link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
626 {
627         link_bblock (cfg, from, to);
628 }
629
630 /**
631  * mono_find_block_region:
632  *
633  *   We mark each basic block with a region ID. We use that to avoid BB
634  *   optimizations when blocks are in different regions.
635  *
636  * Returns:
637  *   A region token that encodes where this region is, and information
638  *   about the clause owner for this block.
639  *
640  *   The region encodes the try/catch/filter clause that owns this block
641  *   as well as the type.  -1 is a special value that represents a block
642  *   that is in none of try/catch/filter.
643  */
644 static int
645 mono_find_block_region (MonoCompile *cfg, int offset)
646 {
647         MonoMethodHeader *header = cfg->header;
648         MonoExceptionClause *clause;
649         int i;
650
651         for (i = 0; i < header->num_clauses; ++i) {
652                 clause = &header->clauses [i];
653                 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
654                     (offset < (clause->handler_offset)))
655                         return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
656                            
657                 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
658                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
659                                 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
660                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
661                                 return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
662                         else
663                                 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
664                 }
665
666                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
667                         return ((i + 1) << 8) | clause->flags;
668         }
669
670         return -1;
671 }
672
673 static GList*
674 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
675 {
676         MonoMethodHeader *header = cfg->header;
677         MonoExceptionClause *clause;
678         int i;
679         GList *res = NULL;
680
681         for (i = 0; i < header->num_clauses; ++i) {
682                 clause = &header->clauses [i];
683                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
684                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
685                         if (clause->flags == type)
686                                 res = g_list_append (res, clause);
687                 }
688         }
689         return res;
690 }
691
692 static void
693 mono_create_spvar_for_region (MonoCompile *cfg, int region)
694 {
695         MonoInst *var;
696
697         var = g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
698         if (var)
699                 return;
700
701         var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
702         /* prevent it from being register allocated */
703         var->flags |= MONO_INST_VOLATILE;
704
705         g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
706 }
707
708 MonoInst *
709 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
710 {
711         return g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
712 }
713
714 static MonoInst*
715 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
716 {
717         MonoInst *var;
718
719         var = g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
720         if (var)
721                 return var;
722
723         var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
724         /* prevent it from being register allocated */
725         var->flags |= MONO_INST_VOLATILE;
726
727         g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
728
729         return var;
730 }
731
732 /*
733  * Returns the type used in the eval stack when @type is loaded.
734  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
735  */
736 void
737 type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
738 {
739         MonoClass *klass;
740
741         type = mini_replace_type (type);
742         inst->klass = klass = mono_class_from_mono_type (type);
743         if (type->byref) {
744                 inst->type = STACK_MP;
745                 return;
746         }
747
748 handle_enum:
749         switch (type->type) {
750         case MONO_TYPE_VOID:
751                 inst->type = STACK_INV;
752                 return;
753         case MONO_TYPE_I1:
754         case MONO_TYPE_U1:
755         case MONO_TYPE_BOOLEAN:
756         case MONO_TYPE_I2:
757         case MONO_TYPE_U2:
758         case MONO_TYPE_CHAR:
759         case MONO_TYPE_I4:
760         case MONO_TYPE_U4:
761                 inst->type = STACK_I4;
762                 return;
763         case MONO_TYPE_I:
764         case MONO_TYPE_U:
765         case MONO_TYPE_PTR:
766         case MONO_TYPE_FNPTR:
767                 inst->type = STACK_PTR;
768                 return;
769         case MONO_TYPE_CLASS:
770         case MONO_TYPE_STRING:
771         case MONO_TYPE_OBJECT:
772         case MONO_TYPE_SZARRAY:
773         case MONO_TYPE_ARRAY:    
774                 inst->type = STACK_OBJ;
775                 return;
776         case MONO_TYPE_I8:
777         case MONO_TYPE_U8:
778                 inst->type = STACK_I8;
779                 return;
780         case MONO_TYPE_R4:
781                 inst->type = cfg->r4_stack_type;
782                 break;
783         case MONO_TYPE_R8:
784                 inst->type = STACK_R8;
785                 return;
786         case MONO_TYPE_VALUETYPE:
787                 if (type->data.klass->enumtype) {
788                         type = mono_class_enum_basetype (type->data.klass);
789                         goto handle_enum;
790                 } else {
791                         inst->klass = klass;
792                         inst->type = STACK_VTYPE;
793                         return;
794                 }
795         case MONO_TYPE_TYPEDBYREF:
796                 inst->klass = mono_defaults.typed_reference_class;
797                 inst->type = STACK_VTYPE;
798                 return;
799         case MONO_TYPE_GENERICINST:
800                 type = &type->data.generic_class->container_class->byval_arg;
801                 goto handle_enum;
802         case MONO_TYPE_VAR:
803         case MONO_TYPE_MVAR:
804                 g_assert (cfg->generic_sharing_context);
805                 if (mini_is_gsharedvt_type (cfg, type)) {
806                         g_assert (cfg->gsharedvt);
807                         inst->type = STACK_VTYPE;
808                 } else {
809                         inst->type = STACK_OBJ;
810                 }
811                 return;
812         default:
813                 g_error ("unknown type 0x%02x in eval stack type", type->type);
814         }
815 }
816
817 /*
818  * The following tables are used to quickly validate the IL code in type_from_op ().
819  */
820 static const char
821 bin_num_table [STACK_MAX] [STACK_MAX] = {
822         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
823         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
824         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
825         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
826         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV, STACK_R8},
827         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
828         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
829         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
830         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4}
831 };
832
833 static const char 
834 neg_table [] = {
835         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4
836 };
837
838 /* reduce the size of this table */
839 static const char
840 bin_int_table [STACK_MAX] [STACK_MAX] = {
841         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
842         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
843         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
844         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
845         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
846         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
847         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
848         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
849 };
850
851 static const char
852 bin_comp_table [STACK_MAX] [STACK_MAX] = {
853 /*      Inv i  L  p  F  &  O  vt r4 */
854         {0},
855         {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
856         {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
857         {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
858         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* F, R8 */
859         {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
860         {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
861         {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
862         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* r, r4 */
863 };
864
865 /* reduce the size of this table */
866 static const char
867 shift_table [STACK_MAX] [STACK_MAX] = {
868         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
869         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
870         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
871         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
872         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
873         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
874         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
875         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
876 };
877
878 /*
879  * Tables to map from the non-specific opcode to the matching
880  * type-specific opcode.
881  */
882 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
883 static const guint16
884 binops_op_map [STACK_MAX] = {
885         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
886 };
887
888 /* handles from CEE_NEG to CEE_CONV_U8 */
889 static const guint16
890 unops_op_map [STACK_MAX] = {
891         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
892 };
893
894 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
895 static const guint16
896 ovfops_op_map [STACK_MAX] = {
897         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
898 };
899
900 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
901 static const guint16
902 ovf2ops_op_map [STACK_MAX] = {
903         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
904 };
905
906 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
907 static const guint16
908 ovf3ops_op_map [STACK_MAX] = {
909         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
910 };
911
912 /* handles from CEE_BEQ to CEE_BLT_UN */
913 static const guint16
914 beqops_op_map [STACK_MAX] = {
915         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
916 };
917
918 /* handles from CEE_CEQ to CEE_CLT_UN */
919 static const guint16
920 ceqops_op_map [STACK_MAX] = {
921         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
922 };
923
924 /*
925  * Sets ins->type (the type on the eval stack) according to the
926  * type of the opcode and the arguments to it.
927  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
928  *
929  * FIXME: this function sets ins->type unconditionally in some cases, but
930  * it should set it to invalid for some types (a conv.x on an object)
931  */
932 static void
933 type_from_op (MonoCompile *cfg, MonoInst *ins, MonoInst *src1, MonoInst *src2)
934 {
935         switch (ins->opcode) {
936         /* binops */
937         case CEE_ADD:
938         case CEE_SUB:
939         case CEE_MUL:
940         case CEE_DIV:
941         case CEE_REM:
942                 /* FIXME: check unverifiable args for STACK_MP */
943                 ins->type = bin_num_table [src1->type] [src2->type];
944                 ins->opcode += binops_op_map [ins->type];
945                 break;
946         case CEE_DIV_UN:
947         case CEE_REM_UN:
948         case CEE_AND:
949         case CEE_OR:
950         case CEE_XOR:
951                 ins->type = bin_int_table [src1->type] [src2->type];
952                 ins->opcode += binops_op_map [ins->type];
953                 break;
954         case CEE_SHL:
955         case CEE_SHR:
956         case CEE_SHR_UN:
957                 ins->type = shift_table [src1->type] [src2->type];
958                 ins->opcode += binops_op_map [ins->type];
959                 break;
960         case OP_COMPARE:
961         case OP_LCOMPARE:
962         case OP_ICOMPARE:
963                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
964                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
965                         ins->opcode = OP_LCOMPARE;
966                 else if (src1->type == STACK_R4)
967                         ins->opcode = OP_RCOMPARE;
968                 else if (src1->type == STACK_R8)
969                         ins->opcode = OP_FCOMPARE;
970                 else
971                         ins->opcode = OP_ICOMPARE;
972                 break;
973         case OP_ICOMPARE_IMM:
974                 ins->type = bin_comp_table [src1->type] [src1->type] ? STACK_I4 : STACK_INV;
975                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
976                         ins->opcode = OP_LCOMPARE_IMM;          
977                 break;
978         case CEE_BEQ:
979         case CEE_BGE:
980         case CEE_BGT:
981         case CEE_BLE:
982         case CEE_BLT:
983         case CEE_BNE_UN:
984         case CEE_BGE_UN:
985         case CEE_BGT_UN:
986         case CEE_BLE_UN:
987         case CEE_BLT_UN:
988                 ins->opcode += beqops_op_map [src1->type];
989                 break;
990         case OP_CEQ:
991                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
992                 ins->opcode += ceqops_op_map [src1->type];
993                 break;
994         case OP_CGT:
995         case OP_CGT_UN:
996         case OP_CLT:
997         case OP_CLT_UN:
998                 ins->type = (bin_comp_table [src1->type] [src2->type] & 1) ? STACK_I4: STACK_INV;
999                 ins->opcode += ceqops_op_map [src1->type];
1000                 break;
1001         /* unops */
1002         case CEE_NEG:
1003                 ins->type = neg_table [src1->type];
1004                 ins->opcode += unops_op_map [ins->type];
1005                 break;
1006         case CEE_NOT:
1007                 if (src1->type >= STACK_I4 && src1->type <= STACK_PTR)
1008                         ins->type = src1->type;
1009                 else
1010                         ins->type = STACK_INV;
1011                 ins->opcode += unops_op_map [ins->type];
1012                 break;
1013         case CEE_CONV_I1:
1014         case CEE_CONV_I2:
1015         case CEE_CONV_I4:
1016         case CEE_CONV_U4:
1017                 ins->type = STACK_I4;
1018                 ins->opcode += unops_op_map [src1->type];
1019                 break;
1020         case CEE_CONV_R_UN:
1021                 ins->type = STACK_R8;
1022                 switch (src1->type) {
1023                 case STACK_I4:
1024                 case STACK_PTR:
1025                         ins->opcode = OP_ICONV_TO_R_UN;
1026                         break;
1027                 case STACK_I8:
1028                         ins->opcode = OP_LCONV_TO_R_UN; 
1029                         break;
1030                 }
1031                 break;
1032         case CEE_CONV_OVF_I1:
1033         case CEE_CONV_OVF_U1:
1034         case CEE_CONV_OVF_I2:
1035         case CEE_CONV_OVF_U2:
1036         case CEE_CONV_OVF_I4:
1037         case CEE_CONV_OVF_U4:
1038                 ins->type = STACK_I4;
1039                 ins->opcode += ovf3ops_op_map [src1->type];
1040                 break;
1041         case CEE_CONV_OVF_I_UN:
1042         case CEE_CONV_OVF_U_UN:
1043                 ins->type = STACK_PTR;
1044                 ins->opcode += ovf2ops_op_map [src1->type];
1045                 break;
1046         case CEE_CONV_OVF_I1_UN:
1047         case CEE_CONV_OVF_I2_UN:
1048         case CEE_CONV_OVF_I4_UN:
1049         case CEE_CONV_OVF_U1_UN:
1050         case CEE_CONV_OVF_U2_UN:
1051         case CEE_CONV_OVF_U4_UN:
1052                 ins->type = STACK_I4;
1053                 ins->opcode += ovf2ops_op_map [src1->type];
1054                 break;
1055         case CEE_CONV_U:
1056                 ins->type = STACK_PTR;
1057                 switch (src1->type) {
1058                 case STACK_I4:
1059                         ins->opcode = OP_ICONV_TO_U;
1060                         break;
1061                 case STACK_PTR:
1062                 case STACK_MP:
1063 #if SIZEOF_VOID_P == 8
1064                         ins->opcode = OP_LCONV_TO_U;
1065 #else
1066                         ins->opcode = OP_MOVE;
1067 #endif
1068                         break;
1069                 case STACK_I8:
1070                         ins->opcode = OP_LCONV_TO_U;
1071                         break;
1072                 case STACK_R8:
1073                         ins->opcode = OP_FCONV_TO_U;
1074                         break;
1075                 }
1076                 break;
1077         case CEE_CONV_I8:
1078         case CEE_CONV_U8:
1079                 ins->type = STACK_I8;
1080                 ins->opcode += unops_op_map [src1->type];
1081                 break;
1082         case CEE_CONV_OVF_I8:
1083         case CEE_CONV_OVF_U8:
1084                 ins->type = STACK_I8;
1085                 ins->opcode += ovf3ops_op_map [src1->type];
1086                 break;
1087         case CEE_CONV_OVF_U8_UN:
1088         case CEE_CONV_OVF_I8_UN:
1089                 ins->type = STACK_I8;
1090                 ins->opcode += ovf2ops_op_map [src1->type];
1091                 break;
1092         case CEE_CONV_R4:
1093                 ins->type = cfg->r4_stack_type;
1094                 ins->opcode += unops_op_map [src1->type];
1095                 break;
1096         case CEE_CONV_R8:
1097                 ins->type = STACK_R8;
1098                 ins->opcode += unops_op_map [src1->type];
1099                 break;
1100         case OP_CKFINITE:
1101                 ins->type = STACK_R8;           
1102                 break;
1103         case CEE_CONV_U2:
1104         case CEE_CONV_U1:
1105                 ins->type = STACK_I4;
1106                 ins->opcode += ovfops_op_map [src1->type];
1107                 break;
1108         case CEE_CONV_I:
1109         case CEE_CONV_OVF_I:
1110         case CEE_CONV_OVF_U:
1111                 ins->type = STACK_PTR;
1112                 ins->opcode += ovfops_op_map [src1->type];
1113                 break;
1114         case CEE_ADD_OVF:
1115         case CEE_ADD_OVF_UN:
1116         case CEE_MUL_OVF:
1117         case CEE_MUL_OVF_UN:
1118         case CEE_SUB_OVF:
1119         case CEE_SUB_OVF_UN:
1120                 ins->type = bin_num_table [src1->type] [src2->type];
1121                 ins->opcode += ovfops_op_map [src1->type];
1122                 if (ins->type == STACK_R8)
1123                         ins->type = STACK_INV;
1124                 break;
1125         case OP_LOAD_MEMBASE:
1126                 ins->type = STACK_PTR;
1127                 break;
1128         case OP_LOADI1_MEMBASE:
1129         case OP_LOADU1_MEMBASE:
1130         case OP_LOADI2_MEMBASE:
1131         case OP_LOADU2_MEMBASE:
1132         case OP_LOADI4_MEMBASE:
1133         case OP_LOADU4_MEMBASE:
1134                 ins->type = STACK_PTR;
1135                 break;
1136         case OP_LOADI8_MEMBASE:
1137                 ins->type = STACK_I8;
1138                 break;
1139         case OP_LOADR4_MEMBASE:
1140                 ins->type = cfg->r4_stack_type;
1141                 break;
1142         case OP_LOADR8_MEMBASE:
1143                 ins->type = STACK_R8;
1144                 break;
1145         default:
1146                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1147                 break;
1148         }
1149
1150         if (ins->type == STACK_MP)
1151                 ins->klass = mono_defaults.object_class;
1152 }
1153
1154 static const char 
1155 ldind_type [] = {
1156         STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
1157 };
1158
1159 #if 0
1160
1161 static const char
1162 param_table [STACK_MAX] [STACK_MAX] = {
1163         {0},
1164 };
1165
1166 static int
1167 check_values_to_signature (MonoInst *args, MonoType *this, MonoMethodSignature *sig) {
1168         int i;
1169
1170         if (sig->hasthis) {
1171                 switch (args->type) {
1172                 case STACK_I4:
1173                 case STACK_I8:
1174                 case STACK_R8:
1175                 case STACK_VTYPE:
1176                 case STACK_INV:
1177                         return 0;
1178                 }
1179                 args++;
1180         }
1181         for (i = 0; i < sig->param_count; ++i) {
1182                 switch (args [i].type) {
1183                 case STACK_INV:
1184                         return 0;
1185                 case STACK_MP:
1186                         if (!sig->params [i]->byref)
1187                                 return 0;
1188                         continue;
1189                 case STACK_OBJ:
1190                         if (sig->params [i]->byref)
1191                                 return 0;
1192                         switch (sig->params [i]->type) {
1193                         case MONO_TYPE_CLASS:
1194                         case MONO_TYPE_STRING:
1195                         case MONO_TYPE_OBJECT:
1196                         case MONO_TYPE_SZARRAY:
1197                         case MONO_TYPE_ARRAY:
1198                                 break;
1199                         default:
1200                                 return 0;
1201                         }
1202                         continue;
1203                 case STACK_R8:
1204                         if (sig->params [i]->byref)
1205                                 return 0;
1206                         if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1207                                 return 0;
1208                         continue;
1209                 case STACK_PTR:
1210                 case STACK_I4:
1211                 case STACK_I8:
1212                 case STACK_VTYPE:
1213                         break;
1214                 }
1215                 /*if (!param_table [args [i].type] [sig->params [i]->type])
1216                         return 0;*/
1217         }
1218         return 1;
1219 }
1220 #endif
1221
1222 /*
1223  * When we need a pointer to the current domain many times in a method, we
1224  * call mono_domain_get() once and we store the result in a local variable.
1225  * This function returns the variable that represents the MonoDomain*.
1226  */
1227 inline static MonoInst *
1228 mono_get_domainvar (MonoCompile *cfg)
1229 {
1230         if (!cfg->domainvar)
1231                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1232         return cfg->domainvar;
1233 }
1234
1235 /*
1236  * The got_var contains the address of the Global Offset Table when AOT 
1237  * compiling.
1238  */
1239 MonoInst *
1240 mono_get_got_var (MonoCompile *cfg)
1241 {
1242 #ifdef MONO_ARCH_NEED_GOT_VAR
1243         if (!cfg->compile_aot)
1244                 return NULL;
1245         if (!cfg->got_var) {
1246                 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1247         }
1248         return cfg->got_var;
1249 #else
1250         return NULL;
1251 #endif
1252 }
1253
1254 static MonoInst *
1255 mono_get_vtable_var (MonoCompile *cfg)
1256 {
1257         g_assert (cfg->generic_sharing_context);
1258
1259         if (!cfg->rgctx_var) {
1260                 cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1261                 /* force the var to be stack allocated */
1262                 cfg->rgctx_var->flags |= MONO_INST_VOLATILE;
1263         }
1264
1265         return cfg->rgctx_var;
1266 }
1267
1268 static MonoType*
1269 type_from_stack_type (MonoInst *ins) {
1270         switch (ins->type) {
1271         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1272         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1273         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1274         case STACK_R4: return &mono_defaults.single_class->byval_arg;
1275         case STACK_R8: return &mono_defaults.double_class->byval_arg;
1276         case STACK_MP:
1277                 return &ins->klass->this_arg;
1278         case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1279         case STACK_VTYPE: return &ins->klass->byval_arg;
1280         default:
1281                 g_error ("stack type %d to monotype not handled\n", ins->type);
1282         }
1283         return NULL;
1284 }
1285
1286 static G_GNUC_UNUSED int
1287 type_to_stack_type (MonoCompile *cfg, MonoType *t)
1288 {
1289         t = mono_type_get_underlying_type (t);
1290         switch (t->type) {
1291         case MONO_TYPE_I1:
1292         case MONO_TYPE_U1:
1293         case MONO_TYPE_BOOLEAN:
1294         case MONO_TYPE_I2:
1295         case MONO_TYPE_U2:
1296         case MONO_TYPE_CHAR:
1297         case MONO_TYPE_I4:
1298         case MONO_TYPE_U4:
1299                 return STACK_I4;
1300         case MONO_TYPE_I:
1301         case MONO_TYPE_U:
1302         case MONO_TYPE_PTR:
1303         case MONO_TYPE_FNPTR:
1304                 return STACK_PTR;
1305         case MONO_TYPE_CLASS:
1306         case MONO_TYPE_STRING:
1307         case MONO_TYPE_OBJECT:
1308         case MONO_TYPE_SZARRAY:
1309         case MONO_TYPE_ARRAY:    
1310                 return STACK_OBJ;
1311         case MONO_TYPE_I8:
1312         case MONO_TYPE_U8:
1313                 return STACK_I8;
1314         case MONO_TYPE_R4:
1315                 return cfg->r4_stack_type;
1316         case MONO_TYPE_R8:
1317                 return STACK_R8;
1318         case MONO_TYPE_VALUETYPE:
1319         case MONO_TYPE_TYPEDBYREF:
1320                 return STACK_VTYPE;
1321         case MONO_TYPE_GENERICINST:
1322                 if (mono_type_generic_inst_is_valuetype (t))
1323                         return STACK_VTYPE;
1324                 else
1325                         return STACK_OBJ;
1326                 break;
1327         default:
1328                 g_assert_not_reached ();
1329         }
1330
1331         return -1;
1332 }
1333
1334 static MonoClass*
1335 array_access_to_klass (int opcode)
1336 {
1337         switch (opcode) {
1338         case CEE_LDELEM_U1:
1339                 return mono_defaults.byte_class;
1340         case CEE_LDELEM_U2:
1341                 return mono_defaults.uint16_class;
1342         case CEE_LDELEM_I:
1343         case CEE_STELEM_I:
1344                 return mono_defaults.int_class;
1345         case CEE_LDELEM_I1:
1346         case CEE_STELEM_I1:
1347                 return mono_defaults.sbyte_class;
1348         case CEE_LDELEM_I2:
1349         case CEE_STELEM_I2:
1350                 return mono_defaults.int16_class;
1351         case CEE_LDELEM_I4:
1352         case CEE_STELEM_I4:
1353                 return mono_defaults.int32_class;
1354         case CEE_LDELEM_U4:
1355                 return mono_defaults.uint32_class;
1356         case CEE_LDELEM_I8:
1357         case CEE_STELEM_I8:
1358                 return mono_defaults.int64_class;
1359         case CEE_LDELEM_R4:
1360         case CEE_STELEM_R4:
1361                 return mono_defaults.single_class;
1362         case CEE_LDELEM_R8:
1363         case CEE_STELEM_R8:
1364                 return mono_defaults.double_class;
1365         case CEE_LDELEM_REF:
1366         case CEE_STELEM_REF:
1367                 return mono_defaults.object_class;
1368         default:
1369                 g_assert_not_reached ();
1370         }
1371         return NULL;
1372 }
1373
1374 /*
1375  * We try to share variables when possible
1376  */
1377 static MonoInst *
1378 mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
1379 {
1380         MonoInst *res;
1381         int pos, vnum;
1382
1383         /* inlining can result in deeper stacks */ 
1384         if (slot >= cfg->header->max_stack)
1385                 return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1386
1387         pos = ins->type - 1 + slot * STACK_MAX;
1388
1389         switch (ins->type) {
1390         case STACK_I4:
1391         case STACK_I8:
1392         case STACK_R8:
1393         case STACK_PTR:
1394         case STACK_MP:
1395         case STACK_OBJ:
1396                 if ((vnum = cfg->intvars [pos]))
1397                         return cfg->varinfo [vnum];
1398                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1399                 cfg->intvars [pos] = res->inst_c0;
1400                 break;
1401         default:
1402                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1403         }
1404         return res;
1405 }
1406
1407 static void
1408 mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
1409 {
1410         /* 
1411          * Don't use this if a generic_context is set, since that means AOT can't
1412          * look up the method using just the image+token.
1413          * table == 0 means this is a reference made from a wrapper.
1414          */
1415         if (cfg->compile_aot && !cfg->generic_context && (mono_metadata_token_table (token) > 0)) {
1416                 MonoJumpInfoToken *jump_info_token = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
1417                 jump_info_token->image = image;
1418                 jump_info_token->token = token;
1419                 g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
1420         }
1421 }
1422
1423 /*
1424  * This function is called to handle items that are left on the evaluation stack
1425  * at basic block boundaries. What happens is that we save the values to local variables
1426  * and we reload them later when first entering the target basic block (with the
1427  * handle_loaded_temps () function).
1428  * A single joint point will use the same variables (stored in the array bb->out_stack or
1429  * bb->in_stack, if the basic block is before or after the joint point).
1430  *
1431  * This function needs to be called _before_ emitting the last instruction of
1432  * the bb (i.e. before emitting a branch).
1433  * If the stack merge fails at a join point, cfg->unverifiable is set.
1434  */
1435 static void
1436 handle_stack_args (MonoCompile *cfg, MonoInst **sp, int count)
1437 {
1438         int i, bindex;
1439         MonoBasicBlock *bb = cfg->cbb;
1440         MonoBasicBlock *outb;
1441         MonoInst *inst, **locals;
1442         gboolean found;
1443
1444         if (!count)
1445                 return;
1446         if (cfg->verbose_level > 3)
1447                 printf ("%d item(s) on exit from B%d\n", count, bb->block_num);
1448         if (!bb->out_scount) {
1449                 bb->out_scount = count;
1450                 //printf ("bblock %d has out:", bb->block_num);
1451                 found = FALSE;
1452                 for (i = 0; i < bb->out_count; ++i) {
1453                         outb = bb->out_bb [i];
1454                         /* exception handlers are linked, but they should not be considered for stack args */
1455                         if (outb->flags & BB_EXCEPTION_HANDLER)
1456                                 continue;
1457                         //printf (" %d", outb->block_num);
1458                         if (outb->in_stack) {
1459                                 found = TRUE;
1460                                 bb->out_stack = outb->in_stack;
1461                                 break;
1462                         }
1463                 }
1464                 //printf ("\n");
1465                 if (!found) {
1466                         bb->out_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1467                         for (i = 0; i < count; ++i) {
1468                                 /* 
1469                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
1470                                  * stack slot and if they are of the same type.
1471                                  * This won't cause conflicts since if 'local' is used to 
1472                                  * store one of the values in the in_stack of a bblock, then
1473                                  * the same variable will be used for the same outgoing stack 
1474                                  * slot as well. 
1475                                  * This doesn't work when inlining methods, since the bblocks
1476                                  * in the inlined methods do not inherit their in_stack from
1477                                  * the bblock they are inlined to. See bug #58863 for an
1478                                  * example.
1479                                  */
1480                                 if (cfg->inlined_method)
1481                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1482                                 else
1483                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
1484                         }
1485                 }
1486         }
1487
1488         for (i = 0; i < bb->out_count; ++i) {
1489                 outb = bb->out_bb [i];
1490                 /* exception handlers are linked, but they should not be considered for stack args */
1491                 if (outb->flags & BB_EXCEPTION_HANDLER)
1492                         continue;
1493                 if (outb->in_scount) {
1494                         if (outb->in_scount != bb->out_scount) {
1495                                 cfg->unverifiable = TRUE;
1496                                 return;
1497                         }
1498                         continue; /* check they are the same locals */
1499                 }
1500                 outb->in_scount = count;
1501                 outb->in_stack = bb->out_stack;
1502         }
1503
1504         locals = bb->out_stack;
1505         cfg->cbb = bb;
1506         for (i = 0; i < count; ++i) {
1507                 EMIT_NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
1508                 inst->cil_code = sp [i]->cil_code;
1509                 sp [i] = locals [i];
1510                 if (cfg->verbose_level > 3)
1511                         printf ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
1512         }
1513
1514         /*
1515          * It is possible that the out bblocks already have in_stack assigned, and
1516          * the in_stacks differ. In this case, we will store to all the different 
1517          * in_stacks.
1518          */
1519
1520         found = TRUE;
1521         bindex = 0;
1522         while (found) {
1523                 /* Find a bblock which has a different in_stack */
1524                 found = FALSE;
1525                 while (bindex < bb->out_count) {
1526                         outb = bb->out_bb [bindex];
1527                         /* exception handlers are linked, but they should not be considered for stack args */
1528                         if (outb->flags & BB_EXCEPTION_HANDLER) {
1529                                 bindex++;
1530                                 continue;
1531                         }
1532                         if (outb->in_stack != locals) {
1533                                 for (i = 0; i < count; ++i) {
1534                                         EMIT_NEW_TEMPSTORE (cfg, inst, outb->in_stack [i]->inst_c0, sp [i]);
1535                                         inst->cil_code = sp [i]->cil_code;
1536                                         sp [i] = locals [i];
1537                                         if (cfg->verbose_level > 3)
1538                                                 printf ("storing %d to temp %d\n", i, (int)outb->in_stack [i]->inst_c0);
1539                                 }
1540                                 locals = outb->in_stack;
1541                                 found = TRUE;
1542                                 break;
1543                         }
1544                         bindex ++;
1545                 }
1546         }
1547 }
1548
1549 /* Emit code which loads interface_offsets [klass->interface_id]
1550  * The array is stored in memory before vtable.
1551 */
1552 static void
1553 mini_emit_load_intf_reg_vtable (MonoCompile *cfg, int intf_reg, int vtable_reg, MonoClass *klass)
1554 {
1555         if (cfg->compile_aot) {
1556                 int ioffset_reg = alloc_preg (cfg);
1557                 int iid_reg = alloc_preg (cfg);
1558
1559                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_ADJUSTED_IID);
1560                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ioffset_reg, iid_reg, vtable_reg);
1561                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, intf_reg, ioffset_reg, 0);
1562         }
1563         else {
1564                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, intf_reg, vtable_reg, -((klass->interface_id + 1) * SIZEOF_VOID_P));
1565         }
1566 }
1567
1568 static void
1569 mini_emit_interface_bitmap_check (MonoCompile *cfg, int intf_bit_reg, int base_reg, int offset, MonoClass *klass)
1570 {
1571         int ibitmap_reg = alloc_preg (cfg);
1572 #ifdef COMPRESSED_INTERFACE_BITMAP
1573         MonoInst *args [2];
1574         MonoInst *res, *ins;
1575         NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, ibitmap_reg, base_reg, offset);
1576         MONO_ADD_INS (cfg->cbb, ins);
1577         args [0] = ins;
1578         if (cfg->compile_aot)
1579                 EMIT_NEW_AOTCONST (cfg, args [1], MONO_PATCH_INFO_IID, klass);
1580         else
1581                 EMIT_NEW_ICONST (cfg, args [1], klass->interface_id);
1582         res = mono_emit_jit_icall (cfg, mono_class_interface_match, args);
1583         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, intf_bit_reg, res->dreg);
1584 #else
1585         int ibitmap_byte_reg = alloc_preg (cfg);
1586
1587         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, base_reg, offset);
1588
1589         if (cfg->compile_aot) {
1590                 int iid_reg = alloc_preg (cfg);
1591                 int shifted_iid_reg = alloc_preg (cfg);
1592                 int ibitmap_byte_address_reg = alloc_preg (cfg);
1593                 int masked_iid_reg = alloc_preg (cfg);
1594                 int iid_one_bit_reg = alloc_preg (cfg);
1595                 int iid_bit_reg = alloc_preg (cfg);
1596                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1597                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, shifted_iid_reg, iid_reg, 3);
1598                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ibitmap_byte_address_reg, ibitmap_reg, shifted_iid_reg);
1599                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, ibitmap_byte_reg, ibitmap_byte_address_reg, 0);
1600                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, masked_iid_reg, iid_reg, 7);
1601                 MONO_EMIT_NEW_ICONST (cfg, iid_one_bit_reg, 1);
1602                 MONO_EMIT_NEW_BIALU (cfg, OP_ISHL, iid_bit_reg, iid_one_bit_reg, masked_iid_reg);
1603                 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, intf_bit_reg, ibitmap_byte_reg, iid_bit_reg);
1604         } else {
1605                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, klass->interface_id >> 3);
1606                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (klass->interface_id & 7));
1607         }
1608 #endif
1609 }
1610
1611 /* 
1612  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoClass
1613  * stored in "klass_reg" implements the interface "klass".
1614  */
1615 static void
1616 mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass_reg, MonoClass *klass)
1617 {
1618         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, interface_bitmap), klass);
1619 }
1620
1621 /* 
1622  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoVTable
1623  * stored in "vtable_reg" implements the interface "klass".
1624  */
1625 static void
1626 mini_emit_load_intf_bit_reg_vtable (MonoCompile *cfg, int intf_bit_reg, int vtable_reg, MonoClass *klass)
1627 {
1628         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, interface_bitmap), klass);
1629 }
1630
1631 /* 
1632  * Emit code which checks whenever the interface id of @klass is smaller than
1633  * than the value given by max_iid_reg.
1634 */
1635 static void
1636 mini_emit_max_iid_check (MonoCompile *cfg, int max_iid_reg, MonoClass *klass,
1637                                                  MonoBasicBlock *false_target)
1638 {
1639         if (cfg->compile_aot) {
1640                 int iid_reg = alloc_preg (cfg);
1641                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1642                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, max_iid_reg, iid_reg);
1643         }
1644         else
1645                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, max_iid_reg, klass->interface_id);
1646         if (false_target)
1647                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1648         else
1649                 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1650 }
1651
1652 /* Same as above, but obtains max_iid from a vtable */
1653 static void
1654 mini_emit_max_iid_check_vtable (MonoCompile *cfg, int vtable_reg, MonoClass *klass,
1655                                                                  MonoBasicBlock *false_target)
1656 {
1657         int max_iid_reg = alloc_preg (cfg);
1658                 
1659         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, max_interface_id));
1660         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1661 }
1662
1663 /* Same as above, but obtains max_iid from a klass */
1664 static void
1665 mini_emit_max_iid_check_class (MonoCompile *cfg, int klass_reg, MonoClass *klass,
1666                                                                  MonoBasicBlock *false_target)
1667 {
1668         int max_iid_reg = alloc_preg (cfg);
1669
1670         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, max_interface_id));
1671         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1672 }
1673
1674 static void
1675 mini_emit_isninst_cast_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_ins, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1676 {
1677         int idepth_reg = alloc_preg (cfg);
1678         int stypes_reg = alloc_preg (cfg);
1679         int stype = alloc_preg (cfg);
1680
1681         mono_class_setup_supertypes (klass);
1682
1683         if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1684                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1685                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1686                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1687         }
1688         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1689         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1690         if (klass_ins) {
1691                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, klass_ins->dreg);
1692         } else if (cfg->compile_aot) {
1693                 int const_reg = alloc_preg (cfg);
1694                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1695                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, const_reg);
1696         } else {
1697                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, stype, klass);
1698         }
1699         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, true_target);
1700 }
1701
1702 static void
1703 mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1704 {
1705         mini_emit_isninst_cast_inst (cfg, klass_reg, klass, NULL, false_target, true_target);
1706 }
1707
1708 static void
1709 mini_emit_iface_cast (MonoCompile *cfg, int vtable_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1710 {
1711         int intf_reg = alloc_preg (cfg);
1712
1713         mini_emit_max_iid_check_vtable (cfg, vtable_reg, klass, false_target);
1714         mini_emit_load_intf_bit_reg_vtable (cfg, intf_reg, vtable_reg, klass);
1715         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_reg, 0);
1716         if (true_target)
1717                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1718         else
1719                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");               
1720 }
1721
1722 /*
1723  * Variant of the above that takes a register to the class, not the vtable.
1724  */
1725 static void
1726 mini_emit_iface_class_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1727 {
1728         int intf_bit_reg = alloc_preg (cfg);
1729
1730         mini_emit_max_iid_check_class (cfg, klass_reg, klass, false_target);
1731         mini_emit_load_intf_bit_reg_class (cfg, intf_bit_reg, klass_reg, klass);
1732         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_bit_reg, 0);
1733         if (true_target)
1734                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1735         else
1736                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
1737 }
1738
1739 static inline void
1740 mini_emit_class_check_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_inst)
1741 {
1742         if (klass_inst) {
1743                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_inst->dreg);
1744         } else if (cfg->compile_aot) {
1745                 int const_reg = alloc_preg (cfg);
1746                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1747                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1748         } else {
1749                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1750         }
1751         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1752 }
1753
1754 static inline void
1755 mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass)
1756 {
1757         mini_emit_class_check_inst (cfg, klass_reg, klass, NULL);
1758 }
1759
1760 static inline void
1761 mini_emit_class_check_branch (MonoCompile *cfg, int klass_reg, MonoClass *klass, int branch_op, MonoBasicBlock *target)
1762 {
1763         if (cfg->compile_aot) {
1764                 int const_reg = alloc_preg (cfg);
1765                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1766                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1767         } else {
1768                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1769         }
1770         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, branch_op, target);
1771 }
1772
1773 static void
1774 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null);
1775         
1776 static void
1777 mini_emit_castclass_inst (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoInst *klass_inst, MonoBasicBlock *object_is_null)
1778 {
1779         if (klass->rank) {
1780                 int rank_reg = alloc_preg (cfg);
1781                 int eclass_reg = alloc_preg (cfg);
1782
1783                 g_assert (!klass_inst);
1784                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, rank));
1785                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
1786                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1787                 //              MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
1788                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
1789                 if (klass->cast_class == mono_defaults.object_class) {
1790                         int parent_reg = alloc_preg (cfg);
1791                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
1792                         mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, object_is_null);
1793                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1794                 } else if (klass->cast_class == mono_defaults.enum_class->parent) {
1795                         mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, object_is_null);
1796                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1797                 } else if (klass->cast_class == mono_defaults.enum_class) {
1798                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1799                 } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1800                         mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, NULL, NULL);
1801                 } else {
1802                         // Pass -1 as obj_reg to skip the check below for arrays of arrays
1803                         mini_emit_castclass (cfg, -1, eclass_reg, klass->cast_class, object_is_null);
1804                 }
1805
1806                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY) && (obj_reg != -1)) {
1807                         /* Check that the object is a vector too */
1808                         int bounds_reg = alloc_preg (cfg);
1809                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
1810                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
1811                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1812                 }
1813         } else {
1814                 int idepth_reg = alloc_preg (cfg);
1815                 int stypes_reg = alloc_preg (cfg);
1816                 int stype = alloc_preg (cfg);
1817
1818                 mono_class_setup_supertypes (klass);
1819
1820                 if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1821                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1822                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1823                         MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1824                 }
1825                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1826                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1827                 mini_emit_class_check_inst (cfg, stype, klass, klass_inst);
1828         }
1829 }
1830
1831 static void
1832 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null)
1833 {
1834         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, NULL, object_is_null);
1835 }
1836
1837 static void 
1838 mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align)
1839 {
1840         int val_reg;
1841
1842         g_assert (val == 0);
1843
1844         if (align == 0)
1845                 align = 4;
1846
1847         if ((size <= SIZEOF_REGISTER) && (size <= align)) {
1848                 switch (size) {
1849                 case 1:
1850                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, destreg, offset, val);
1851                         return;
1852                 case 2:
1853                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI2_MEMBASE_IMM, destreg, offset, val);
1854                         return;
1855                 case 4:
1856                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI4_MEMBASE_IMM, destreg, offset, val);
1857                         return;
1858 #if SIZEOF_REGISTER == 8
1859                 case 8:
1860                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI8_MEMBASE_IMM, destreg, offset, val);
1861                         return;
1862 #endif
1863                 }
1864         }
1865
1866         val_reg = alloc_preg (cfg);
1867
1868         if (SIZEOF_REGISTER == 8)
1869                 MONO_EMIT_NEW_I8CONST (cfg, val_reg, val);
1870         else
1871                 MONO_EMIT_NEW_ICONST (cfg, val_reg, val);
1872
1873         if (align < 4) {
1874                 /* This could be optimized further if neccesary */
1875                 while (size >= 1) {
1876                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1877                         offset += 1;
1878                         size -= 1;
1879                 }
1880                 return;
1881         }       
1882
1883 #if !NO_UNALIGNED_ACCESS
1884         if (SIZEOF_REGISTER == 8) {
1885                 if (offset % 8) {
1886                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1887                         offset += 4;
1888                         size -= 4;
1889                 }
1890                 while (size >= 8) {
1891                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, offset, val_reg);
1892                         offset += 8;
1893                         size -= 8;
1894                 }
1895         }       
1896 #endif
1897
1898         while (size >= 4) {
1899                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1900                 offset += 4;
1901                 size -= 4;
1902         }
1903         while (size >= 2) {
1904                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, val_reg);
1905                 offset += 2;
1906                 size -= 2;
1907         }
1908         while (size >= 1) {
1909                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1910                 offset += 1;
1911                 size -= 1;
1912         }
1913 }
1914
1915 void 
1916 mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align)
1917 {
1918         int cur_reg;
1919
1920         if (align == 0)
1921                 align = 4;
1922
1923         /*FIXME arbitrary hack to avoid unbound code expansion.*/
1924         g_assert (size < 10000);
1925
1926         if (align < 4) {
1927                 /* This could be optimized further if neccesary */
1928                 while (size >= 1) {
1929                         cur_reg = alloc_preg (cfg);
1930                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1931                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1932                         doffset += 1;
1933                         soffset += 1;
1934                         size -= 1;
1935                 }
1936         }
1937
1938 #if !NO_UNALIGNED_ACCESS
1939         if (SIZEOF_REGISTER == 8) {
1940                 while (size >= 8) {
1941                         cur_reg = alloc_preg (cfg);
1942                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI8_MEMBASE, cur_reg, srcreg, soffset);
1943                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, doffset, cur_reg);
1944                         doffset += 8;
1945                         soffset += 8;
1946                         size -= 8;
1947                 }
1948         }       
1949 #endif
1950
1951         while (size >= 4) {
1952                 cur_reg = alloc_preg (cfg);
1953                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, cur_reg, srcreg, soffset);
1954                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, doffset, cur_reg);
1955                 doffset += 4;
1956                 soffset += 4;
1957                 size -= 4;
1958         }
1959         while (size >= 2) {
1960                 cur_reg = alloc_preg (cfg);
1961                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, cur_reg, srcreg, soffset);
1962                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, doffset, cur_reg);
1963                 doffset += 2;
1964                 soffset += 2;
1965                 size -= 2;
1966         }
1967         while (size >= 1) {
1968                 cur_reg = alloc_preg (cfg);
1969                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1970                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1971                 doffset += 1;
1972                 soffset += 1;
1973                 size -= 1;
1974         }
1975 }
1976
1977 static void
1978 emit_tls_set (MonoCompile *cfg, int sreg1, int tls_key)
1979 {
1980         MonoInst *ins, *c;
1981
1982         if (cfg->compile_aot) {
1983                 EMIT_NEW_TLS_OFFSETCONST (cfg, c, tls_key);
1984                 MONO_INST_NEW (cfg, ins, OP_TLS_SET_REG);
1985                 ins->sreg1 = sreg1;
1986                 ins->sreg2 = c->dreg;
1987                 MONO_ADD_INS (cfg->cbb, ins);
1988         } else {
1989                 MONO_INST_NEW (cfg, ins, OP_TLS_SET);
1990                 ins->sreg1 = sreg1;
1991                 ins->inst_offset = mini_get_tls_offset (tls_key);
1992                 MONO_ADD_INS (cfg->cbb, ins);
1993         }
1994 }
1995
1996 /*
1997  * emit_push_lmf:
1998  *
1999  *   Emit IR to push the current LMF onto the LMF stack.
2000  */
2001 static void
2002 emit_push_lmf (MonoCompile *cfg)
2003 {
2004         /*
2005          * Emit IR to push the LMF:
2006          * lmf_addr = <lmf_addr from tls>
2007          * lmf->lmf_addr = lmf_addr
2008          * lmf->prev_lmf = *lmf_addr
2009          * *lmf_addr = lmf
2010          */
2011         int lmf_reg, prev_lmf_reg;
2012         MonoInst *ins, *lmf_ins;
2013
2014         if (!cfg->lmf_ir)
2015                 return;
2016
2017         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
2018                 /* Load current lmf */
2019                 lmf_ins = mono_get_lmf_intrinsic (cfg);
2020                 g_assert (lmf_ins);
2021                 MONO_ADD_INS (cfg->cbb, lmf_ins);
2022                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2023                 lmf_reg = ins->dreg;
2024                 /* Save previous_lmf */
2025                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), lmf_ins->dreg);
2026                 /* Set new LMF */
2027                 emit_tls_set (cfg, lmf_reg, TLS_KEY_LMF);
2028         } else {
2029                 /*
2030                  * Store lmf_addr in a variable, so it can be allocated to a global register.
2031                  */
2032                 if (!cfg->lmf_addr_var)
2033                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2034
2035 #ifdef HOST_WIN32
2036                 ins = mono_get_jit_tls_intrinsic (cfg);
2037                 if (ins) {
2038                         int jit_tls_dreg = ins->dreg;
2039
2040                         MONO_ADD_INS (cfg->cbb, ins);
2041                         lmf_reg = alloc_preg (cfg);
2042                         EMIT_NEW_BIALU_IMM (cfg, lmf_ins, OP_PADD_IMM, lmf_reg, jit_tls_dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2043                 } else {
2044                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2045                 }
2046 #else
2047                 lmf_ins = mono_get_lmf_addr_intrinsic (cfg);
2048                 if (lmf_ins) {
2049                         MONO_ADD_INS (cfg->cbb, lmf_ins);
2050                 } else {
2051 #ifdef TARGET_IOS
2052                         MonoInst *args [16], *jit_tls_ins, *ins;
2053
2054                         /* Inline mono_get_lmf_addr () */
2055                         /* jit_tls = pthread_getspecific (mono_jit_tls_id); lmf_addr = &jit_tls->lmf; */
2056
2057                         /* Load mono_jit_tls_id */
2058                         EMIT_NEW_AOTCONST (cfg, args [0], MONO_PATCH_INFO_JIT_TLS_ID, NULL);
2059                         /* call pthread_getspecific () */
2060                         jit_tls_ins = mono_emit_jit_icall (cfg, pthread_getspecific, args);
2061                         /* lmf_addr = &jit_tls->lmf */
2062                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, cfg->lmf_addr_var->dreg, jit_tls_ins->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2063                         lmf_ins = ins;
2064 #else
2065                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2066 #endif
2067                 }
2068 #endif
2069                 lmf_ins->dreg = cfg->lmf_addr_var->dreg;
2070
2071                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2072                 lmf_reg = ins->dreg;
2073
2074                 prev_lmf_reg = alloc_preg (cfg);
2075                 /* Save previous_lmf */
2076                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, cfg->lmf_addr_var->dreg, 0);
2077                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), prev_lmf_reg);
2078                 /* Set new lmf */
2079                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, cfg->lmf_addr_var->dreg, 0, lmf_reg);
2080         }
2081 }
2082
2083 /*
2084  * emit_pop_lmf:
2085  *
2086  *   Emit IR to pop the current LMF from the LMF stack.
2087  */
2088 static void
2089 emit_pop_lmf (MonoCompile *cfg)
2090 {
2091         int lmf_reg, lmf_addr_reg, prev_lmf_reg;
2092         MonoInst *ins;
2093
2094         if (!cfg->lmf_ir)
2095                 return;
2096
2097         EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2098         lmf_reg = ins->dreg;
2099
2100         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
2101                 /* Load previous_lmf */
2102                 prev_lmf_reg = alloc_preg (cfg);
2103                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2104                 /* Set new LMF */
2105                 emit_tls_set (cfg, prev_lmf_reg, TLS_KEY_LMF);
2106         } else {
2107                 /*
2108                  * Emit IR to pop the LMF:
2109                  * *(lmf->lmf_addr) = lmf->prev_lmf
2110                  */
2111                 /* This could be called before emit_push_lmf () */
2112                 if (!cfg->lmf_addr_var)
2113                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2114                 lmf_addr_reg = cfg->lmf_addr_var->dreg;
2115
2116                 prev_lmf_reg = alloc_preg (cfg);
2117                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2118                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_addr_reg, 0, prev_lmf_reg);
2119         }
2120 }
2121
2122 static void
2123 emit_instrumentation_call (MonoCompile *cfg, void *func)
2124 {
2125         MonoInst *iargs [1];
2126
2127         /*
2128          * Avoid instrumenting inlined methods since it can
2129          * distort profiling results.
2130          */
2131         if (cfg->method != cfg->current_method)
2132                 return;
2133
2134         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
2135                 EMIT_NEW_METHODCONST (cfg, iargs [0], cfg->method);
2136                 mono_emit_jit_icall (cfg, func, iargs);
2137         }
2138 }
2139
2140 static int
2141 ret_type_to_call_opcode (MonoCompile *cfg, MonoType *type, int calli, int virt, MonoGenericSharingContext *gsctx)
2142 {
2143         if (type->byref)
2144                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2145
2146 handle_enum:
2147         type = mini_get_basic_type_from_generic (gsctx, type);
2148         type = mini_replace_type (type);
2149         switch (type->type) {
2150         case MONO_TYPE_VOID:
2151                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALL_MEMBASE: OP_VOIDCALL;
2152         case MONO_TYPE_I1:
2153         case MONO_TYPE_U1:
2154         case MONO_TYPE_BOOLEAN:
2155         case MONO_TYPE_I2:
2156         case MONO_TYPE_U2:
2157         case MONO_TYPE_CHAR:
2158         case MONO_TYPE_I4:
2159         case MONO_TYPE_U4:
2160                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2161         case MONO_TYPE_I:
2162         case MONO_TYPE_U:
2163         case MONO_TYPE_PTR:
2164         case MONO_TYPE_FNPTR:
2165                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2166         case MONO_TYPE_CLASS:
2167         case MONO_TYPE_STRING:
2168         case MONO_TYPE_OBJECT:
2169         case MONO_TYPE_SZARRAY:
2170         case MONO_TYPE_ARRAY:    
2171                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2172         case MONO_TYPE_I8:
2173         case MONO_TYPE_U8:
2174                 return calli? OP_LCALL_REG: virt? OP_LCALL_MEMBASE: OP_LCALL;
2175         case MONO_TYPE_R4:
2176                 if (cfg->r4fp)
2177                         return calli? OP_RCALL_REG: virt? OP_RCALL_MEMBASE: OP_RCALL;
2178                 else
2179                         return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2180         case MONO_TYPE_R8:
2181                 return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2182         case MONO_TYPE_VALUETYPE:
2183                 if (type->data.klass->enumtype) {
2184                         type = mono_class_enum_basetype (type->data.klass);
2185                         goto handle_enum;
2186                 } else
2187                         return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2188         case MONO_TYPE_TYPEDBYREF:
2189                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2190         case MONO_TYPE_GENERICINST:
2191                 type = &type->data.generic_class->container_class->byval_arg;
2192                 goto handle_enum;
2193         case MONO_TYPE_VAR:
2194         case MONO_TYPE_MVAR:
2195                 /* gsharedvt */
2196                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2197         default:
2198                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
2199         }
2200         return -1;
2201 }
2202
2203 /*
2204  * target_type_is_incompatible:
2205  * @cfg: MonoCompile context
2206  *
2207  * Check that the item @arg on the evaluation stack can be stored
2208  * in the target type (can be a local, or field, etc).
2209  * The cfg arg can be used to check if we need verification or just
2210  * validity checks.
2211  *
2212  * Returns: non-0 value if arg can't be stored on a target.
2213  */
2214 static int
2215 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
2216 {
2217         MonoType *simple_type;
2218         MonoClass *klass;
2219
2220         target = mini_replace_type (target);
2221         if (target->byref) {
2222                 /* FIXME: check that the pointed to types match */
2223                 if (arg->type == STACK_MP)
2224                         return arg->klass != mono_class_from_mono_type (target);
2225                 if (arg->type == STACK_PTR)
2226                         return 0;
2227                 return 1;
2228         }
2229
2230         simple_type = mono_type_get_underlying_type (target);
2231         switch (simple_type->type) {
2232         case MONO_TYPE_VOID:
2233                 return 1;
2234         case MONO_TYPE_I1:
2235         case MONO_TYPE_U1:
2236         case MONO_TYPE_BOOLEAN:
2237         case MONO_TYPE_I2:
2238         case MONO_TYPE_U2:
2239         case MONO_TYPE_CHAR:
2240         case MONO_TYPE_I4:
2241         case MONO_TYPE_U4:
2242                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2243                         return 1;
2244                 return 0;
2245         case MONO_TYPE_PTR:
2246                 /* STACK_MP is needed when setting pinned locals */
2247                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2248                         return 1;
2249                 return 0;
2250         case MONO_TYPE_I:
2251         case MONO_TYPE_U:
2252         case MONO_TYPE_FNPTR:
2253                 /* 
2254                  * Some opcodes like ldloca returns 'transient pointers' which can be stored in
2255                  * in native int. (#688008).
2256                  */
2257                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2258                         return 1;
2259                 return 0;
2260         case MONO_TYPE_CLASS:
2261         case MONO_TYPE_STRING:
2262         case MONO_TYPE_OBJECT:
2263         case MONO_TYPE_SZARRAY:
2264         case MONO_TYPE_ARRAY:    
2265                 if (arg->type != STACK_OBJ)
2266                         return 1;
2267                 /* FIXME: check type compatibility */
2268                 return 0;
2269         case MONO_TYPE_I8:
2270         case MONO_TYPE_U8:
2271                 if (arg->type != STACK_I8)
2272                         return 1;
2273                 return 0;
2274         case MONO_TYPE_R4:
2275                 if (arg->type != cfg->r4_stack_type)
2276                         return 1;
2277                 return 0;
2278         case MONO_TYPE_R8:
2279                 if (arg->type != STACK_R8)
2280                         return 1;
2281                 return 0;
2282         case MONO_TYPE_VALUETYPE:
2283                 if (arg->type != STACK_VTYPE)
2284                         return 1;
2285                 klass = mono_class_from_mono_type (simple_type);
2286                 if (klass != arg->klass)
2287                         return 1;
2288                 return 0;
2289         case MONO_TYPE_TYPEDBYREF:
2290                 if (arg->type != STACK_VTYPE)
2291                         return 1;
2292                 klass = mono_class_from_mono_type (simple_type);
2293                 if (klass != arg->klass)
2294                         return 1;
2295                 return 0;
2296         case MONO_TYPE_GENERICINST:
2297                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
2298                         if (arg->type != STACK_VTYPE)
2299                                 return 1;
2300                         klass = mono_class_from_mono_type (simple_type);
2301                         if (klass != arg->klass)
2302                                 return 1;
2303                         return 0;
2304                 } else {
2305                         if (arg->type != STACK_OBJ)
2306                                 return 1;
2307                         /* FIXME: check type compatibility */
2308                         return 0;
2309                 }
2310         case MONO_TYPE_VAR:
2311         case MONO_TYPE_MVAR:
2312                 g_assert (cfg->generic_sharing_context);
2313                 if (mini_type_var_is_vt (cfg, simple_type)) {
2314                         if (arg->type != STACK_VTYPE)
2315                                 return 1;
2316                 } else {
2317                         if (arg->type != STACK_OBJ)
2318                                 return 1;
2319                 }
2320                 return 0;
2321         default:
2322                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
2323         }
2324         return 1;
2325 }
2326
2327 /*
2328  * Prepare arguments for passing to a function call.
2329  * Return a non-zero value if the arguments can't be passed to the given
2330  * signature.
2331  * The type checks are not yet complete and some conversions may need
2332  * casts on 32 or 64 bit architectures.
2333  *
2334  * FIXME: implement this using target_type_is_incompatible ()
2335  */
2336 static int
2337 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2338 {
2339         MonoType *simple_type;
2340         int i;
2341
2342         if (sig->hasthis) {
2343                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2344                         return 1;
2345                 args++;
2346         }
2347         for (i = 0; i < sig->param_count; ++i) {
2348                 if (sig->params [i]->byref) {
2349                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2350                                 return 1;
2351                         continue;
2352                 }
2353                 simple_type = sig->params [i];
2354                 simple_type = mini_get_basic_type_from_generic (cfg->generic_sharing_context, simple_type);
2355 handle_enum:
2356                 switch (simple_type->type) {
2357                 case MONO_TYPE_VOID:
2358                         return 1;
2359                         continue;
2360                 case MONO_TYPE_I1:
2361                 case MONO_TYPE_U1:
2362                 case MONO_TYPE_BOOLEAN:
2363                 case MONO_TYPE_I2:
2364                 case MONO_TYPE_U2:
2365                 case MONO_TYPE_CHAR:
2366                 case MONO_TYPE_I4:
2367                 case MONO_TYPE_U4:
2368                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2369                                 return 1;
2370                         continue;
2371                 case MONO_TYPE_I:
2372                 case MONO_TYPE_U:
2373                 case MONO_TYPE_PTR:
2374                 case MONO_TYPE_FNPTR:
2375                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2376                                 return 1;
2377                         continue;
2378                 case MONO_TYPE_CLASS:
2379                 case MONO_TYPE_STRING:
2380                 case MONO_TYPE_OBJECT:
2381                 case MONO_TYPE_SZARRAY:
2382                 case MONO_TYPE_ARRAY:    
2383                         if (args [i]->type != STACK_OBJ)
2384                                 return 1;
2385                         continue;
2386                 case MONO_TYPE_I8:
2387                 case MONO_TYPE_U8:
2388                         if (args [i]->type != STACK_I8)
2389                                 return 1;
2390                         continue;
2391                 case MONO_TYPE_R4:
2392                         if (args [i]->type != cfg->r4_stack_type)
2393                                 return 1;
2394                         continue;
2395                 case MONO_TYPE_R8:
2396                         if (args [i]->type != STACK_R8)
2397                                 return 1;
2398                         continue;
2399                 case MONO_TYPE_VALUETYPE:
2400                         if (simple_type->data.klass->enumtype) {
2401                                 simple_type = mono_class_enum_basetype (simple_type->data.klass);
2402                                 goto handle_enum;
2403                         }
2404                         if (args [i]->type != STACK_VTYPE)
2405                                 return 1;
2406                         continue;
2407                 case MONO_TYPE_TYPEDBYREF:
2408                         if (args [i]->type != STACK_VTYPE)
2409                                 return 1;
2410                         continue;
2411                 case MONO_TYPE_GENERICINST:
2412                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2413                         goto handle_enum;
2414                 case MONO_TYPE_VAR:
2415                 case MONO_TYPE_MVAR:
2416                         /* gsharedvt */
2417                         if (args [i]->type != STACK_VTYPE)
2418                                 return 1;
2419                         continue;
2420                 default:
2421                         g_error ("unknown type 0x%02x in check_call_signature",
2422                                  simple_type->type);
2423                 }
2424         }
2425         return 0;
2426 }
2427
2428 static int
2429 callvirt_to_call (int opcode)
2430 {
2431         switch (opcode) {
2432         case OP_CALL_MEMBASE:
2433                 return OP_CALL;
2434         case OP_VOIDCALL_MEMBASE:
2435                 return OP_VOIDCALL;
2436         case OP_FCALL_MEMBASE:
2437                 return OP_FCALL;
2438         case OP_RCALL_MEMBASE:
2439                 return OP_RCALL;
2440         case OP_VCALL_MEMBASE:
2441                 return OP_VCALL;
2442         case OP_LCALL_MEMBASE:
2443                 return OP_LCALL;
2444         default:
2445                 g_assert_not_reached ();
2446         }
2447
2448         return -1;
2449 }
2450
2451 /* Either METHOD or IMT_ARG needs to be set */
2452 static void
2453 emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoMethod *method, MonoInst *imt_arg)
2454 {
2455         int method_reg;
2456
2457         if (COMPILE_LLVM (cfg)) {
2458                 method_reg = alloc_preg (cfg);
2459
2460                 if (imt_arg) {
2461                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2462                 } else if (cfg->compile_aot) {
2463                         MONO_EMIT_NEW_AOTCONST (cfg, method_reg, method, MONO_PATCH_INFO_METHODCONST);
2464                 } else {
2465                         MonoInst *ins;
2466                         MONO_INST_NEW (cfg, ins, OP_PCONST);
2467                         ins->inst_p0 = method;
2468                         ins->dreg = method_reg;
2469                         MONO_ADD_INS (cfg->cbb, ins);
2470                 }
2471
2472 #ifdef ENABLE_LLVM
2473                 call->imt_arg_reg = method_reg;
2474 #endif
2475 #ifdef MONO_ARCH_IMT_REG
2476         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2477 #else
2478         /* Need this to keep the IMT arg alive */
2479         mono_call_inst_add_outarg_reg (cfg, call, method_reg, 0, FALSE);
2480 #endif
2481                 return;
2482         }
2483
2484 #ifdef MONO_ARCH_IMT_REG
2485         method_reg = alloc_preg (cfg);
2486
2487         if (imt_arg) {
2488                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2489         } else if (cfg->compile_aot) {
2490                 MONO_EMIT_NEW_AOTCONST (cfg, method_reg, method, MONO_PATCH_INFO_METHODCONST);
2491         } else {
2492                 MonoInst *ins;
2493                 MONO_INST_NEW (cfg, ins, OP_PCONST);
2494                 ins->inst_p0 = method;
2495                 ins->dreg = method_reg;
2496                 MONO_ADD_INS (cfg->cbb, ins);
2497         }
2498
2499         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2500 #else
2501         mono_arch_emit_imt_argument (cfg, call, imt_arg);
2502 #endif
2503 }
2504
2505 static MonoJumpInfo *
2506 mono_patch_info_new (MonoMemPool *mp, int ip, MonoJumpInfoType type, gconstpointer target)
2507 {
2508         MonoJumpInfo *ji = mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
2509
2510         ji->ip.i = ip;
2511         ji->type = type;
2512         ji->data.target = target;
2513
2514         return ji;
2515 }
2516
2517 static int
2518 mini_class_check_context_used (MonoCompile *cfg, MonoClass *klass)
2519 {
2520         if (cfg->generic_sharing_context)
2521                 return mono_class_check_context_used (klass);
2522         else
2523                 return 0;
2524 }
2525
2526 static int
2527 mini_method_check_context_used (MonoCompile *cfg, MonoMethod *method)
2528 {
2529         if (cfg->generic_sharing_context)
2530                 return mono_method_check_context_used (method);
2531         else
2532                 return 0;
2533 }
2534
2535 /*
2536  * check_method_sharing:
2537  *
2538  *   Check whenever the vtable or an mrgctx needs to be passed when calling CMETHOD.
2539  */
2540 static void
2541 check_method_sharing (MonoCompile *cfg, MonoMethod *cmethod, gboolean *out_pass_vtable, gboolean *out_pass_mrgctx)
2542 {
2543         gboolean pass_vtable = FALSE;
2544         gboolean pass_mrgctx = FALSE;
2545
2546         if (((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
2547                 (cmethod->klass->generic_class || cmethod->klass->generic_container)) {
2548                 gboolean sharable = FALSE;
2549
2550                 if (mono_method_is_generic_sharable (cmethod, TRUE)) {
2551                         sharable = TRUE;
2552                 } else {
2553                         gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
2554                         MonoGenericContext *context = mini_class_get_context (cmethod->klass);
2555                         gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
2556
2557                         sharable = sharing_enabled && context_sharable;
2558                 }
2559
2560                 /*
2561                  * Pass vtable iff target method might
2562                  * be shared, which means that sharing
2563                  * is enabled for its class and its
2564                  * context is sharable (and it's not a
2565                  * generic method).
2566                  */
2567                 if (sharable && !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
2568                         pass_vtable = TRUE;
2569         }
2570
2571         if (mini_method_get_context (cmethod) &&
2572                 mini_method_get_context (cmethod)->method_inst) {
2573                 g_assert (!pass_vtable);
2574
2575                 if (mono_method_is_generic_sharable (cmethod, TRUE)) {
2576                         pass_mrgctx = TRUE;
2577                 } else {
2578                         gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
2579                         MonoGenericContext *context = mini_method_get_context (cmethod);
2580                         gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
2581
2582                         if (sharing_enabled && context_sharable)
2583                                 pass_mrgctx = TRUE;
2584                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, mono_method_signature (cmethod)))
2585                                 pass_mrgctx = TRUE;
2586                 }
2587         }
2588
2589         if (out_pass_vtable)
2590                 *out_pass_vtable = pass_vtable;
2591         if (out_pass_mrgctx)
2592                 *out_pass_mrgctx = pass_mrgctx;
2593 }
2594
2595 inline static MonoCallInst *
2596 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
2597                                          MonoInst **args, int calli, int virtual, int tail, int rgctx, int unbox_trampoline)
2598 {
2599         MonoType *sig_ret;
2600         MonoCallInst *call;
2601 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2602         int i;
2603 #endif
2604
2605         if (tail) {
2606                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
2607
2608                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
2609         } else
2610                 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (cfg, sig->ret, calli, virtual, cfg->generic_sharing_context));
2611
2612         call->args = args;
2613         call->signature = sig;
2614         call->rgctx_reg = rgctx;
2615         sig_ret = mini_replace_type (sig->ret);
2616
2617         type_to_eval_stack_type ((cfg), sig_ret, &call->inst);
2618
2619         if (tail) {
2620                 if (mini_type_is_vtype (cfg, sig_ret)) {
2621                         call->vret_var = cfg->vret_addr;
2622                         //g_assert_not_reached ();
2623                 }
2624         } else if (mini_type_is_vtype (cfg, sig_ret)) {
2625                 MonoInst *temp = mono_compile_create_var (cfg, sig_ret, OP_LOCAL);
2626                 MonoInst *loada;
2627
2628                 temp->backend.is_pinvoke = sig->pinvoke;
2629
2630                 /*
2631                  * We use a new opcode OP_OUTARG_VTRETADDR instead of LDADDR for emitting the
2632                  * address of return value to increase optimization opportunities.
2633                  * Before vtype decomposition, the dreg of the call ins itself represents the
2634                  * fact the call modifies the return value. After decomposition, the call will
2635                  * be transformed into one of the OP_VOIDCALL opcodes, and the VTRETADDR opcode
2636                  * will be transformed into an LDADDR.
2637                  */
2638                 MONO_INST_NEW (cfg, loada, OP_OUTARG_VTRETADDR);
2639                 loada->dreg = alloc_preg (cfg);
2640                 loada->inst_p0 = temp;
2641                 /* We reference the call too since call->dreg could change during optimization */
2642                 loada->inst_p1 = call;
2643                 MONO_ADD_INS (cfg->cbb, loada);
2644
2645                 call->inst.dreg = temp->dreg;
2646
2647                 call->vret_var = loada;
2648         } else if (!MONO_TYPE_IS_VOID (sig_ret))
2649                 call->inst.dreg = alloc_dreg (cfg, call->inst.type);
2650
2651 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2652         if (COMPILE_SOFT_FLOAT (cfg)) {
2653                 /* 
2654                  * If the call has a float argument, we would need to do an r8->r4 conversion using 
2655                  * an icall, but that cannot be done during the call sequence since it would clobber
2656                  * the call registers + the stack. So we do it before emitting the call.
2657                  */
2658                 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2659                         MonoType *t;
2660                         MonoInst *in = call->args [i];
2661
2662                         if (i >= sig->hasthis)
2663                                 t = sig->params [i - sig->hasthis];
2664                         else
2665                                 t = &mono_defaults.int_class->byval_arg;
2666                         t = mono_type_get_underlying_type (t);
2667
2668                         if (!t->byref && t->type == MONO_TYPE_R4) {
2669                                 MonoInst *iargs [1];
2670                                 MonoInst *conv;
2671
2672                                 iargs [0] = in;
2673                                 conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
2674
2675                                 /* The result will be in an int vreg */
2676                                 call->args [i] = conv;
2677                         }
2678                 }
2679         }
2680 #endif
2681
2682         call->need_unbox_trampoline = unbox_trampoline;
2683
2684 #ifdef ENABLE_LLVM
2685         if (COMPILE_LLVM (cfg))
2686                 mono_llvm_emit_call (cfg, call);
2687         else
2688                 mono_arch_emit_call (cfg, call);
2689 #else
2690         mono_arch_emit_call (cfg, call);
2691 #endif
2692
2693         cfg->param_area = MAX (cfg->param_area, call->stack_usage);
2694         cfg->flags |= MONO_CFG_HAS_CALLS;
2695         
2696         return call;
2697 }
2698
2699 static void
2700 set_rgctx_arg (MonoCompile *cfg, MonoCallInst *call, int rgctx_reg, MonoInst *rgctx_arg)
2701 {
2702 #ifdef MONO_ARCH_RGCTX_REG
2703         mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
2704         cfg->uses_rgctx_reg = TRUE;
2705         call->rgctx_reg = TRUE;
2706 #ifdef ENABLE_LLVM
2707         call->rgctx_arg_reg = rgctx_reg;
2708 #endif
2709 #else
2710         NOT_IMPLEMENTED;
2711 #endif
2712 }       
2713
2714 inline static MonoInst*
2715 mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg)
2716 {
2717         MonoCallInst *call;
2718         MonoInst *ins;
2719         int rgctx_reg = -1;
2720         gboolean check_sp = FALSE;
2721
2722         if (cfg->check_pinvoke_callconv && cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
2723                 WrapperInfo *info = mono_marshal_get_wrapper_info (cfg->method);
2724
2725                 if (info && info->subtype == WRAPPER_SUBTYPE_PINVOKE)
2726                         check_sp = TRUE;
2727         }
2728
2729         if (rgctx_arg) {
2730                 rgctx_reg = mono_alloc_preg (cfg);
2731                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2732         }
2733
2734         if (check_sp) {
2735                 if (!cfg->stack_inbalance_var)
2736                         cfg->stack_inbalance_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2737
2738                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2739                 ins->dreg = cfg->stack_inbalance_var->dreg;
2740                 MONO_ADD_INS (cfg->cbb, ins);
2741         }
2742
2743         call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE, FALSE);
2744
2745         call->inst.sreg1 = addr->dreg;
2746
2747         if (imt_arg)
2748                 emit_imt_argument (cfg, call, NULL, imt_arg);
2749
2750         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2751
2752         if (check_sp) {
2753                 int sp_reg;
2754
2755                 sp_reg = mono_alloc_preg (cfg);
2756
2757                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2758                 ins->dreg = sp_reg;
2759                 MONO_ADD_INS (cfg->cbb, ins);
2760
2761                 /* Restore the stack so we don't crash when throwing the exception */
2762                 MONO_INST_NEW (cfg, ins, OP_SET_SP);
2763                 ins->sreg1 = cfg->stack_inbalance_var->dreg;
2764                 MONO_ADD_INS (cfg->cbb, ins);
2765
2766                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, cfg->stack_inbalance_var->dreg, sp_reg);
2767                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ExecutionEngineException");
2768         }
2769
2770         if (rgctx_arg)
2771                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2772
2773         return (MonoInst*)call;
2774 }
2775
2776 static MonoInst*
2777 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2778
2779 static MonoInst*
2780 emit_get_rgctx_method (MonoCompile *cfg, int context_used, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type);
2781 static MonoInst*
2782 emit_get_rgctx_klass (MonoCompile *cfg, int context_used, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2783
2784 static MonoInst*
2785 mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig, gboolean tail,
2786                                                         MonoInst **args, MonoInst *this, MonoInst *imt_arg, MonoInst *rgctx_arg)
2787 {
2788 #ifndef DISABLE_REMOTING
2789         gboolean might_be_remote = FALSE;
2790 #endif
2791         gboolean virtual = this != NULL;
2792         gboolean enable_for_aot = TRUE;
2793         int context_used;
2794         MonoCallInst *call;
2795         int rgctx_reg = 0;
2796         gboolean need_unbox_trampoline;
2797
2798         if (!sig)
2799                 sig = mono_method_signature (method);
2800
2801         if (rgctx_arg) {
2802                 rgctx_reg = mono_alloc_preg (cfg);
2803                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2804         }
2805
2806         if (method->string_ctor) {
2807                 /* Create the real signature */
2808                 /* FIXME: Cache these */
2809                 MonoMethodSignature *ctor_sig = mono_metadata_signature_dup_mempool (cfg->mempool, sig);
2810                 ctor_sig->ret = &mono_defaults.string_class->byval_arg;
2811
2812                 sig = ctor_sig;
2813         }
2814
2815         context_used = mini_method_check_context_used (cfg, method);
2816
2817 #ifndef DISABLE_REMOTING
2818         might_be_remote = this && sig->hasthis &&
2819                 (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) &&
2820                 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && (!MONO_CHECK_THIS (this) || context_used);
2821
2822         if (might_be_remote && context_used) {
2823                 MonoInst *addr;
2824
2825                 g_assert (cfg->generic_sharing_context);
2826
2827                 addr = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK);
2828
2829                 return mono_emit_calli (cfg, sig, args, addr, NULL, NULL);
2830         }
2831 #endif
2832
2833         need_unbox_trampoline = method->klass == mono_defaults.object_class || (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
2834
2835         call = mono_emit_call_args (cfg, sig, args, FALSE, virtual, tail, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline);
2836
2837 #ifndef DISABLE_REMOTING
2838         if (might_be_remote)
2839                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2840         else
2841 #endif
2842                 call->method = method;
2843         call->inst.flags |= MONO_INST_HAS_METHOD;
2844         call->inst.inst_left = this;
2845         call->tail_call = tail;
2846
2847         if (virtual) {
2848                 int vtable_reg, slot_reg, this_reg;
2849                 int offset;
2850
2851                 this_reg = this->dreg;
2852
2853                 if (ARCH_HAVE_DELEGATE_TRAMPOLINES && (method->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (method->name, "Invoke")) {
2854                         MonoInst *dummy_use;
2855
2856                         MONO_EMIT_NULL_CHECK (cfg, this_reg);
2857
2858                         /* Make a call to delegate->invoke_impl */
2859                         call->inst.inst_basereg = this_reg;
2860                         call->inst.inst_offset = MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl);
2861                         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2862
2863                         /* We must emit a dummy use here because the delegate trampoline will
2864                         replace the 'this' argument with the delegate target making this activation
2865                         no longer a root for the delegate.
2866                         This is an issue for delegates that target collectible code such as dynamic
2867                         methods of GC'able assemblies.
2868
2869                         For a test case look into #667921.
2870
2871                         FIXME: a dummy use is not the best way to do it as the local register allocator
2872                         will put it on a caller save register and spil it around the call. 
2873                         Ideally, we would either put it on a callee save register or only do the store part.  
2874                          */
2875                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, args [0]);
2876
2877                         return (MonoInst*)call;
2878                 }
2879
2880                 if ((!cfg->compile_aot || enable_for_aot) && 
2881                         (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || 
2882                          (MONO_METHOD_IS_FINAL (method) &&
2883                           method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)) &&
2884                         !(mono_class_is_marshalbyref (method->klass) && context_used)) {
2885                         /* 
2886                          * the method is not virtual, we just need to ensure this is not null
2887                          * and then we can call the method directly.
2888                          */
2889 #ifndef DISABLE_REMOTING
2890                         if (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) {
2891                                 /* 
2892                                  * The check above ensures method is not gshared, this is needed since
2893                                  * gshared methods can't have wrappers.
2894                                  */
2895                                 method = call->method = mono_marshal_get_remoting_invoke_with_check (method);
2896                         }
2897 #endif
2898
2899                         if (!method->string_ctor)
2900                                 MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2901
2902                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2903                 } else if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && MONO_METHOD_IS_FINAL (method)) {
2904                         /*
2905                          * the method is virtual, but we can statically dispatch since either
2906                          * it's class or the method itself are sealed.
2907                          * But first we need to ensure it's not a null reference.
2908                          */
2909                         MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2910
2911                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2912                 } else {
2913                         vtable_reg = alloc_preg (cfg);
2914                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2915                         if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2916                                 slot_reg = -1;
2917                                 if (mono_use_imt) {
2918                                         guint32 imt_slot = mono_method_get_imt_slot (method);
2919                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2920                                         slot_reg = vtable_reg;
2921                                         offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
2922                                 }
2923                                 if (slot_reg == -1) {
2924                                         slot_reg = alloc_preg (cfg);
2925                                         mini_emit_load_intf_reg_vtable (cfg, slot_reg, vtable_reg, method->klass);
2926                                         offset = mono_method_get_vtable_index (method) * SIZEOF_VOID_P;
2927                                 }
2928                         } else {
2929                                 slot_reg = vtable_reg;
2930                                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) +
2931                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
2932                                 if (imt_arg) {
2933                                         g_assert (mono_method_signature (method)->generic_param_count);
2934                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2935                                 }
2936                         }
2937
2938                         call->inst.sreg1 = slot_reg;
2939                         call->inst.inst_offset = offset;
2940                         call->virtual = TRUE;
2941                 }
2942         }
2943
2944         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2945
2946         if (rgctx_arg)
2947                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2948
2949         return (MonoInst*)call;
2950 }
2951
2952 MonoInst*
2953 mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoInst **args, MonoInst *this)
2954 {
2955         return mono_emit_method_call_full (cfg, method, mono_method_signature (method), FALSE, args, this, NULL, NULL);
2956 }
2957
2958 MonoInst*
2959 mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig,
2960                                            MonoInst **args)
2961 {
2962         MonoCallInst *call;
2963
2964         g_assert (sig);
2965
2966         call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE, FALSE, FALSE);
2967         call->fptr = func;
2968
2969         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2970
2971         return (MonoInst*)call;
2972 }
2973
2974 MonoInst*
2975 mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args)
2976 {
2977         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2978
2979         g_assert (info);
2980
2981         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2982 }
2983
2984 /*
2985  * mono_emit_abs_call:
2986  *
2987  *   Emit a call to the runtime function described by PATCH_TYPE and DATA.
2988  */
2989 inline static MonoInst*
2990 mono_emit_abs_call (MonoCompile *cfg, MonoJumpInfoType patch_type, gconstpointer data, 
2991                                         MonoMethodSignature *sig, MonoInst **args)
2992 {
2993         MonoJumpInfo *ji = mono_patch_info_new (cfg->mempool, 0, patch_type, data);
2994         MonoInst *ins;
2995
2996         /* 
2997          * We pass ji as the call address, the PATCH_INFO_ABS resolving code will
2998          * handle it.
2999          */
3000         if (cfg->abs_patches == NULL)
3001                 cfg->abs_patches = g_hash_table_new (NULL, NULL);
3002         g_hash_table_insert (cfg->abs_patches, ji, ji);
3003         ins = mono_emit_native_call (cfg, ji, sig, args);
3004         ((MonoCallInst*)ins)->fptr_is_patch = TRUE;
3005         return ins;
3006 }
3007
3008 MonoInst*
3009 mono_emit_jit_icall_by_info (MonoCompile *cfg, MonoJitICallInfo *info, MonoInst **args, MonoBasicBlock **out_cbb)
3010 {
3011         gboolean no_wrapper = FALSE;
3012
3013         /*
3014          * Call the jit icall without a wrapper if possible.
3015          * The wrapper is needed for the following reasons:
3016          * - to handle exceptions thrown using mono_raise_exceptions () from the
3017          *   icall function. The EH code needs the lmf frame pushed by the
3018          *   wrapper to be able to unwind back to managed code.
3019          * - to be able to do stack walks for asynchronously suspended
3020          *   threads when debugging.
3021          */
3022         if (info->no_raise) {
3023                 if (cfg->compile_aot) {
3024                         // FIXME: This might be loaded into a runtime during debugging
3025                         // even if it is not compiled using 'soft-debug'.
3026                 } else {
3027                         no_wrapper = TRUE;
3028                         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
3029                         if ((cfg->compile_llvm && SIZEOF_VOID_P == 8) || cfg->gen_seq_points_debug_data)
3030                                 no_wrapper = FALSE;
3031                 }
3032         }
3033
3034         if (no_wrapper) {
3035                 char *name;
3036                 int costs;
3037
3038                 if (!info->wrapper_method) {
3039                         name = g_strdup_printf ("__icall_wrapper_%s", info->name);
3040                         info->wrapper_method = mono_marshal_get_icall_wrapper (info->sig, name, info->func, TRUE);
3041                         g_free (name);
3042                         mono_memory_barrier ();
3043                 }
3044
3045                 /*
3046                  * Inline the wrapper method, which is basically a call to the C icall, and
3047                  * an exception check.
3048                  */
3049                 costs = inline_method (cfg, info->wrapper_method, NULL,
3050                                                            args, NULL, cfg->real_offset, TRUE, out_cbb);
3051                 g_assert (costs > 0);
3052                 g_assert (!MONO_TYPE_IS_VOID (info->sig->ret));
3053
3054                 return args [0];
3055         } else {
3056                 return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
3057         }
3058 }
3059  
3060 static MonoInst*
3061 mono_emit_widen_call_res (MonoCompile *cfg, MonoInst *ins, MonoMethodSignature *fsig)
3062 {
3063         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
3064                 if ((fsig->pinvoke || LLVM_ENABLED) && !fsig->ret->byref) {
3065                         int widen_op = -1;
3066
3067                         /* 
3068                          * Native code might return non register sized integers 
3069                          * without initializing the upper bits.
3070                          */
3071                         switch (mono_type_to_load_membase (cfg, fsig->ret)) {
3072                         case OP_LOADI1_MEMBASE:
3073                                 widen_op = OP_ICONV_TO_I1;
3074                                 break;
3075                         case OP_LOADU1_MEMBASE:
3076                                 widen_op = OP_ICONV_TO_U1;
3077                                 break;
3078                         case OP_LOADI2_MEMBASE:
3079                                 widen_op = OP_ICONV_TO_I2;
3080                                 break;
3081                         case OP_LOADU2_MEMBASE:
3082                                 widen_op = OP_ICONV_TO_U2;
3083                                 break;
3084                         default:
3085                                 break;
3086                         }
3087
3088                         if (widen_op != -1) {
3089                                 int dreg = alloc_preg (cfg);
3090                                 MonoInst *widen;
3091
3092                                 EMIT_NEW_UNALU (cfg, widen, widen_op, dreg, ins->dreg);
3093                                 widen->type = ins->type;
3094                                 ins = widen;
3095                         }
3096                 }
3097         }
3098
3099         return ins;
3100 }
3101
3102 static MonoMethod*
3103 get_memcpy_method (void)
3104 {
3105         static MonoMethod *memcpy_method = NULL;
3106         if (!memcpy_method) {
3107                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
3108                 if (!memcpy_method)
3109                         g_error ("Old corlib found. Install a new one");
3110         }
3111         return memcpy_method;
3112 }
3113
3114 static void
3115 create_write_barrier_bitmap (MonoCompile *cfg, MonoClass *klass, unsigned *wb_bitmap, int offset)
3116 {
3117         MonoClassField *field;
3118         gpointer iter = NULL;
3119
3120         while ((field = mono_class_get_fields (klass, &iter))) {
3121                 int foffset;
3122
3123                 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3124                         continue;
3125                 foffset = klass->valuetype ? field->offset - sizeof (MonoObject): field->offset;
3126                 if (mini_type_is_reference (cfg, mono_field_get_type (field))) {
3127                         g_assert ((foffset % SIZEOF_VOID_P) == 0);
3128                         *wb_bitmap |= 1 << ((offset + foffset) / SIZEOF_VOID_P);
3129                 } else {
3130                         MonoClass *field_class = mono_class_from_mono_type (field->type);
3131                         if (field_class->has_references)
3132                                 create_write_barrier_bitmap (cfg, field_class, wb_bitmap, offset + foffset);
3133                 }
3134         }
3135 }
3136
3137 static void
3138 emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value)
3139 {
3140         int card_table_shift_bits;
3141         gpointer card_table_mask;
3142         guint8 *card_table;
3143         MonoInst *dummy_use;
3144         int nursery_shift_bits;
3145         size_t nursery_size;
3146         gboolean has_card_table_wb = FALSE;
3147
3148         if (!cfg->gen_write_barriers)
3149                 return;
3150
3151         card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
3152
3153         mono_gc_get_nursery (&nursery_shift_bits, &nursery_size);
3154
3155 #ifdef MONO_ARCH_HAVE_CARD_TABLE_WBARRIER
3156         has_card_table_wb = TRUE;
3157 #endif
3158
3159         if (has_card_table_wb && !cfg->compile_aot && card_table && nursery_shift_bits > 0 && !COMPILE_LLVM (cfg)) {
3160                 MonoInst *wbarrier;
3161
3162                 MONO_INST_NEW (cfg, wbarrier, OP_CARD_TABLE_WBARRIER);
3163                 wbarrier->sreg1 = ptr->dreg;
3164                 wbarrier->sreg2 = value->dreg;
3165                 MONO_ADD_INS (cfg->cbb, wbarrier);
3166         } else if (card_table) {
3167                 int offset_reg = alloc_preg (cfg);
3168                 int card_reg  = alloc_preg (cfg);
3169                 MonoInst *ins;
3170
3171                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, offset_reg, ptr->dreg, card_table_shift_bits);
3172                 if (card_table_mask)
3173                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, offset_reg, offset_reg, card_table_mask);
3174
3175                 /*We can't use PADD_IMM since the cardtable might end up in high addresses and amd64 doesn't support
3176                  * IMM's larger than 32bits.
3177                  */
3178                 if (cfg->compile_aot) {
3179                         MONO_EMIT_NEW_AOTCONST (cfg, card_reg, NULL, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR);
3180                 } else {
3181                         MONO_INST_NEW (cfg, ins, OP_PCONST);
3182                         ins->inst_p0 = card_table;
3183                         ins->dreg = card_reg;
3184                         MONO_ADD_INS (cfg->cbb, ins);
3185                 }
3186
3187                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, offset_reg, offset_reg, card_reg);
3188                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, offset_reg, 0, 1);
3189         } else {
3190                 MonoMethod *write_barrier = mono_gc_get_write_barrier ();
3191                 mono_emit_method_call (cfg, write_barrier, &ptr, NULL);
3192         }
3193
3194         EMIT_NEW_DUMMY_USE (cfg, dummy_use, value);
3195 }
3196
3197 static gboolean
3198 mono_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align)
3199 {
3200         int dest_ptr_reg, tmp_reg, destreg, srcreg, offset;
3201         unsigned need_wb = 0;
3202
3203         if (align == 0)
3204                 align = 4;
3205
3206         /*types with references can't have alignment smaller than sizeof(void*) */
3207         if (align < SIZEOF_VOID_P)
3208                 return FALSE;
3209
3210         /*This value cannot be bigger than 32 due to the way we calculate the required wb bitmap.*/
3211         if (size > 32 * SIZEOF_VOID_P)
3212                 return FALSE;
3213
3214         create_write_barrier_bitmap (cfg, klass, &need_wb, 0);
3215
3216         /* We don't unroll more than 5 stores to avoid code bloat. */
3217         if (size > 5 * SIZEOF_VOID_P) {
3218                 /*This is harmless and simplify mono_gc_wbarrier_value_copy_bitmap */
3219                 size += (SIZEOF_VOID_P - 1);
3220                 size &= ~(SIZEOF_VOID_P - 1);
3221
3222                 EMIT_NEW_ICONST (cfg, iargs [2], size);
3223                 EMIT_NEW_ICONST (cfg, iargs [3], need_wb);
3224                 mono_emit_jit_icall (cfg, mono_gc_wbarrier_value_copy_bitmap, iargs);
3225                 return TRUE;
3226         }
3227
3228         destreg = iargs [0]->dreg;
3229         srcreg = iargs [1]->dreg;
3230         offset = 0;
3231
3232         dest_ptr_reg = alloc_preg (cfg);
3233         tmp_reg = alloc_preg (cfg);
3234
3235         /*tmp = dreg*/
3236         EMIT_NEW_UNALU (cfg, iargs [0], OP_MOVE, dest_ptr_reg, destreg);
3237
3238         while (size >= SIZEOF_VOID_P) {
3239                 MonoInst *load_inst;
3240                 MONO_INST_NEW (cfg, load_inst, OP_LOAD_MEMBASE);
3241                 load_inst->dreg = tmp_reg;
3242                 load_inst->inst_basereg = srcreg;
3243                 load_inst->inst_offset = offset;
3244                 MONO_ADD_INS (cfg->cbb, load_inst);
3245
3246                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, dest_ptr_reg, 0, tmp_reg);
3247
3248                 if (need_wb & 0x1)
3249                         emit_write_barrier (cfg, iargs [0], load_inst);
3250
3251                 offset += SIZEOF_VOID_P;
3252                 size -= SIZEOF_VOID_P;
3253                 need_wb >>= 1;
3254
3255                 /*tmp += sizeof (void*)*/
3256                 if (size >= SIZEOF_VOID_P) {
3257                         NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dest_ptr_reg, dest_ptr_reg, SIZEOF_VOID_P);
3258                         MONO_ADD_INS (cfg->cbb, iargs [0]);
3259                 }
3260         }
3261
3262         /* Those cannot be references since size < sizeof (void*) */
3263         while (size >= 4) {
3264                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tmp_reg, srcreg, offset);
3265                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, tmp_reg);
3266                 offset += 4;
3267                 size -= 4;
3268         }
3269
3270         while (size >= 2) {
3271                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmp_reg, srcreg, offset);
3272                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, tmp_reg);
3273                 offset += 2;
3274                 size -= 2;
3275         }
3276
3277         while (size >= 1) {
3278                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmp_reg, srcreg, offset);
3279                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, tmp_reg);
3280                 offset += 1;
3281                 size -= 1;
3282         }
3283
3284         return TRUE;
3285 }
3286
3287 /*
3288  * Emit code to copy a valuetype of type @klass whose address is stored in
3289  * @src->dreg to memory whose address is stored at @dest->dreg.
3290  */
3291 void
3292 mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native)
3293 {
3294         MonoInst *iargs [4];
3295         int context_used, n;
3296         guint32 align = 0;
3297         MonoMethod *memcpy_method;
3298         MonoInst *size_ins = NULL;
3299         MonoInst *memcpy_ins = NULL;
3300
3301         g_assert (klass);
3302         /*
3303          * This check breaks with spilled vars... need to handle it during verification anyway.
3304          * g_assert (klass && klass == src->klass && klass == dest->klass);
3305          */
3306
3307         if (mini_is_gsharedvt_klass (cfg, klass)) {
3308                 g_assert (!native);
3309                 context_used = mini_class_check_context_used (cfg, klass);
3310                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3311                 memcpy_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_MEMCPY);
3312         }
3313
3314         if (native)
3315                 n = mono_class_native_size (klass, &align);
3316         else
3317                 n = mono_class_value_size (klass, &align);
3318
3319         /* if native is true there should be no references in the struct */
3320         if (cfg->gen_write_barriers && (klass->has_references || size_ins) && !native) {
3321                 /* Avoid barriers when storing to the stack */
3322                 if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) ||
3323                           (dest->opcode == OP_LDADDR))) {
3324                         int context_used;
3325
3326                         iargs [0] = dest;
3327                         iargs [1] = src;
3328
3329                         context_used = mini_class_check_context_used (cfg, klass);
3330
3331                         /* It's ok to intrinsify under gsharing since shared code types are layout stable. */
3332                         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && mono_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
3333                                 return;
3334                         } else if (context_used) {
3335                                 iargs [2] = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3336                         }  else {
3337                                 if (cfg->compile_aot) {
3338                                         EMIT_NEW_CLASSCONST (cfg, iargs [2], klass);
3339                                 } else {
3340                                         EMIT_NEW_PCONST (cfg, iargs [2], klass);
3341                                         mono_class_compute_gc_descriptor (klass);
3342                                 }
3343                         }
3344
3345                         if (size_ins)
3346                                 mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs);
3347                         else
3348                                 mono_emit_jit_icall (cfg, mono_value_copy, iargs);
3349                         return;
3350                 }
3351         }
3352
3353         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 8) {
3354                 /* FIXME: Optimize the case when src/dest is OP_LDADDR */
3355                 mini_emit_memcpy (cfg, dest->dreg, 0, src->dreg, 0, n, align);
3356         } else {
3357                 iargs [0] = dest;
3358                 iargs [1] = src;
3359                 if (size_ins)
3360                         iargs [2] = size_ins;
3361                 else
3362                         EMIT_NEW_ICONST (cfg, iargs [2], n);
3363                 
3364                 memcpy_method = get_memcpy_method ();
3365                 if (memcpy_ins)
3366                         mono_emit_calli (cfg, mono_method_signature (memcpy_method), iargs, memcpy_ins, NULL, NULL);
3367                 else
3368                         mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
3369         }
3370 }
3371
3372 static MonoMethod*
3373 get_memset_method (void)
3374 {
3375         static MonoMethod *memset_method = NULL;
3376         if (!memset_method) {
3377                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
3378                 if (!memset_method)
3379                         g_error ("Old corlib found. Install a new one");
3380         }
3381         return memset_method;
3382 }
3383
3384 void
3385 mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass)
3386 {
3387         MonoInst *iargs [3];
3388         int n, context_used;
3389         guint32 align;
3390         MonoMethod *memset_method;
3391         MonoInst *size_ins = NULL;
3392         MonoInst *bzero_ins = NULL;
3393         static MonoMethod *bzero_method;
3394
3395         /* FIXME: Optimize this for the case when dest is an LDADDR */
3396
3397         mono_class_init (klass);
3398         if (mini_is_gsharedvt_klass (cfg, klass)) {
3399                 context_used = mini_class_check_context_used (cfg, klass);
3400                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3401                 bzero_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_BZERO);
3402                 if (!bzero_method)
3403                         bzero_method = mono_class_get_method_from_name (mono_defaults.string_class, "bzero_aligned_1", 2);
3404                 g_assert (bzero_method);
3405                 iargs [0] = dest;
3406                 iargs [1] = size_ins;
3407                 mono_emit_calli (cfg, mono_method_signature (bzero_method), iargs, bzero_ins, NULL, NULL);
3408                 return;
3409         }
3410
3411         n = mono_class_value_size (klass, &align);
3412
3413         if (n <= sizeof (gpointer) * 8) {
3414                 mini_emit_memset (cfg, dest->dreg, 0, n, 0, align);
3415         }
3416         else {
3417                 memset_method = get_memset_method ();
3418                 iargs [0] = dest;
3419                 EMIT_NEW_ICONST (cfg, iargs [1], 0);
3420                 EMIT_NEW_ICONST (cfg, iargs [2], n);
3421                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
3422         }
3423 }
3424
3425 static MonoInst*
3426 emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used)
3427 {
3428         MonoInst *this = NULL;
3429
3430         g_assert (cfg->generic_sharing_context);
3431
3432         if (!(method->flags & METHOD_ATTRIBUTE_STATIC) &&
3433                         !(context_used & MONO_GENERIC_CONTEXT_USED_METHOD) &&
3434                         !method->klass->valuetype)
3435                 EMIT_NEW_ARGLOAD (cfg, this, 0);
3436
3437         if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
3438                 MonoInst *mrgctx_loc, *mrgctx_var;
3439
3440                 g_assert (!this);
3441                 g_assert (method->is_inflated && mono_method_get_context (method)->method_inst);
3442
3443                 mrgctx_loc = mono_get_vtable_var (cfg);
3444                 EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
3445
3446                 return mrgctx_var;
3447         } else if (method->flags & METHOD_ATTRIBUTE_STATIC || method->klass->valuetype) {
3448                 MonoInst *vtable_loc, *vtable_var;
3449
3450                 g_assert (!this);
3451
3452                 vtable_loc = mono_get_vtable_var (cfg);
3453                 EMIT_NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
3454
3455                 if (method->is_inflated && mono_method_get_context (method)->method_inst) {
3456                         MonoInst *mrgctx_var = vtable_var;
3457                         int vtable_reg;
3458
3459                         vtable_reg = alloc_preg (cfg);
3460                         EMIT_NEW_LOAD_MEMBASE (cfg, vtable_var, OP_LOAD_MEMBASE, vtable_reg, mrgctx_var->dreg, MONO_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, class_vtable));
3461                         vtable_var->type = STACK_PTR;
3462                 }
3463
3464                 return vtable_var;
3465         } else {
3466                 MonoInst *ins;
3467                 int vtable_reg;
3468         
3469                 vtable_reg = alloc_preg (cfg);
3470                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, vtable_reg, this->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3471                 return ins;
3472         }
3473 }
3474
3475 static MonoJumpInfoRgctxEntry *
3476 mono_patch_info_rgctx_entry_new (MonoMemPool *mp, MonoMethod *method, gboolean in_mrgctx, MonoJumpInfoType patch_type, gconstpointer patch_data, MonoRgctxInfoType info_type)
3477 {
3478         MonoJumpInfoRgctxEntry *res = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoRgctxEntry));
3479         res->method = method;
3480         res->in_mrgctx = in_mrgctx;
3481         res->data = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
3482         res->data->type = patch_type;
3483         res->data->data.target = patch_data;
3484         res->info_type = info_type;
3485
3486         return res;
3487 }
3488
3489 static inline MonoInst*
3490 emit_rgctx_fetch (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3491 {
3492         return mono_emit_abs_call (cfg, MONO_PATCH_INFO_RGCTX_FETCH, entry, helper_sig_rgctx_lazy_fetch_trampoline, &rgctx);
3493 }
3494
3495 static MonoInst*
3496 emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
3497                                           MonoClass *klass, MonoRgctxInfoType rgctx_type)
3498 {
3499         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);
3500         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3501
3502         return emit_rgctx_fetch (cfg, rgctx, entry);
3503 }
3504
3505 static MonoInst*
3506 emit_get_rgctx_sig (MonoCompile *cfg, int context_used,
3507                                         MonoMethodSignature *sig, MonoRgctxInfoType rgctx_type)
3508 {
3509         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);
3510         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3511
3512         return emit_rgctx_fetch (cfg, rgctx, entry);
3513 }
3514
3515 static MonoInst*
3516 emit_get_rgctx_gsharedvt_call (MonoCompile *cfg, int context_used,
3517                                                            MonoMethodSignature *sig, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3518 {
3519         MonoJumpInfoGSharedVtCall *call_info;
3520         MonoJumpInfoRgctxEntry *entry;
3521         MonoInst *rgctx;
3522
3523         call_info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoGSharedVtCall));
3524         call_info->sig = sig;
3525         call_info->method = cmethod;
3526
3527         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);
3528         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3529
3530         return emit_rgctx_fetch (cfg, rgctx, entry);
3531 }
3532
3533
3534 static MonoInst*
3535 emit_get_rgctx_gsharedvt_method (MonoCompile *cfg, int context_used,
3536                                                                  MonoMethod *cmethod, MonoGSharedVtMethodInfo *info)
3537 {
3538         MonoJumpInfoRgctxEntry *entry;
3539         MonoInst *rgctx;
3540
3541         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);
3542         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3543
3544         return emit_rgctx_fetch (cfg, rgctx, entry);
3545 }
3546
3547 /*
3548  * emit_get_rgctx_method:
3549  *
3550  *   Emit IR to load the property RGCTX_TYPE of CMETHOD. If context_used is 0, emit
3551  * normal constants, else emit a load from the rgctx.
3552  */
3553 static MonoInst*
3554 emit_get_rgctx_method (MonoCompile *cfg, int context_used,
3555                                            MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3556 {
3557         if (!context_used) {
3558                 MonoInst *ins;
3559
3560                 switch (rgctx_type) {
3561                 case MONO_RGCTX_INFO_METHOD:
3562                         EMIT_NEW_METHODCONST (cfg, ins, cmethod);
3563                         return ins;
3564                 case MONO_RGCTX_INFO_METHOD_RGCTX:
3565                         EMIT_NEW_METHOD_RGCTX_CONST (cfg, ins, cmethod);
3566                         return ins;
3567                 default:
3568                         g_assert_not_reached ();
3569                 }
3570         } else {
3571                 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);
3572                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3573
3574                 return emit_rgctx_fetch (cfg, rgctx, entry);
3575         }
3576 }
3577
3578 static MonoInst*
3579 emit_get_rgctx_field (MonoCompile *cfg, int context_used,
3580                                           MonoClassField *field, MonoRgctxInfoType rgctx_type)
3581 {
3582         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);
3583         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3584
3585         return emit_rgctx_fetch (cfg, rgctx, entry);
3586 }
3587
3588 static int
3589 get_gsharedvt_info_slot (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3590 {
3591         MonoGSharedVtMethodInfo *info = cfg->gsharedvt_info;
3592         MonoRuntimeGenericContextInfoTemplate *template;
3593         int i, idx;
3594
3595         g_assert (info);
3596
3597         for (i = 0; i < info->num_entries; ++i) {
3598                 MonoRuntimeGenericContextInfoTemplate *otemplate = &info->entries [i];
3599
3600                 if (otemplate->info_type == rgctx_type && otemplate->data == data && rgctx_type != MONO_RGCTX_INFO_LOCAL_OFFSET)
3601                         return i;
3602         }
3603
3604         if (info->num_entries == info->count_entries) {
3605                 MonoRuntimeGenericContextInfoTemplate *new_entries;
3606                 int new_count_entries = info->count_entries ? info->count_entries * 2 : 16;
3607
3608                 new_entries = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * new_count_entries);
3609
3610                 memcpy (new_entries, info->entries, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
3611                 info->entries = new_entries;
3612                 info->count_entries = new_count_entries;
3613         }
3614
3615         idx = info->num_entries;
3616         template = &info->entries [idx];
3617         template->info_type = rgctx_type;
3618         template->data = data;
3619
3620         info->num_entries ++;
3621
3622         return idx;
3623 }
3624
3625 /*
3626  * emit_get_gsharedvt_info:
3627  *
3628  *   This is similar to emit_get_rgctx_.., but loads the data from the gsharedvt info var instead of calling an rgctx fetch trampoline.
3629  */
3630 static MonoInst*
3631 emit_get_gsharedvt_info (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3632 {
3633         MonoInst *ins;
3634         int idx, dreg;
3635
3636         idx = get_gsharedvt_info_slot (cfg, data, rgctx_type);
3637         /* Load info->entries [idx] */
3638         dreg = alloc_preg (cfg);
3639         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, cfg->gsharedvt_info_var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
3640
3641         return ins;
3642 }
3643
3644 static MonoInst*
3645 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type)
3646 {
3647         return emit_get_gsharedvt_info (cfg, &klass->byval_arg, rgctx_type);
3648 }
3649
3650 /*
3651  * On return the caller must check @klass for load errors.
3652  */
3653 static void
3654 emit_generic_class_init (MonoCompile *cfg, MonoClass *klass)
3655 {
3656         MonoInst *vtable_arg;
3657         MonoCallInst *call;
3658         int context_used;
3659
3660         context_used = mini_class_check_context_used (cfg, klass);
3661
3662         if (context_used) {
3663                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
3664                                                                                    klass, MONO_RGCTX_INFO_VTABLE);
3665         } else {
3666                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3667
3668                 if (!vtable)
3669                         return;
3670                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
3671         }
3672
3673         if (COMPILE_LLVM (cfg))
3674                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_GENERIC_CLASS_INIT, NULL, helper_sig_generic_class_init_trampoline_llvm, &vtable_arg);
3675         else
3676                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_GENERIC_CLASS_INIT, NULL, helper_sig_generic_class_init_trampoline, &vtable_arg);
3677 #ifdef MONO_ARCH_VTABLE_REG
3678         mono_call_inst_add_outarg_reg (cfg, call, vtable_arg->dreg, MONO_ARCH_VTABLE_REG, FALSE);
3679         cfg->uses_vtable_reg = TRUE;
3680 #else
3681         NOT_IMPLEMENTED;
3682 #endif
3683 }
3684
3685 static void
3686 emit_seq_point (MonoCompile *cfg, MonoMethod *method, guint8* ip, gboolean intr_loc, gboolean nonempty_stack)
3687 {
3688         MonoInst *ins;
3689
3690         if (cfg->gen_seq_points && cfg->method == method) {
3691                 NEW_SEQ_POINT (cfg, ins, ip - cfg->header->code, intr_loc);
3692                 if (nonempty_stack)
3693                         ins->flags |= MONO_INST_NONEMPTY_STACK;
3694                 MONO_ADD_INS (cfg->cbb, ins);
3695         }
3696 }
3697
3698 static void
3699 save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean null_check, MonoBasicBlock **out_bblock)
3700 {
3701         if (mini_get_debug_options ()->better_cast_details) {
3702                 int vtable_reg = alloc_preg (cfg);
3703                 int klass_reg = alloc_preg (cfg);
3704                 MonoBasicBlock *is_null_bb = NULL;
3705                 MonoInst *tls_get;
3706                 int to_klass_reg, context_used;
3707
3708                 if (null_check) {
3709                         NEW_BBLOCK (cfg, is_null_bb);
3710
3711                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3712                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3713                 }
3714
3715                 tls_get = mono_get_jit_tls_intrinsic (cfg);
3716                 if (!tls_get) {
3717                         fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
3718                         exit (1);
3719                 }
3720
3721                 MONO_ADD_INS (cfg->cbb, tls_get);
3722                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3723                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3724
3725                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg);
3726
3727                 context_used = mini_class_check_context_used (cfg, klass);
3728                 if (context_used) {
3729                         MonoInst *class_ins;
3730
3731                         class_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3732                         to_klass_reg = class_ins->dreg;
3733                 } else {
3734                         to_klass_reg = alloc_preg (cfg);
3735                         MONO_EMIT_NEW_CLASSCONST (cfg, to_klass_reg, klass);
3736                 }
3737                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg);
3738
3739                 if (null_check) {
3740                         MONO_START_BB (cfg, is_null_bb);
3741                         if (out_bblock)
3742                                 *out_bblock = cfg->cbb;
3743                 }
3744         }
3745 }
3746
3747 static void
3748 reset_cast_details (MonoCompile *cfg)
3749 {
3750         /* Reset the variables holding the cast details */
3751         if (mini_get_debug_options ()->better_cast_details) {
3752                 MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
3753
3754                 MONO_ADD_INS (cfg->cbb, tls_get);
3755                 /* It is enough to reset the from field */
3756                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0);
3757         }
3758 }
3759
3760 /*
3761  * On return the caller must check @array_class for load errors
3762  */
3763 static void
3764 mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_class)
3765 {
3766         int vtable_reg = alloc_preg (cfg);
3767         int context_used;
3768
3769         context_used = mini_class_check_context_used (cfg, array_class);
3770
3771         save_cast_details (cfg, array_class, obj->dreg, FALSE, NULL);
3772
3773         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3774
3775         if (cfg->opt & MONO_OPT_SHARED) {
3776                 int class_reg = alloc_preg (cfg);
3777                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, class_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3778                 if (cfg->compile_aot) {
3779                         int klass_reg = alloc_preg (cfg);
3780                         MONO_EMIT_NEW_CLASSCONST (cfg, klass_reg, array_class);
3781                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, class_reg, klass_reg);
3782                 } else {
3783                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, class_reg, array_class);
3784                 }
3785         } else if (context_used) {
3786                 MonoInst *vtable_ins;
3787
3788                 vtable_ins = emit_get_rgctx_klass (cfg, context_used, array_class, MONO_RGCTX_INFO_VTABLE);
3789                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vtable_ins->dreg);
3790         } else {
3791                 if (cfg->compile_aot) {
3792                         int vt_reg;
3793                         MonoVTable *vtable;
3794
3795                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3796                                 return;
3797                         vt_reg = alloc_preg (cfg);
3798                         MONO_EMIT_NEW_VTABLECONST (cfg, vt_reg, vtable);
3799                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vt_reg);
3800                 } else {
3801                         MonoVTable *vtable;
3802                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3803                                 return;
3804                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vtable);
3805                 }
3806         }
3807         
3808         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException");
3809
3810         reset_cast_details (cfg);
3811 }
3812
3813 /**
3814  * Handles unbox of a Nullable<T>. If context_used is non zero, then shared 
3815  * generic code is generated.
3816  */
3817 static MonoInst*
3818 handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int context_used)
3819 {
3820         MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
3821
3822         if (context_used) {
3823                 MonoInst *rgctx, *addr;
3824
3825                 /* FIXME: What if the class is shared?  We might not
3826                    have to get the address of the method from the
3827                    RGCTX. */
3828                 addr = emit_get_rgctx_method (cfg, context_used, method,
3829                                                                           MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
3830
3831                 rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3832
3833                 return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
3834         } else {
3835                 gboolean pass_vtable, pass_mrgctx;
3836                 MonoInst *rgctx_arg = NULL;
3837
3838                 check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
3839                 g_assert (!pass_mrgctx);
3840
3841                 if (pass_vtable) {
3842                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
3843
3844                         g_assert (vtable);
3845                         EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
3846                 }
3847
3848                 return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
3849         }
3850 }
3851
3852 static MonoInst*
3853 handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_used)
3854 {
3855         MonoInst *add;
3856         int obj_reg;
3857         int vtable_reg = alloc_dreg (cfg ,STACK_PTR);
3858         int klass_reg = alloc_dreg (cfg ,STACK_PTR);
3859         int eclass_reg = alloc_dreg (cfg ,STACK_PTR);
3860         int rank_reg = alloc_dreg (cfg ,STACK_I4);
3861
3862         obj_reg = sp [0]->dreg;
3863         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3864         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
3865
3866         /* FIXME: generics */
3867         g_assert (klass->rank == 0);
3868                         
3869         // Check rank == 0
3870         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, 0);
3871         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3872
3873         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3874         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, element_class));
3875
3876         if (context_used) {
3877                 MonoInst *element_class;
3878
3879                 /* This assertion is from the unboxcast insn */
3880                 g_assert (klass->rank == 0);
3881
3882                 element_class = emit_get_rgctx_klass (cfg, context_used,
3883                                 klass->element_class, MONO_RGCTX_INFO_KLASS);
3884
3885                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, eclass_reg, element_class->dreg);
3886                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3887         } else {
3888                 save_cast_details (cfg, klass->element_class, obj_reg, FALSE, NULL);
3889                 mini_emit_class_check (cfg, eclass_reg, klass->element_class);
3890                 reset_cast_details (cfg);
3891         }
3892
3893         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), obj_reg, sizeof (MonoObject));
3894         MONO_ADD_INS (cfg->cbb, add);
3895         add->type = STACK_MP;
3896         add->klass = klass;
3897
3898         return add;
3899 }
3900
3901 static MonoInst*
3902 handle_unbox_gsharedvt (MonoCompile *cfg, MonoClass *klass, MonoInst *obj, MonoBasicBlock **out_cbb)
3903 {
3904         MonoInst *addr, *klass_inst, *is_ref, *args[16];
3905         MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
3906         MonoInst *ins;
3907         int dreg, addr_reg;
3908
3909         klass_inst = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_KLASS);
3910
3911         /* obj */
3912         args [0] = obj;
3913
3914         /* klass */
3915         args [1] = klass_inst;
3916
3917         /* CASTCLASS */
3918         obj = mono_emit_jit_icall (cfg, mono_object_castclass_unbox, args);
3919
3920         NEW_BBLOCK (cfg, is_ref_bb);
3921         NEW_BBLOCK (cfg, is_nullable_bb);
3922         NEW_BBLOCK (cfg, end_bb);
3923         is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
3924         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 1);
3925         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
3926
3927         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 2);
3928         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
3929
3930         /* This will contain either the address of the unboxed vtype, or an address of the temporary where the ref is stored */
3931         addr_reg = alloc_dreg (cfg, STACK_MP);
3932
3933         /* Non-ref case */
3934         /* UNBOX */
3935         NEW_BIALU_IMM (cfg, addr, OP_ADD_IMM, addr_reg, obj->dreg, sizeof (MonoObject));
3936         MONO_ADD_INS (cfg->cbb, addr);
3937
3938         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3939
3940         /* Ref case */
3941         MONO_START_BB (cfg, is_ref_bb);
3942
3943         /* Save the ref to a temporary */
3944         dreg = alloc_ireg (cfg);
3945         EMIT_NEW_VARLOADA_VREG (cfg, addr, dreg, &klass->byval_arg);
3946         addr->dreg = addr_reg;
3947         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, obj->dreg);
3948         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3949
3950         /* Nullable case */
3951         MONO_START_BB (cfg, is_nullable_bb);
3952
3953         {
3954                 MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX);
3955                 MonoInst *unbox_call;
3956                 MonoMethodSignature *unbox_sig;
3957                 MonoInst *var;
3958
3959                 var = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
3960
3961                 unbox_sig = mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
3962                 unbox_sig->ret = &klass->byval_arg;
3963                 unbox_sig->param_count = 1;
3964                 unbox_sig->params [0] = &mono_defaults.object_class->byval_arg;
3965                 unbox_call = mono_emit_calli (cfg, unbox_sig, &obj, addr, NULL, NULL);
3966
3967                 EMIT_NEW_VARLOADA_VREG (cfg, addr, unbox_call->dreg, &klass->byval_arg);
3968                 addr->dreg = addr_reg;
3969         }
3970
3971         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3972
3973         /* End */
3974         MONO_START_BB (cfg, end_bb);
3975
3976         /* LDOBJ */
3977         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr_reg, 0);
3978
3979         *out_cbb = cfg->cbb;
3980
3981         return ins;
3982 }
3983
3984 /*
3985  * Returns NULL and set the cfg exception on error.
3986  */
3987 static MonoInst*
3988 handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_used)
3989 {
3990         MonoInst *iargs [2];
3991         void *alloc_ftn;
3992
3993         if (context_used) {
3994                 MonoInst *data;
3995                 int rgctx_info;
3996                 MonoInst *iargs [2];
3997                 gboolean known_instance_size = !mini_is_gsharedvt_klass (cfg, klass);
3998
3999                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (klass, for_box, known_instance_size);
4000
4001                 if (cfg->opt & MONO_OPT_SHARED)
4002                         rgctx_info = MONO_RGCTX_INFO_KLASS;
4003                 else
4004                         rgctx_info = MONO_RGCTX_INFO_VTABLE;
4005                 data = emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
4006
4007                 if (cfg->opt & MONO_OPT_SHARED) {
4008                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4009                         iargs [1] = data;
4010                         alloc_ftn = mono_object_new;
4011                 } else {
4012                         iargs [0] = data;
4013                         alloc_ftn = mono_object_new_specific;
4014                 }
4015
4016                 if (managed_alloc && !(cfg->opt & MONO_OPT_SHARED)) {
4017                         if (known_instance_size)
4018                                 EMIT_NEW_ICONST (cfg, iargs [1], mono_gc_get_aligned_size_for_allocator (klass->instance_size));
4019                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4020                 }
4021
4022                 return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4023         }
4024
4025         if (cfg->opt & MONO_OPT_SHARED) {
4026                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4027                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
4028
4029                 alloc_ftn = mono_object_new;
4030         } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !klass->generic_class) {
4031                 /* This happens often in argument checking code, eg. throw new FooException... */
4032                 /* Avoid relocations and save some space by calling a helper function specialized to mscorlib */
4033                 EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
4034                 return mono_emit_jit_icall (cfg, mono_helper_newobj_mscorlib, iargs);
4035         } else {
4036                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
4037                 MonoMethod *managed_alloc = NULL;
4038                 gboolean pass_lw;
4039
4040                 if (!vtable) {
4041                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4042                         cfg->exception_ptr = klass;
4043                         return NULL;
4044                 }
4045
4046 #ifndef MONO_CROSS_COMPILE
4047                 managed_alloc = mono_gc_get_managed_allocator (klass, for_box, TRUE);
4048 #endif
4049
4050                 if (managed_alloc) {
4051                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4052                         EMIT_NEW_ICONST (cfg, iargs [1], mono_gc_get_aligned_size_for_allocator (klass->instance_size));
4053                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4054                 }
4055                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
4056                 if (pass_lw) {
4057                         guint32 lw = vtable->klass->instance_size;
4058                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
4059                         EMIT_NEW_ICONST (cfg, iargs [0], lw);
4060                         EMIT_NEW_VTABLECONST (cfg, iargs [1], vtable);
4061                 }
4062                 else {
4063                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4064                 }
4065         }
4066
4067         return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4068 }
4069         
4070 /*
4071  * Returns NULL and set the cfg exception on error.
4072  */     
4073 static MonoInst*
4074 handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used, MonoBasicBlock **out_cbb)
4075 {
4076         MonoInst *alloc, *ins;
4077
4078         *out_cbb = cfg->cbb;
4079
4080         if (mono_class_is_nullable (klass)) {
4081                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
4082
4083                 if (context_used) {
4084                         /* FIXME: What if the class is shared?  We might not
4085                            have to get the method address from the RGCTX. */
4086                         MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4087                                                                                                         MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4088                         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
4089
4090                         return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
4091                 } else {
4092                         gboolean pass_vtable, pass_mrgctx;
4093                         MonoInst *rgctx_arg = NULL;
4094
4095                         check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
4096                         g_assert (!pass_mrgctx);
4097
4098                         if (pass_vtable) {
4099                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4100
4101                                 g_assert (vtable);
4102                                 EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
4103                         }
4104
4105                         return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4106                 }
4107         }
4108
4109         if (mini_is_gsharedvt_klass (cfg, klass)) {
4110                 MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4111                 MonoInst *res, *is_ref, *src_var, *addr;
4112                 int addr_reg, dreg;
4113
4114                 dreg = alloc_ireg (cfg);
4115
4116                 NEW_BBLOCK (cfg, is_ref_bb);
4117                 NEW_BBLOCK (cfg, is_nullable_bb);
4118                 NEW_BBLOCK (cfg, end_bb);
4119                 is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4120                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 1);
4121                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4122
4123                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 2);
4124                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4125
4126                 /* Non-ref case */
4127                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4128                 if (!alloc)
4129                         return NULL;
4130                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4131                 ins->opcode = OP_STOREV_MEMBASE;
4132
4133                 EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, alloc->dreg);
4134                 res->type = STACK_OBJ;
4135                 res->klass = klass;
4136                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4137                 
4138                 /* Ref case */
4139                 MONO_START_BB (cfg, is_ref_bb);
4140                 addr_reg = alloc_ireg (cfg);
4141
4142                 /* val is a vtype, so has to load the value manually */
4143                 src_var = get_vreg_to_inst (cfg, val->dreg);
4144                 if (!src_var)
4145                         src_var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, val->dreg);
4146                 EMIT_NEW_VARLOADA (cfg, addr, src_var, src_var->inst_vtype);
4147                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, addr->dreg, 0);
4148                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4149
4150                 /* Nullable case */
4151                 MONO_START_BB (cfg, is_nullable_bb);
4152
4153                 {
4154                         MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass,
4155                                                                                                         MONO_RGCTX_INFO_NULLABLE_CLASS_BOX);
4156                         MonoInst *box_call;
4157                         MonoMethodSignature *box_sig;
4158
4159                         /*
4160                          * klass is Nullable<T>, need to call Nullable<T>.Box () using a gsharedvt signature, but we cannot
4161                          * construct that method at JIT time, so have to do things by hand.
4162                          */
4163                         box_sig = mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4164                         box_sig->ret = &mono_defaults.object_class->byval_arg;
4165                         box_sig->param_count = 1;
4166                         box_sig->params [0] = &klass->byval_arg;
4167                         box_call = mono_emit_calli (cfg, box_sig, &val, addr, NULL, NULL);
4168                         EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, box_call->dreg);
4169                         res->type = STACK_OBJ;
4170                         res->klass = klass;
4171                 }
4172
4173                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4174
4175                 MONO_START_BB (cfg, end_bb);
4176
4177                 *out_cbb = cfg->cbb;
4178
4179                 return res;
4180         } else {
4181                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4182                 if (!alloc)
4183                         return NULL;
4184
4185                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4186                 return alloc;
4187         }
4188 }
4189
4190
4191 static gboolean
4192 mini_class_has_reference_variant_generic_argument (MonoCompile *cfg, MonoClass *klass, int context_used)
4193 {
4194         int i;
4195         MonoGenericContainer *container;
4196         MonoGenericInst *ginst;
4197
4198         if (klass->generic_class) {
4199                 container = klass->generic_class->container_class->generic_container;
4200                 ginst = klass->generic_class->context.class_inst;
4201         } else if (klass->generic_container && context_used) {
4202                 container = klass->generic_container;
4203                 ginst = container->context.class_inst;
4204         } else {
4205                 return FALSE;
4206         }
4207
4208         for (i = 0; i < container->type_argc; ++i) {
4209                 MonoType *type;
4210                 if (!(mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT)))
4211                         continue;
4212                 type = ginst->type_argv [i];
4213                 if (mini_type_is_reference (cfg, type))
4214                         return TRUE;
4215         }
4216         return FALSE;
4217 }
4218
4219 #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)
4220
4221 static MonoInst*
4222 emit_castclass_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args, MonoBasicBlock **out_bblock)
4223 {
4224         MonoMethod *mono_castclass;
4225         MonoInst *res;
4226
4227         mono_castclass = mono_marshal_get_castclass_with_cache ();
4228
4229         save_cast_details (cfg, klass, args [0]->dreg, TRUE, out_bblock);
4230         res = mono_emit_method_call (cfg, mono_castclass, args, NULL);
4231         reset_cast_details (cfg);
4232         *out_bblock = cfg->cbb;
4233
4234         return res;
4235 }
4236
4237 static MonoInst*
4238 emit_castclass_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass *klass, MonoBasicBlock **out_bblock)
4239 {
4240         MonoInst *args [3];
4241         int idx;
4242
4243         /* obj */
4244         args [0] = obj;
4245
4246         /* klass */
4247         EMIT_NEW_CLASSCONST (cfg, args [1], klass);
4248
4249         /* inline cache*/
4250         if (cfg->compile_aot) {
4251                 /* Each CASTCLASS_CACHE patch needs a unique index which identifies the call site */
4252                 cfg->castclass_cache_index ++;
4253                 idx = (cfg->method_index << 16) | cfg->castclass_cache_index;
4254                 EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
4255         } else {
4256                 EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
4257         }
4258
4259         /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
4260
4261         return emit_castclass_with_cache (cfg, klass, args, out_bblock);
4262 }
4263
4264 /*
4265  * Returns NULL and set the cfg exception on error.
4266  */
4267 static MonoInst*
4268 handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, guint8 *ip, MonoBasicBlock **out_bb, int *inline_costs)
4269 {
4270         MonoBasicBlock *is_null_bb;
4271         int obj_reg = src->dreg;
4272         int vtable_reg = alloc_preg (cfg);
4273         int context_used;
4274         MonoInst *klass_inst = NULL, *res;
4275         MonoBasicBlock *bblock;
4276
4277         *out_bb = cfg->cbb;
4278
4279         context_used = mini_class_check_context_used (cfg, klass);
4280
4281         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
4282                 res = emit_castclass_with_cache_nonshared (cfg, src, klass, &bblock);
4283                 (*inline_costs) += 2;
4284                 *out_bb = cfg->cbb;
4285                 return res;
4286         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
4287                 MonoMethod *mono_castclass;
4288                 MonoInst *iargs [1];
4289                 int costs;
4290
4291                 mono_castclass = mono_marshal_get_castclass (klass); 
4292                 iargs [0] = src;
4293                                 
4294                 save_cast_details (cfg, klass, src->dreg, TRUE, &bblock);
4295                 costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
4296                                                            iargs, ip, cfg->real_offset, TRUE, &bblock);
4297                 reset_cast_details (cfg);
4298                 CHECK_CFG_EXCEPTION;
4299                 g_assert (costs > 0);
4300                                 
4301                 cfg->real_offset += 5;
4302
4303                 (*inline_costs) += costs;
4304
4305                 *out_bb = cfg->cbb;
4306                 return src;
4307         }
4308
4309         if (context_used) {
4310                 MonoInst *args [3];
4311
4312                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4313                         MonoInst *cache_ins;
4314
4315                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4316
4317                         /* obj */
4318                         args [0] = src;
4319
4320                         /* klass - it's the second element of the cache entry*/
4321                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4322
4323                         /* cache */
4324                         args [2] = cache_ins;
4325
4326                         return emit_castclass_with_cache (cfg, klass, args, out_bb);
4327                 }
4328
4329                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4330         }
4331
4332         NEW_BBLOCK (cfg, is_null_bb);
4333
4334         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4335         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
4336
4337         save_cast_details (cfg, klass, obj_reg, FALSE, NULL);
4338
4339         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4340                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4341                 mini_emit_iface_cast (cfg, vtable_reg, klass, NULL, NULL);
4342         } else {
4343                 int klass_reg = alloc_preg (cfg);
4344
4345                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4346
4347                 if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4348                         /* the remoting code is broken, access the class for now */
4349                         if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4350                                 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4351                                 if (!vt) {
4352                                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4353                                         cfg->exception_ptr = klass;
4354                                         return NULL;
4355                                 }
4356                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4357                         } else {
4358                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4359                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4360                         }
4361                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4362                 } else {
4363                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4364                         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, klass_inst, is_null_bb);
4365                 }
4366         }
4367
4368         MONO_START_BB (cfg, is_null_bb);
4369
4370         reset_cast_details (cfg);
4371
4372         *out_bb = cfg->cbb;
4373
4374         return src;
4375
4376 exception_exit:
4377         return NULL;
4378 }
4379
4380 /*
4381  * Returns NULL and set the cfg exception on error.
4382  */
4383 static MonoInst*
4384 handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
4385 {
4386         MonoInst *ins;
4387         MonoBasicBlock *is_null_bb, *false_bb, *end_bb;
4388         int obj_reg = src->dreg;
4389         int vtable_reg = alloc_preg (cfg);
4390         int res_reg = alloc_ireg_ref (cfg);
4391         MonoInst *klass_inst = NULL;
4392
4393         if (context_used) {
4394                 MonoInst *args [3];
4395
4396                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4397                         MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
4398                         MonoInst *cache_ins;
4399
4400                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4401
4402                         /* obj */
4403                         args [0] = src;
4404
4405                         /* klass - it's the second element of the cache entry*/
4406                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4407
4408                         /* cache */
4409                         args [2] = cache_ins;
4410
4411                         return mono_emit_method_call (cfg, mono_isinst, args, NULL);
4412                 }
4413
4414                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4415         }
4416
4417         NEW_BBLOCK (cfg, is_null_bb);
4418         NEW_BBLOCK (cfg, false_bb);
4419         NEW_BBLOCK (cfg, end_bb);
4420
4421         /* Do the assignment at the beginning, so the other assignment can be if converted */
4422         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, res_reg, obj_reg);
4423         ins->type = STACK_OBJ;
4424         ins->klass = klass;
4425
4426         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4427         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_null_bb);
4428
4429         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4430
4431         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4432                 g_assert (!context_used);
4433                 /* the is_null_bb target simply copies the input register to the output */
4434                 mini_emit_iface_cast (cfg, vtable_reg, klass, false_bb, is_null_bb);
4435         } else {
4436                 int klass_reg = alloc_preg (cfg);
4437
4438                 if (klass->rank) {
4439                         int rank_reg = alloc_preg (cfg);
4440                         int eclass_reg = alloc_preg (cfg);
4441
4442                         g_assert (!context_used);
4443                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
4444                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
4445                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4446                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4447                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
4448                         if (klass->cast_class == mono_defaults.object_class) {
4449                                 int parent_reg = alloc_preg (cfg);
4450                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
4451                                 mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, is_null_bb);
4452                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4453                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4454                         } else if (klass->cast_class == mono_defaults.enum_class->parent) {
4455                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, is_null_bb);
4456                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);                          
4457                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4458                         } else if (klass->cast_class == mono_defaults.enum_class) {
4459                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4460                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4461                         } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
4462                                 mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4463                         } else {
4464                                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY)) {
4465                                         /* Check that the object is a vector too */
4466                                         int bounds_reg = alloc_preg (cfg);
4467                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
4468                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
4469                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4470                                 }
4471
4472                                 /* the is_null_bb target simply copies the input register to the output */
4473                                 mini_emit_isninst_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4474                         }
4475                 } else if (mono_class_is_nullable (klass)) {
4476                         g_assert (!context_used);
4477                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4478                         /* the is_null_bb target simply copies the input register to the output */
4479                         mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb);
4480                 } else {
4481                         if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4482                                 g_assert (!context_used);
4483                                 /* the remoting code is broken, access the class for now */
4484                                 if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4485                                         MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4486                                         if (!vt) {
4487                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4488                                                 cfg->exception_ptr = klass;
4489                                                 return NULL;
4490                                         }
4491                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4492                                 } else {
4493                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4494                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4495                                 }
4496                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4497                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
4498                         } else {
4499                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4500                                 /* the is_null_bb target simply copies the input register to the output */
4501                                 mini_emit_isninst_cast_inst (cfg, klass_reg, klass, klass_inst, false_bb, is_null_bb);
4502                         }
4503                 }
4504         }
4505
4506         MONO_START_BB (cfg, false_bb);
4507
4508         MONO_EMIT_NEW_PCONST (cfg, res_reg, 0);
4509         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4510
4511         MONO_START_BB (cfg, is_null_bb);
4512
4513         MONO_START_BB (cfg, end_bb);
4514
4515         return ins;
4516 }
4517
4518 static MonoInst*
4519 handle_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4520 {
4521         /* This opcode takes as input an object reference and a class, and returns:
4522         0) if the object is an instance of the class,
4523         1) if the object is not instance of the class,
4524         2) if the object is a proxy whose type cannot be determined */
4525
4526         MonoInst *ins;
4527 #ifndef DISABLE_REMOTING
4528         MonoBasicBlock *true_bb, *false_bb, *false2_bb, *end_bb, *no_proxy_bb, *interface_fail_bb;
4529 #else
4530         MonoBasicBlock *true_bb, *false_bb, *end_bb;
4531 #endif
4532         int obj_reg = src->dreg;
4533         int dreg = alloc_ireg (cfg);
4534         int tmp_reg;
4535 #ifndef DISABLE_REMOTING
4536         int klass_reg = alloc_preg (cfg);
4537 #endif
4538
4539         NEW_BBLOCK (cfg, true_bb);
4540         NEW_BBLOCK (cfg, false_bb);
4541         NEW_BBLOCK (cfg, end_bb);
4542 #ifndef DISABLE_REMOTING
4543         NEW_BBLOCK (cfg, false2_bb);
4544         NEW_BBLOCK (cfg, no_proxy_bb);
4545 #endif
4546
4547         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4548         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
4549
4550         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4551 #ifndef DISABLE_REMOTING
4552                 NEW_BBLOCK (cfg, interface_fail_bb);
4553 #endif
4554
4555                 tmp_reg = alloc_preg (cfg);
4556                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4557 #ifndef DISABLE_REMOTING
4558                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, true_bb);
4559                 MONO_START_BB (cfg, interface_fail_bb);
4560                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4561                 
4562                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, false_bb);
4563
4564                 tmp_reg = alloc_preg (cfg);
4565                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4566                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4567                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false2_bb);                
4568 #else
4569                 mini_emit_iface_cast (cfg, tmp_reg, klass, false_bb, true_bb);
4570 #endif
4571         } else {
4572 #ifndef DISABLE_REMOTING
4573                 tmp_reg = alloc_preg (cfg);
4574                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4575                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4576
4577                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4578                 tmp_reg = alloc_preg (cfg);
4579                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4580                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4581
4582                 tmp_reg = alloc_preg (cfg);             
4583                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4584                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4585                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4586                 
4587                 mini_emit_isninst_cast (cfg, klass_reg, klass, false2_bb, true_bb);
4588                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false2_bb);
4589
4590                 MONO_START_BB (cfg, no_proxy_bb);
4591
4592                 mini_emit_isninst_cast (cfg, klass_reg, klass, false_bb, true_bb);
4593 #else
4594                 g_error ("transparent proxy support is disabled while trying to JIT code that uses it");
4595 #endif
4596         }
4597
4598         MONO_START_BB (cfg, false_bb);
4599
4600         MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4601         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4602
4603 #ifndef DISABLE_REMOTING
4604         MONO_START_BB (cfg, false2_bb);
4605
4606         MONO_EMIT_NEW_ICONST (cfg, dreg, 2);
4607         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4608 #endif
4609
4610         MONO_START_BB (cfg, true_bb);
4611
4612         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4613
4614         MONO_START_BB (cfg, end_bb);
4615
4616         /* FIXME: */
4617         MONO_INST_NEW (cfg, ins, OP_ICONST);
4618         ins->dreg = dreg;
4619         ins->type = STACK_I4;
4620
4621         return ins;
4622 }
4623
4624 static MonoInst*
4625 handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4626 {
4627         /* This opcode takes as input an object reference and a class, and returns:
4628         0) if the object is an instance of the class,
4629         1) if the object is a proxy whose type cannot be determined
4630         an InvalidCastException exception is thrown otherwhise*/
4631         
4632         MonoInst *ins;
4633 #ifndef DISABLE_REMOTING
4634         MonoBasicBlock *end_bb, *ok_result_bb, *no_proxy_bb, *interface_fail_bb, *fail_1_bb;
4635 #else
4636         MonoBasicBlock *ok_result_bb;
4637 #endif
4638         int obj_reg = src->dreg;
4639         int dreg = alloc_ireg (cfg);
4640         int tmp_reg = alloc_preg (cfg);
4641
4642 #ifndef DISABLE_REMOTING
4643         int klass_reg = alloc_preg (cfg);
4644         NEW_BBLOCK (cfg, end_bb);
4645 #endif
4646
4647         NEW_BBLOCK (cfg, ok_result_bb);
4648
4649         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4650         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, ok_result_bb);
4651
4652         save_cast_details (cfg, klass, obj_reg, FALSE, NULL);
4653
4654         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4655 #ifndef DISABLE_REMOTING
4656                 NEW_BBLOCK (cfg, interface_fail_bb);
4657         
4658                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4659                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, ok_result_bb);
4660                 MONO_START_BB (cfg, interface_fail_bb);
4661                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4662
4663                 mini_emit_class_check (cfg, klass_reg, mono_defaults.transparent_proxy_class);
4664
4665                 tmp_reg = alloc_preg (cfg);             
4666                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4667                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4668                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
4669                 
4670                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4671                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4672 #else
4673                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4674                 mini_emit_iface_cast (cfg, tmp_reg, klass, NULL, NULL);
4675                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, ok_result_bb);
4676 #endif
4677         } else {
4678 #ifndef DISABLE_REMOTING
4679                 NEW_BBLOCK (cfg, no_proxy_bb);
4680
4681                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4682                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4683                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4684
4685                 tmp_reg = alloc_preg (cfg);
4686                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4687                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4688
4689                 tmp_reg = alloc_preg (cfg);
4690                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4691                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4692                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4693
4694                 NEW_BBLOCK (cfg, fail_1_bb);
4695                 
4696                 mini_emit_isninst_cast (cfg, klass_reg, klass, fail_1_bb, ok_result_bb);
4697
4698                 MONO_START_BB (cfg, fail_1_bb);
4699
4700                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4701                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4702
4703                 MONO_START_BB (cfg, no_proxy_bb);
4704
4705                 mini_emit_castclass (cfg, obj_reg, klass_reg, klass, ok_result_bb);
4706 #else
4707                 g_error ("Transparent proxy support is disabled while trying to JIT code that uses it");
4708 #endif
4709         }
4710
4711         MONO_START_BB (cfg, ok_result_bb);
4712
4713         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4714
4715 #ifndef DISABLE_REMOTING
4716         MONO_START_BB (cfg, end_bb);
4717 #endif
4718
4719         /* FIXME: */
4720         MONO_INST_NEW (cfg, ins, OP_ICONST);
4721         ins->dreg = dreg;
4722         ins->type = STACK_I4;
4723
4724         return ins;
4725 }
4726
4727 static G_GNUC_UNUSED MonoInst*
4728 handle_enum_has_flag (MonoCompile *cfg, MonoClass *klass, MonoInst *enum_this, MonoInst *enum_flag)
4729 {
4730         MonoType *enum_type = mono_type_get_underlying_type (&klass->byval_arg);
4731         guint32 load_opc = mono_type_to_load_membase (cfg, enum_type);
4732         gboolean is_i4 = TRUE;
4733
4734         switch (enum_type->type) {
4735         case MONO_TYPE_I8:
4736         case MONO_TYPE_U8:
4737 #if SIZEOF_REGISTER == 8
4738         case MONO_TYPE_I:
4739         case MONO_TYPE_U:
4740 #endif
4741                 is_i4 = FALSE;
4742                 break;
4743         }
4744
4745         {
4746                 MonoInst *load, *and, *cmp, *ceq;
4747                 int enum_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4748                 int and_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4749                 int dest_reg = alloc_ireg (cfg);
4750
4751                 EMIT_NEW_LOAD_MEMBASE (cfg, load, load_opc, enum_reg, enum_this->dreg, 0);
4752                 EMIT_NEW_BIALU (cfg, and, is_i4 ? OP_IAND : OP_LAND, and_reg, enum_reg, enum_flag->dreg);
4753                 EMIT_NEW_BIALU (cfg, cmp, is_i4 ? OP_ICOMPARE : OP_LCOMPARE, -1, and_reg, enum_flag->dreg);
4754                 EMIT_NEW_UNALU (cfg, ceq, is_i4 ? OP_ICEQ : OP_LCEQ, dest_reg, -1);
4755
4756                 ceq->type = STACK_I4;
4757
4758                 if (!is_i4) {
4759                         load = mono_decompose_opcode (cfg, load, NULL);
4760                         and = mono_decompose_opcode (cfg, and, NULL);
4761                         cmp = mono_decompose_opcode (cfg, cmp, NULL);
4762                         ceq = mono_decompose_opcode (cfg, ceq, NULL);
4763                 }
4764
4765                 return ceq;
4766         }
4767 }
4768
4769 /*
4770  * Returns NULL and set the cfg exception on error.
4771  */
4772 static G_GNUC_UNUSED MonoInst*
4773 handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method, int context_used, gboolean virtual)
4774 {
4775         MonoInst *ptr;
4776         int dreg;
4777         gpointer trampoline;
4778         MonoInst *obj, *method_ins, *tramp_ins;
4779         MonoDomain *domain;
4780         guint8 **code_slot;
4781         
4782         // FIXME reenable optimisation for virtual case
4783         if (virtual)
4784                 return NULL;
4785
4786         if (virtual) {
4787                 MonoMethod *invoke = mono_get_delegate_invoke (klass);
4788                 g_assert (invoke);
4789
4790                 if (!mono_get_delegate_virtual_invoke_impl (mono_method_signature (invoke), context_used ? NULL : method))
4791                         return NULL;
4792         }
4793
4794         obj = handle_alloc (cfg, klass, FALSE, 0);
4795         if (!obj)
4796                 return NULL;
4797
4798         /* Inline the contents of mono_delegate_ctor */
4799
4800         /* Set target field */
4801         /* Optimize away setting of NULL target */
4802         if (!(target->opcode == OP_PCONST && target->inst_p0 == 0)) {
4803                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
4804                 if (cfg->gen_write_barriers) {
4805                         dreg = alloc_preg (cfg);
4806                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target));
4807                         emit_write_barrier (cfg, ptr, target);
4808                 }
4809         }
4810
4811         /* Set method field */
4812         method_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
4813         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg);
4814
4815         /* 
4816          * To avoid looking up the compiled code belonging to the target method
4817          * in mono_delegate_trampoline (), we allocate a per-domain memory slot to
4818          * store it, and we fill it after the method has been compiled.
4819          */
4820         if (!method->dynamic && !(cfg->opt & MONO_OPT_SHARED)) {
4821                 MonoInst *code_slot_ins;
4822
4823                 if (context_used) {
4824                         code_slot_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD_DELEGATE_CODE);
4825                 } else {
4826                         domain = mono_domain_get ();
4827                         mono_domain_lock (domain);
4828                         if (!domain_jit_info (domain)->method_code_hash)
4829                                 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
4830                         code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, method);
4831                         if (!code_slot) {
4832                                 code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
4833                                 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, method, code_slot);
4834                         }
4835                         mono_domain_unlock (domain);
4836
4837                         if (cfg->compile_aot)
4838                                 EMIT_NEW_AOTCONST (cfg, code_slot_ins, MONO_PATCH_INFO_METHOD_CODE_SLOT, method);
4839                         else
4840                                 EMIT_NEW_PCONST (cfg, code_slot_ins, code_slot);
4841                 }
4842                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);                
4843         }
4844
4845         if (cfg->compile_aot) {
4846                 MonoDelegateClassMethodPair *del_tramp;
4847
4848                 del_tramp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoDelegateClassMethodPair));
4849                 del_tramp->klass = klass;
4850                 del_tramp->method = context_used ? NULL : method;
4851                 del_tramp->virtual = virtual;
4852                 EMIT_NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_DELEGATE_TRAMPOLINE, del_tramp);
4853         } else {
4854                 if (virtual)
4855                         trampoline = mono_create_delegate_virtual_trampoline (cfg->domain, klass, context_used ? NULL : method);
4856                 else
4857                         trampoline = mono_create_delegate_trampoline_info (cfg->domain, klass, context_used ? NULL : method);
4858                 EMIT_NEW_PCONST (cfg, tramp_ins, trampoline);
4859         }
4860
4861         /* Set invoke_impl field */
4862         if (virtual) {
4863                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), tramp_ins->dreg);
4864         } else {
4865                 dreg = alloc_preg (cfg);
4866                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, invoke_impl));
4867                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), dreg);
4868
4869                 dreg = alloc_preg (cfg);
4870                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, method_ptr));
4871                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr), dreg);
4872         }
4873
4874         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
4875
4876         return obj;
4877 }
4878
4879 static MonoInst*
4880 handle_array_new (MonoCompile *cfg, int rank, MonoInst **sp, unsigned char *ip)
4881 {
4882         MonoJitICallInfo *info;
4883
4884         /* Need to register the icall so it gets an icall wrapper */
4885         info = mono_get_array_new_va_icall (rank);
4886
4887         cfg->flags |= MONO_CFG_HAS_VARARGS;
4888
4889         /* mono_array_new_va () needs a vararg calling convention */
4890         cfg->disable_llvm = TRUE;
4891
4892         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
4893         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, sp);
4894 }
4895
4896 /*
4897  * handle_constrained_gsharedvt_call:
4898  *
4899  *   Handle constrained calls where the receiver is a gsharedvt type.
4900  * Return the instruction representing the call. Set the cfg exception on failure.
4901  */
4902 static MonoInst*
4903 handle_constrained_gsharedvt_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp, MonoClass *constrained_call,
4904                                                                    gboolean *ref_emit_widen, MonoBasicBlock **ref_bblock)
4905 {
4906         MonoInst *ins = NULL;
4907         MonoBasicBlock *bblock = *ref_bblock;
4908         gboolean emit_widen = *ref_emit_widen;
4909
4910         /*
4911          * Constrained calls need to behave differently at runtime dependending on whenever the receiver is instantiated as ref type or as a vtype.
4912          * 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
4913          * pack the arguments into an array, and do the rest of the work in in an icall.
4914          */
4915         if (((cmethod->klass == mono_defaults.object_class) || (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) &&
4916                 (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)) &&
4917                 (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]))))) {
4918                 MonoInst *args [16];
4919
4920                 /*
4921                  * This case handles calls to
4922                  * - object:ToString()/Equals()/GetHashCode(),
4923                  * - System.IComparable<T>:CompareTo()
4924                  * - System.IEquatable<T>:Equals ()
4925                  * plus some simple interface calls enough to support AsyncTaskMethodBuilder.
4926                  */
4927
4928                 args [0] = sp [0];
4929                 if (mono_method_check_context_used (cmethod))
4930                         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cmethod), cmethod, MONO_RGCTX_INFO_METHOD);
4931                 else
4932                         EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
4933                 args [2] = emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_call), constrained_call, MONO_RGCTX_INFO_KLASS);
4934
4935                 /* !fsig->hasthis is for the wrapper for the Object.GetType () icall */
4936                 if (fsig->hasthis && fsig->param_count) {
4937                         /* Pass the arguments using a localloc-ed array using the format expected by runtime_invoke () */
4938                         MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
4939                         ins->dreg = alloc_preg (cfg);
4940                         ins->inst_imm = fsig->param_count * sizeof (mgreg_t);
4941                         MONO_ADD_INS (cfg->cbb, ins);
4942                         args [4] = ins;
4943
4944                         if (mini_is_gsharedvt_type (cfg, fsig->params [0])) {
4945                                 int addr_reg;
4946
4947                                 args [3] = emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type (fsig->params [0]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4948
4949                                 EMIT_NEW_VARLOADA_VREG (cfg, ins, sp [1]->dreg, fsig->params [0]);
4950                                 addr_reg = ins->dreg;
4951                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, addr_reg);
4952                         } else {
4953                                 EMIT_NEW_ICONST (cfg, args [3], 0);
4954                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, sp [1]->dreg);
4955                         }
4956                 } else {
4957                         EMIT_NEW_ICONST (cfg, args [3], 0);
4958                         EMIT_NEW_ICONST (cfg, args [4], 0);
4959                 }
4960                 ins = mono_emit_jit_icall (cfg, mono_gsharedvt_constrained_call, args);
4961                 emit_widen = FALSE;
4962
4963                 if (mini_is_gsharedvt_type (cfg, fsig->ret)) {
4964                         ins = handle_unbox_gsharedvt (cfg, mono_class_from_mono_type (fsig->ret), ins, &bblock);
4965                 } else if (MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret)) {
4966                         MonoInst *add;
4967
4968                         /* Unbox */
4969                         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), ins->dreg, sizeof (MonoObject));
4970                         MONO_ADD_INS (cfg->cbb, add);
4971                         /* Load value */
4972                         NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, add->dreg, 0);
4973                         MONO_ADD_INS (cfg->cbb, ins);
4974                         /* ins represents the call result */
4975                 }
4976         } else {
4977                 GSHAREDVT_FAILURE (CEE_CALLVIRT);
4978         }
4979
4980         *ref_emit_widen = emit_widen;
4981         *ref_bblock = bblock;
4982
4983         return ins;
4984
4985  exception_exit:
4986         return NULL;
4987 }
4988
4989 static void
4990 mono_emit_load_got_addr (MonoCompile *cfg)
4991 {
4992         MonoInst *getaddr, *dummy_use;
4993
4994         if (!cfg->got_var || cfg->got_var_allocated)
4995                 return;
4996
4997         MONO_INST_NEW (cfg, getaddr, OP_LOAD_GOTADDR);
4998         getaddr->cil_code = cfg->header->code;
4999         getaddr->dreg = cfg->got_var->dreg;
5000
5001         /* Add it to the start of the first bblock */
5002         if (cfg->bb_entry->code) {
5003                 getaddr->next = cfg->bb_entry->code;
5004                 cfg->bb_entry->code = getaddr;
5005         }
5006         else
5007                 MONO_ADD_INS (cfg->bb_entry, getaddr);
5008
5009         cfg->got_var_allocated = TRUE;
5010
5011         /* 
5012          * Add a dummy use to keep the got_var alive, since real uses might
5013          * only be generated by the back ends.
5014          * Add it to end_bblock, so the variable's lifetime covers the whole
5015          * method.
5016          * It would be better to make the usage of the got var explicit in all
5017          * cases when the backend needs it (i.e. calls, throw etc.), so this
5018          * wouldn't be needed.
5019          */
5020         NEW_DUMMY_USE (cfg, dummy_use, cfg->got_var);
5021         MONO_ADD_INS (cfg->bb_exit, dummy_use);
5022 }
5023
5024 static int inline_limit;
5025 static gboolean inline_limit_inited;
5026
5027 static gboolean
5028 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
5029 {
5030         MonoMethodHeaderSummary header;
5031         MonoVTable *vtable;
5032 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5033         MonoMethodSignature *sig = mono_method_signature (method);
5034         int i;
5035 #endif
5036
5037         if (cfg->disable_inline)
5038                 return FALSE;
5039         if (cfg->generic_sharing_context)
5040                 return FALSE;
5041
5042         if (cfg->inline_depth > 10)
5043                 return FALSE;
5044
5045 #ifdef MONO_ARCH_HAVE_LMF_OPS
5046         if (((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
5047                  (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) &&
5048             !MONO_TYPE_ISSTRUCT (signature->ret) && !mini_class_is_system_array (method->klass))
5049                 return TRUE;
5050 #endif
5051
5052
5053         if (!mono_method_get_header_summary (method, &header))
5054                 return FALSE;
5055
5056         /*runtime, icall and pinvoke are checked by summary call*/
5057         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
5058             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
5059             (mono_class_is_marshalbyref (method->klass)) ||
5060             header.has_clauses)
5061                 return FALSE;
5062
5063         /* also consider num_locals? */
5064         /* Do the size check early to avoid creating vtables */
5065         if (!inline_limit_inited) {
5066                 if (g_getenv ("MONO_INLINELIMIT"))
5067                         inline_limit = atoi (g_getenv ("MONO_INLINELIMIT"));
5068                 else
5069                         inline_limit = INLINE_LENGTH_LIMIT;
5070                 inline_limit_inited = TRUE;
5071         }
5072         if (header.code_size >= inline_limit && !(method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
5073                 return FALSE;
5074
5075         /*
5076          * if we can initialize the class of the method right away, we do,
5077          * otherwise we don't allow inlining if the class needs initialization,
5078          * since it would mean inserting a call to mono_runtime_class_init()
5079          * inside the inlined code
5080          */
5081         if (!(cfg->opt & MONO_OPT_SHARED)) {
5082                 /* The AggressiveInlining hint is a good excuse to force that cctor to run. */
5083                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING) {
5084                         vtable = mono_class_vtable (cfg->domain, method->klass);
5085                         if (!vtable)
5086                                 return FALSE;
5087                         if (!cfg->compile_aot)
5088                                 mono_runtime_class_init (vtable);
5089                 } else if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5090                         if (cfg->run_cctors && method->klass->has_cctor) {
5091                                 /*FIXME it would easier and lazier to just use mono_class_try_get_vtable */
5092                                 if (!method->klass->runtime_info)
5093                                         /* No vtable created yet */
5094                                         return FALSE;
5095                                 vtable = mono_class_vtable (cfg->domain, method->klass);
5096                                 if (!vtable)
5097                                         return FALSE;
5098                                 /* This makes so that inline cannot trigger */
5099                                 /* .cctors: too many apps depend on them */
5100                                 /* running with a specific order... */
5101                                 if (! vtable->initialized)
5102                                         return FALSE;
5103                                 mono_runtime_class_init (vtable);
5104                         }
5105                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
5106                         if (!method->klass->runtime_info)
5107                                 /* No vtable created yet */
5108                                 return FALSE;
5109                         vtable = mono_class_vtable (cfg->domain, method->klass);
5110                         if (!vtable)
5111                                 return FALSE;
5112                         if (!vtable->initialized)
5113                                 return FALSE;
5114                 }
5115         } else {
5116                 /* 
5117                  * If we're compiling for shared code
5118                  * the cctor will need to be run at aot method load time, for example,
5119                  * or at the end of the compilation of the inlining method.
5120                  */
5121                 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
5122                         return FALSE;
5123         }
5124
5125         /*
5126          * CAS - do not inline methods with declarative security
5127          * Note: this has to be before any possible return TRUE;
5128          */
5129         if (mono_security_method_has_declsec (method))
5130                 return FALSE;
5131
5132 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5133         if (mono_arch_is_soft_float ()) {
5134                 /* FIXME: */
5135                 if (sig->ret && sig->ret->type == MONO_TYPE_R4)
5136                         return FALSE;
5137                 for (i = 0; i < sig->param_count; ++i)
5138                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4)
5139                                 return FALSE;
5140         }
5141 #endif
5142
5143         if (g_list_find (cfg->dont_inline, method))
5144                 return FALSE;
5145
5146         return TRUE;
5147 }
5148
5149 static gboolean
5150 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoClass *klass, MonoVTable *vtable)
5151 {
5152         if (!cfg->compile_aot) {
5153                 g_assert (vtable);
5154                 if (vtable->initialized)
5155                         return FALSE;
5156         }
5157
5158         if (klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5159                 if (cfg->method == method)
5160                         return FALSE;
5161         }
5162
5163         if (!mono_class_needs_cctor_run (klass, method))
5164                 return FALSE;
5165
5166         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (klass == method->klass))
5167                 /* The initialization is already done before the method is called */
5168                 return FALSE;
5169
5170         return TRUE;
5171 }
5172
5173 static MonoInst*
5174 mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck)
5175 {
5176         MonoInst *ins;
5177         guint32 size;
5178         int mult_reg, add_reg, array_reg, index_reg, index2_reg;
5179         int context_used;
5180
5181         if (mini_is_gsharedvt_variable_klass (cfg, klass)) {
5182                 size = -1;
5183         } else {
5184                 mono_class_init (klass);
5185                 size = mono_class_array_element_size (klass);
5186         }
5187
5188         mult_reg = alloc_preg (cfg);
5189         array_reg = arr->dreg;
5190         index_reg = index->dreg;
5191
5192 #if SIZEOF_REGISTER == 8
5193         /* The array reg is 64 bits but the index reg is only 32 */
5194         if (COMPILE_LLVM (cfg)) {
5195                 /* Not needed */
5196                 index2_reg = index_reg;
5197         } else {
5198                 index2_reg = alloc_preg (cfg);
5199                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
5200         }
5201 #else
5202         if (index->type == STACK_I8) {
5203                 index2_reg = alloc_preg (cfg);
5204                 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I4, index2_reg, index_reg);
5205         } else {
5206                 index2_reg = index_reg;
5207         }
5208 #endif
5209
5210         if (bcheck)
5211                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
5212
5213 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5214         if (size == 1 || size == 2 || size == 4 || size == 8) {
5215                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
5216
5217                 EMIT_NEW_X86_LEA (cfg, ins, array_reg, index2_reg, fast_log2 [size], MONO_STRUCT_OFFSET (MonoArray, vector));
5218                 ins->klass = mono_class_get_element_class (klass);
5219                 ins->type = STACK_MP;
5220
5221                 return ins;
5222         }
5223 #endif          
5224
5225         add_reg = alloc_ireg_mp (cfg);
5226
5227         if (size == -1) {
5228                 MonoInst *rgctx_ins;
5229
5230                 /* gsharedvt */
5231                 g_assert (cfg->generic_sharing_context);
5232                 context_used = mini_class_check_context_used (cfg, klass);
5233                 g_assert (context_used);
5234                 rgctx_ins = emit_get_gsharedvt_info (cfg, &klass->byval_arg, MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE);
5235                 MONO_EMIT_NEW_BIALU (cfg, OP_IMUL, mult_reg, index2_reg, rgctx_ins->dreg);
5236         } else {
5237                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
5238         }
5239         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg);
5240         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5241         ins->klass = mono_class_get_element_class (klass);
5242         ins->type = STACK_MP;
5243         MONO_ADD_INS (cfg->cbb, ins);
5244
5245         return ins;
5246 }
5247
5248 #ifndef MONO_ARCH_EMULATE_MUL_DIV
5249 static MonoInst*
5250 mini_emit_ldelema_2_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index_ins1, MonoInst *index_ins2)
5251 {
5252         int bounds_reg = alloc_preg (cfg);
5253         int add_reg = alloc_ireg_mp (cfg);
5254         int mult_reg = alloc_preg (cfg);
5255         int mult2_reg = alloc_preg (cfg);
5256         int low1_reg = alloc_preg (cfg);
5257         int low2_reg = alloc_preg (cfg);
5258         int high1_reg = alloc_preg (cfg);
5259         int high2_reg = alloc_preg (cfg);
5260         int realidx1_reg = alloc_preg (cfg);
5261         int realidx2_reg = alloc_preg (cfg);
5262         int sum_reg = alloc_preg (cfg);
5263         int index1, index2, tmpreg;
5264         MonoInst *ins;
5265         guint32 size;
5266
5267         mono_class_init (klass);
5268         size = mono_class_array_element_size (klass);
5269
5270         index1 = index_ins1->dreg;
5271         index2 = index_ins2->dreg;
5272
5273 #if SIZEOF_REGISTER == 8
5274         /* The array reg is 64 bits but the index reg is only 32 */
5275         if (COMPILE_LLVM (cfg)) {
5276                 /* Not needed */
5277         } else {
5278                 tmpreg = alloc_preg (cfg);
5279                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index1);
5280                 index1 = tmpreg;
5281                 tmpreg = alloc_preg (cfg);
5282                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index2);
5283                 index2 = tmpreg;
5284         }
5285 #else
5286         // FIXME: Do we need to do something here for i8 indexes, like in ldelema_1_ins ?
5287         tmpreg = -1;
5288 #endif
5289
5290         /* range checking */
5291         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, 
5292                                        arr->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5293
5294         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low1_reg, 
5295                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5296         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx1_reg, index1, low1_reg);
5297         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high1_reg, 
5298                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5299         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high1_reg, realidx1_reg);
5300         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5301
5302         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low2_reg, 
5303                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5304         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx2_reg, index2, low2_reg);
5305         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high2_reg, 
5306                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5307         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high2_reg, realidx2_reg);
5308         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5309
5310         MONO_EMIT_NEW_BIALU (cfg, OP_PMUL, mult_reg, high2_reg, realidx1_reg);
5311         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, mult_reg, realidx2_reg);
5312         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PMUL_IMM, mult2_reg, sum_reg, size);
5313         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult2_reg, arr->dreg);
5314         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5315
5316         ins->type = STACK_MP;
5317         ins->klass = klass;
5318         MONO_ADD_INS (cfg->cbb, ins);
5319
5320         return ins;
5321 }
5322 #endif
5323
5324 static MonoInst*
5325 mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
5326 {
5327         int rank;
5328         MonoInst *addr;
5329         MonoMethod *addr_method;
5330         int element_size;
5331         MonoClass *eclass = cmethod->klass->element_class;
5332
5333         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
5334
5335         if (rank == 1)
5336                 return mini_emit_ldelema_1_ins (cfg, eclass, sp [0], sp [1], TRUE);
5337
5338 #ifndef MONO_ARCH_EMULATE_MUL_DIV
5339         /* emit_ldelema_2 depends on OP_LMUL */
5340         if (rank == 2 && (cfg->opt & MONO_OPT_INTRINS) && !mini_is_gsharedvt_variable_klass (cfg, eclass)) {
5341                 return mini_emit_ldelema_2_ins (cfg, eclass, sp [0], sp [1], sp [2]);
5342         }
5343 #endif
5344
5345         if (mini_is_gsharedvt_variable_klass (cfg, eclass))
5346                 element_size = 0;
5347         else
5348                 element_size = mono_class_array_element_size (eclass);
5349         addr_method = mono_marshal_get_array_address (rank, element_size);
5350         addr = mono_emit_method_call (cfg, addr_method, sp, NULL);
5351
5352         return addr;
5353 }
5354
5355 static MonoBreakPolicy
5356 always_insert_breakpoint (MonoMethod *method)
5357 {
5358         return MONO_BREAK_POLICY_ALWAYS;
5359 }
5360
5361 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
5362
5363 /**
5364  * mono_set_break_policy:
5365  * policy_callback: the new callback function
5366  *
5367  * Allow embedders to decide wherther to actually obey breakpoint instructions
5368  * (both break IL instructions and Debugger.Break () method calls), for example
5369  * to not allow an app to be aborted by a perfectly valid IL opcode when executing
5370  * untrusted or semi-trusted code.
5371  *
5372  * @policy_callback will be called every time a break point instruction needs to
5373  * be inserted with the method argument being the method that calls Debugger.Break()
5374  * or has the IL break instruction. The callback should return #MONO_BREAK_POLICY_NEVER
5375  * if it wants the breakpoint to not be effective in the given method.
5376  * #MONO_BREAK_POLICY_ALWAYS is the default.
5377  */
5378 void
5379 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
5380 {
5381         if (policy_callback)
5382                 break_policy_func = policy_callback;
5383         else
5384                 break_policy_func = always_insert_breakpoint;
5385 }
5386
5387 static gboolean
5388 should_insert_brekpoint (MonoMethod *method) {
5389         switch (break_policy_func (method)) {
5390         case MONO_BREAK_POLICY_ALWAYS:
5391                 return TRUE;
5392         case MONO_BREAK_POLICY_NEVER:
5393                 return FALSE;
5394         case MONO_BREAK_POLICY_ON_DBG:
5395                 g_warning ("mdb no longer supported");
5396                 return FALSE;
5397         default:
5398                 g_warning ("Incorrect value returned from break policy callback");
5399                 return FALSE;
5400         }
5401 }
5402
5403 /* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */
5404 static MonoInst*
5405 emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5406 {
5407         MonoInst *addr, *store, *load;
5408         MonoClass *eklass = mono_class_from_mono_type (fsig->params [2]);
5409
5410         /* the bounds check is already done by the callers */
5411         addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5412         if (is_set) {
5413                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
5414                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
5415                 if (mini_type_is_reference (cfg, fsig->params [2]))
5416                         emit_write_barrier (cfg, addr, load);
5417         } else {
5418                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
5419                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
5420         }
5421         return store;
5422 }
5423
5424
5425 static gboolean
5426 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
5427 {
5428         return mini_type_is_reference (cfg, &klass->byval_arg);
5429 }
5430
5431 static MonoInst*
5432 emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboolean safety_checks)
5433 {
5434         if (safety_checks && generic_class_is_reference_type (cfg, klass) &&
5435                 !(sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL)) {
5436                 MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
5437                 MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
5438                 MonoInst *iargs [3];
5439
5440                 if (!helper->slot)
5441                         mono_class_setup_vtable (obj_array);
5442                 g_assert (helper->slot);
5443
5444                 if (sp [0]->type != STACK_OBJ)
5445                         return NULL;
5446                 if (sp [2]->type != STACK_OBJ)
5447                         return NULL;
5448
5449                 iargs [2] = sp [2];
5450                 iargs [1] = sp [1];
5451                 iargs [0] = sp [0];
5452
5453                 return mono_emit_method_call (cfg, helper, iargs, sp [0]);
5454         } else {
5455                 MonoInst *ins;
5456
5457                 if (mini_is_gsharedvt_variable_klass (cfg, klass)) {
5458                         MonoInst *addr;
5459
5460                         // FIXME-VT: OP_ICONST optimization
5461                         addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
5462                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5463                         ins->opcode = OP_STOREV_MEMBASE;
5464                 } else if (sp [1]->opcode == OP_ICONST) {
5465                         int array_reg = sp [0]->dreg;
5466                         int index_reg = sp [1]->dreg;
5467                         int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
5468
5469                         if (safety_checks)
5470                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
5471                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
5472                 } else {
5473                         MonoInst *addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], safety_checks);
5474                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5475                         if (generic_class_is_reference_type (cfg, klass))
5476                                 emit_write_barrier (cfg, addr, sp [2]);
5477                 }
5478                 return ins;
5479         }
5480 }
5481
5482 static MonoInst*
5483 emit_array_unsafe_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5484 {
5485         MonoClass *eklass;
5486         
5487         if (is_set)
5488                 eklass = mono_class_from_mono_type (fsig->params [2]);
5489         else
5490                 eklass = mono_class_from_mono_type (fsig->ret);
5491
5492         if (is_set) {
5493                 return emit_array_store (cfg, eklass, args, FALSE);
5494         } else {
5495                 MonoInst *ins, *addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5496                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &eklass->byval_arg, addr->dreg, 0);
5497                 return ins;
5498         }
5499 }
5500
5501 static gboolean
5502 is_unsafe_mov_compatible (MonoClass *param_klass, MonoClass *return_klass)
5503 {
5504         uint32_t align;
5505
5506         //Only allow for valuetypes
5507         if (!param_klass->valuetype || !return_klass->valuetype)
5508                 return FALSE;
5509
5510         //That are blitable
5511         if (param_klass->has_references || return_klass->has_references)
5512                 return FALSE;
5513
5514         /* Avoid mixing structs and primitive types/enums, they need to be handled differently in the JIT */
5515         if ((MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && !MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)) ||
5516                 (!MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)))
5517                 return FALSE;
5518
5519         if (param_klass->byval_arg.type == MONO_TYPE_R4 || param_klass->byval_arg.type == MONO_TYPE_R8 ||
5520                 return_klass->byval_arg.type == MONO_TYPE_R4 || return_klass->byval_arg.type == MONO_TYPE_R8)
5521                 return FALSE;
5522
5523         //And have the same size
5524         if (mono_class_value_size (param_klass, &align) != mono_class_value_size (return_klass, &align))
5525                 return FALSE;
5526         return TRUE;
5527 }
5528
5529 static MonoInst*
5530 emit_array_unsafe_mov (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args)
5531 {
5532         MonoClass *param_klass = mono_class_from_mono_type (fsig->params [0]);
5533         MonoClass *return_klass = mono_class_from_mono_type (fsig->ret);
5534
5535         //Valuetypes that are semantically equivalent
5536         if (is_unsafe_mov_compatible (param_klass, return_klass))
5537                 return args [0];
5538
5539         //Arrays of valuetypes that are semantically equivalent
5540         if (param_klass->rank == 1 && return_klass->rank == 1 && is_unsafe_mov_compatible (param_klass->element_class, return_klass->element_class))
5541                 return args [0];
5542
5543         return NULL;
5544 }
5545
5546 static MonoInst*
5547 mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5548 {
5549 #ifdef MONO_ARCH_SIMD_INTRINSICS
5550         MonoInst *ins = NULL;
5551
5552         if (cfg->opt & MONO_OPT_SIMD) {
5553                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5554                 if (ins)
5555                         return ins;
5556         }
5557 #endif
5558
5559         return mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
5560 }
5561
5562 static MonoInst*
5563 emit_memory_barrier (MonoCompile *cfg, int kind)
5564 {
5565         MonoInst *ins = NULL;
5566         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
5567         MONO_ADD_INS (cfg->cbb, ins);
5568         ins->backend.memory_barrier_kind = kind;
5569
5570         return ins;
5571 }
5572
5573 static MonoInst*
5574 llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5575 {
5576         MonoInst *ins = NULL;
5577         int opcode = 0;
5578
5579         /* The LLVM backend supports these intrinsics */
5580         if (cmethod->klass == mono_defaults.math_class) {
5581                 if (strcmp (cmethod->name, "Sin") == 0) {
5582                         opcode = OP_SIN;
5583                 } else if (strcmp (cmethod->name, "Cos") == 0) {
5584                         opcode = OP_COS;
5585                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
5586                         opcode = OP_SQRT;
5587                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
5588                         opcode = OP_ABS;
5589                 }
5590
5591                 if (opcode && fsig->param_count == 1) {
5592                         MONO_INST_NEW (cfg, ins, opcode);
5593                         ins->type = STACK_R8;
5594                         ins->dreg = mono_alloc_freg (cfg);
5595                         ins->sreg1 = args [0]->dreg;
5596                         MONO_ADD_INS (cfg->cbb, ins);
5597                 }
5598
5599                 opcode = 0;
5600                 if (cfg->opt & MONO_OPT_CMOV) {
5601                         if (strcmp (cmethod->name, "Min") == 0) {
5602                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5603                                         opcode = OP_IMIN;
5604                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5605                                         opcode = OP_IMIN_UN;
5606                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5607                                         opcode = OP_LMIN;
5608                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5609                                         opcode = OP_LMIN_UN;
5610                         } else if (strcmp (cmethod->name, "Max") == 0) {
5611                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5612                                         opcode = OP_IMAX;
5613                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5614                                         opcode = OP_IMAX_UN;
5615                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5616                                         opcode = OP_LMAX;
5617                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5618                                         opcode = OP_LMAX_UN;
5619                         }
5620                 }
5621
5622                 if (opcode && fsig->param_count == 2) {
5623                         MONO_INST_NEW (cfg, ins, opcode);
5624                         ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
5625                         ins->dreg = mono_alloc_ireg (cfg);
5626                         ins->sreg1 = args [0]->dreg;
5627                         ins->sreg2 = args [1]->dreg;
5628                         MONO_ADD_INS (cfg->cbb, ins);
5629                 }
5630         }
5631
5632         return ins;
5633 }
5634
5635 static MonoInst*
5636 mini_emit_inst_for_sharable_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5637 {
5638         if (cmethod->klass == mono_defaults.array_class) {
5639                 if (strcmp (cmethod->name, "UnsafeStore") == 0)
5640                         return emit_array_unsafe_access (cfg, fsig, args, TRUE);
5641                 else if (strcmp (cmethod->name, "UnsafeLoad") == 0)
5642                         return emit_array_unsafe_access (cfg, fsig, args, FALSE);
5643                 else if (strcmp (cmethod->name, "UnsafeMov") == 0)
5644                         return emit_array_unsafe_mov (cfg, fsig, args);
5645         }
5646
5647         return NULL;
5648 }
5649
5650 static MonoInst*
5651 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5652 {
5653         MonoInst *ins = NULL;
5654         
5655         static MonoClass *runtime_helpers_class = NULL;
5656         if (! runtime_helpers_class)
5657                 runtime_helpers_class = mono_class_from_name (mono_defaults.corlib,
5658                         "System.Runtime.CompilerServices", "RuntimeHelpers");
5659
5660         if (cmethod->klass == mono_defaults.string_class) {
5661                 if (strcmp (cmethod->name, "get_Chars") == 0 && fsig->param_count == 2) {
5662                         int dreg = alloc_ireg (cfg);
5663                         int index_reg = alloc_preg (cfg);
5664                         int mult_reg = alloc_preg (cfg);
5665                         int add_reg = alloc_preg (cfg);
5666
5667 #if SIZEOF_REGISTER == 8
5668                         /* The array reg is 64 bits but the index reg is only 32 */
5669                         MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index_reg, args [1]->dreg);
5670 #else
5671                         index_reg = args [1]->dreg;
5672 #endif  
5673                         MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
5674
5675 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5676                         EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, MONO_STRUCT_OFFSET (MonoString, chars));
5677                         add_reg = ins->dreg;
5678                         /* Avoid a warning */
5679                         mult_reg = 0;
5680                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5681                                                                    add_reg, 0);
5682 #else
5683                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1);
5684                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5685                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5686                                                                    add_reg, MONO_STRUCT_OFFSET (MonoString, chars));
5687 #endif
5688                         type_from_op (cfg, ins, NULL, NULL);
5689                         return ins;
5690                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count == 1) {
5691                         int dreg = alloc_ireg (cfg);
5692                         /* Decompose later to allow more optimizations */
5693                         EMIT_NEW_UNALU (cfg, ins, OP_STRLEN, dreg, args [0]->dreg);
5694                         ins->type = STACK_I4;
5695                         ins->flags |= MONO_INST_FAULT;
5696                         cfg->cbb->has_array_access = TRUE;
5697                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
5698
5699                         return ins;
5700                 } else if (strcmp (cmethod->name, "InternalSetChar") == 0 && fsig->param_count == 3) {
5701                         int mult_reg = alloc_preg (cfg);
5702                         int add_reg = alloc_preg (cfg);
5703
5704                         /* The corlib functions check for oob already. */
5705                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, args [1]->dreg, 1);
5706                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5707                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, add_reg, MONO_STRUCT_OFFSET (MonoString, chars), args [2]->dreg);
5708                         return cfg->cbb->last_ins;
5709                 } else 
5710                         return NULL;
5711         } else if (cmethod->klass == mono_defaults.object_class) {
5712
5713                 if (strcmp (cmethod->name, "GetType") == 0 && fsig->param_count == 1) {
5714                         int dreg = alloc_ireg_ref (cfg);
5715                         int vt_reg = alloc_preg (cfg);
5716                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
5717                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, MONO_STRUCT_OFFSET (MonoVTable, type));
5718                         type_from_op (cfg, ins, NULL, NULL);
5719
5720                         return ins;
5721 #if !defined(MONO_ARCH_EMULATE_MUL_DIV)
5722                 } else if (strcmp (cmethod->name, "InternalGetHashCode") == 0 && fsig->param_count == 1 && !mono_gc_is_moving ()) {
5723                         int dreg = alloc_ireg (cfg);
5724                         int t1 = alloc_ireg (cfg);
5725         
5726                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, t1, args [0]->dreg, 3);
5727                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_MUL_IMM, dreg, t1, 2654435761u);
5728                         ins->type = STACK_I4;
5729
5730                         return ins;
5731 #endif
5732                 } else if (strcmp (cmethod->name, ".ctor") == 0 && fsig->param_count == 0) {
5733                         MONO_INST_NEW (cfg, ins, OP_NOP);
5734                         MONO_ADD_INS (cfg->cbb, ins);
5735                         return ins;
5736                 } else
5737                         return NULL;
5738         } else if (cmethod->klass == mono_defaults.array_class) {
5739                 if (strcmp (cmethod->name, "GetGenericValueImpl") == 0 && fsig->param_count == 3 && !cfg->gsharedvt)
5740                         return emit_array_generic_access (cfg, fsig, args, FALSE);
5741                 else if (strcmp (cmethod->name, "SetGenericValueImpl") == 0 && fsig->param_count == 3 && !cfg->gsharedvt)
5742                         return emit_array_generic_access (cfg, fsig, args, TRUE);
5743
5744 #ifndef MONO_BIG_ARRAYS
5745                 /*
5746                  * This is an inline version of GetLength/GetLowerBound(0) used frequently in
5747                  * Array methods.
5748                  */
5749                 else if (((strcmp (cmethod->name, "GetLength") == 0 && fsig->param_count == 2) ||
5750                          (strcmp (cmethod->name, "GetLowerBound") == 0 && fsig->param_count == 2)) &&
5751                          args [1]->opcode == OP_ICONST && args [1]->inst_c0 == 0) {
5752                         int dreg = alloc_ireg (cfg);
5753                         int bounds_reg = alloc_ireg_mp (cfg);
5754                         MonoBasicBlock *end_bb, *szarray_bb;
5755                         gboolean get_length = strcmp (cmethod->name, "GetLength") == 0;
5756
5757                         NEW_BBLOCK (cfg, end_bb);
5758                         NEW_BBLOCK (cfg, szarray_bb);
5759
5760                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOAD_MEMBASE, bounds_reg,
5761                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5762                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
5763                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, szarray_bb);
5764                         /* Non-szarray case */
5765                         if (get_length)
5766                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5767                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5768                         else
5769                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5770                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5771                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
5772                         MONO_START_BB (cfg, szarray_bb);
5773                         /* Szarray case */
5774                         if (get_length)
5775                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5776                                                                            args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
5777                         else
5778                                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
5779                         MONO_START_BB (cfg, end_bb);
5780
5781                         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, dreg, dreg);
5782                         ins->type = STACK_I4;
5783                         
5784                         return ins;
5785                 }
5786 #endif
5787
5788                 if (cmethod->name [0] != 'g')
5789                         return NULL;
5790
5791                 if (strcmp (cmethod->name, "get_Rank") == 0 && fsig->param_count == 1) {
5792                         int dreg = alloc_ireg (cfg);
5793                         int vtable_reg = alloc_preg (cfg);
5794                         MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, 
5795                                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
5796                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
5797                                                                    vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
5798                         type_from_op (cfg, ins, NULL, NULL);
5799
5800                         return ins;
5801                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count == 1) {
5802                         int dreg = alloc_ireg (cfg);
5803
5804                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
5805                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
5806                         type_from_op (cfg, ins, NULL, NULL);
5807
5808                         return ins;
5809                 } else
5810                         return NULL;
5811         } else if (cmethod->klass == runtime_helpers_class) {
5812
5813                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0 && fsig->param_count == 0) {
5814                         EMIT_NEW_ICONST (cfg, ins, MONO_STRUCT_OFFSET (MonoString, chars));
5815                         return ins;
5816                 } else
5817                         return NULL;
5818         } else if (cmethod->klass == mono_defaults.thread_class) {
5819                 if (strcmp (cmethod->name, "SpinWait_nop") == 0 && fsig->param_count == 0) {
5820                         MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
5821                         MONO_ADD_INS (cfg->cbb, ins);
5822                         return ins;
5823                 } else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0) {
5824                         return emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5825                 } else if (!strcmp (cmethod->name, "VolatileRead") && fsig->param_count == 1) {
5826                         guint32 opcode = 0;
5827                         gboolean is_ref = mini_type_is_reference (cfg, fsig->params [0]);
5828
5829                         if (fsig->params [0]->type == MONO_TYPE_I1)
5830                                 opcode = OP_LOADI1_MEMBASE;
5831                         else if (fsig->params [0]->type == MONO_TYPE_U1)
5832                                 opcode = OP_LOADU1_MEMBASE;
5833                         else if (fsig->params [0]->type == MONO_TYPE_I2)
5834                                 opcode = OP_LOADI2_MEMBASE;
5835                         else if (fsig->params [0]->type == MONO_TYPE_U2)
5836                                 opcode = OP_LOADU2_MEMBASE;
5837                         else if (fsig->params [0]->type == MONO_TYPE_I4)
5838                                 opcode = OP_LOADI4_MEMBASE;
5839                         else if (fsig->params [0]->type == MONO_TYPE_U4)
5840                                 opcode = OP_LOADU4_MEMBASE;
5841                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
5842                                 opcode = OP_LOADI8_MEMBASE;
5843                         else if (fsig->params [0]->type == MONO_TYPE_R4)
5844                                 opcode = OP_LOADR4_MEMBASE;
5845                         else if (fsig->params [0]->type == MONO_TYPE_R8)
5846                                 opcode = OP_LOADR8_MEMBASE;
5847                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
5848                                 opcode = OP_LOAD_MEMBASE;
5849
5850                         if (opcode) {
5851                                 MONO_INST_NEW (cfg, ins, opcode);
5852                                 ins->inst_basereg = args [0]->dreg;
5853                                 ins->inst_offset = 0;
5854                                 MONO_ADD_INS (cfg->cbb, ins);
5855
5856                                 switch (fsig->params [0]->type) {
5857                                 case MONO_TYPE_I1:
5858                                 case MONO_TYPE_U1:
5859                                 case MONO_TYPE_I2:
5860                                 case MONO_TYPE_U2:
5861                                 case MONO_TYPE_I4:
5862                                 case MONO_TYPE_U4:
5863                                         ins->dreg = mono_alloc_ireg (cfg);
5864                                         ins->type = STACK_I4;
5865                                         break;
5866                                 case MONO_TYPE_I8:
5867                                 case MONO_TYPE_U8:
5868                                         ins->dreg = mono_alloc_lreg (cfg);
5869                                         ins->type = STACK_I8;
5870                                         break;
5871                                 case MONO_TYPE_I:
5872                                 case MONO_TYPE_U:
5873                                         ins->dreg = mono_alloc_ireg (cfg);
5874 #if SIZEOF_REGISTER == 8
5875                                         ins->type = STACK_I8;
5876 #else
5877                                         ins->type = STACK_I4;
5878 #endif
5879                                         break;
5880                                 case MONO_TYPE_R4:
5881                                 case MONO_TYPE_R8:
5882                                         ins->dreg = mono_alloc_freg (cfg);
5883                                         ins->type = STACK_R8;
5884                                         break;
5885                                 default:
5886                                         g_assert (mini_type_is_reference (cfg, fsig->params [0]));
5887                                         ins->dreg = mono_alloc_ireg_ref (cfg);
5888                                         ins->type = STACK_OBJ;
5889                                         break;
5890                                 }
5891
5892                                 if (opcode == OP_LOADI8_MEMBASE)
5893                                         ins = mono_decompose_opcode (cfg, ins, NULL);
5894
5895                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
5896
5897                                 return ins;
5898                         }
5899                 } else if (!strcmp (cmethod->name, "VolatileWrite") && fsig->param_count == 2) {
5900                         guint32 opcode = 0;
5901                         gboolean is_ref = mini_type_is_reference (cfg, fsig->params [0]);
5902
5903                         if (fsig->params [0]->type == MONO_TYPE_I1 || fsig->params [0]->type == MONO_TYPE_U1)
5904                                 opcode = OP_STOREI1_MEMBASE_REG;
5905                         else if (fsig->params [0]->type == MONO_TYPE_I2 || fsig->params [0]->type == MONO_TYPE_U2)
5906                                 opcode = OP_STOREI2_MEMBASE_REG;
5907                         else if (fsig->params [0]->type == MONO_TYPE_I4 || fsig->params [0]->type == MONO_TYPE_U4)
5908                                 opcode = OP_STOREI4_MEMBASE_REG;
5909                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
5910                                 opcode = OP_STOREI8_MEMBASE_REG;
5911                         else if (fsig->params [0]->type == MONO_TYPE_R4)
5912                                 opcode = OP_STORER4_MEMBASE_REG;
5913                         else if (fsig->params [0]->type == MONO_TYPE_R8)
5914                                 opcode = OP_STORER8_MEMBASE_REG;
5915                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
5916                                 opcode = OP_STORE_MEMBASE_REG;
5917
5918                         if (opcode) {
5919                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
5920
5921                                 MONO_INST_NEW (cfg, ins, opcode);
5922                                 ins->sreg1 = args [1]->dreg;
5923                                 ins->inst_destbasereg = args [0]->dreg;
5924                                 ins->inst_offset = 0;
5925                                 MONO_ADD_INS (cfg->cbb, ins);
5926
5927                                 if (opcode == OP_STOREI8_MEMBASE_REG)
5928                                         ins = mono_decompose_opcode (cfg, ins, NULL);
5929
5930                                 return ins;
5931                         }
5932                 }
5933         } else if (cmethod->klass == mono_defaults.monitor_class) {
5934 #if defined(MONO_ARCH_MONITOR_OBJECT_REG)
5935                 if (strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 1) {
5936                         MonoCallInst *call;
5937
5938                         if (COMPILE_LLVM (cfg)) {
5939                                 /* 
5940                                  * Pass the argument normally, the LLVM backend will handle the
5941                                  * calling convention problems.
5942                                  */
5943                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER, NULL, helper_sig_monitor_enter_exit_trampoline_llvm, args);
5944                         } else {
5945                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER,
5946                                             NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
5947                                 mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg,
5948                                                                                            MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
5949                         }
5950
5951                         return (MonoInst*)call;
5952 #if defined(MONO_ARCH_MONITOR_LOCK_TAKEN_REG)
5953                 } else if (strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 2) {
5954                         MonoCallInst *call;
5955
5956                         if (COMPILE_LLVM (cfg)) {
5957                                 /*
5958                                  * Pass the argument normally, the LLVM backend will handle the
5959                                  * calling convention problems.
5960                                  */
5961                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER_V4, NULL, helper_sig_monitor_enter_v4_trampoline_llvm, args);
5962                         } else {
5963                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER_V4,
5964                                             NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
5965                                 mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg, MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
5966                                 mono_call_inst_add_outarg_reg (cfg, call, args [1]->dreg, MONO_ARCH_MONITOR_LOCK_TAKEN_REG, FALSE);
5967                         }
5968
5969                         return (MonoInst*)call;
5970 #endif
5971                 } else if (strcmp (cmethod->name, "Exit") == 0 && fsig->param_count == 1) {
5972                         MonoCallInst *call;
5973
5974                         if (COMPILE_LLVM (cfg)) {
5975                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_EXIT, NULL, helper_sig_monitor_enter_exit_trampoline_llvm, args);
5976                         } else {
5977                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_EXIT,
5978                                             NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
5979                                 mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg,
5980                                                                                            MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
5981                         }
5982
5983                         return (MonoInst*)call;
5984                 }
5985 #endif
5986         } else if (cmethod->klass->image == mono_defaults.corlib &&
5987                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
5988                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
5989                 ins = NULL;
5990
5991 #if SIZEOF_REGISTER == 8
5992                 if (strcmp (cmethod->name, "Read") == 0 && fsig->param_count == 1 && (fsig->params [0]->type == MONO_TYPE_I8)) {
5993                         if (mono_arch_opcode_supported (OP_ATOMIC_LOAD_I8)) {
5994                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_LOAD_I8);
5995                                 ins->dreg = mono_alloc_preg (cfg);
5996                                 ins->sreg1 = args [0]->dreg;
5997                                 ins->type = STACK_I8;
5998                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_SEQ;
5999                                 MONO_ADD_INS (cfg->cbb, ins);
6000                         } else {
6001                                 MonoInst *load_ins;
6002
6003                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6004
6005                                 /* 64 bit reads are already atomic */
6006                                 MONO_INST_NEW (cfg, load_ins, OP_LOADI8_MEMBASE);
6007                                 load_ins->dreg = mono_alloc_preg (cfg);
6008                                 load_ins->inst_basereg = args [0]->dreg;
6009                                 load_ins->inst_offset = 0;
6010                                 load_ins->type = STACK_I8;
6011                                 MONO_ADD_INS (cfg->cbb, load_ins);
6012
6013                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6014
6015                                 ins = load_ins;
6016                         }
6017                 }
6018 #endif
6019
6020                 if (strcmp (cmethod->name, "Increment") == 0 && fsig->param_count == 1) {
6021                         MonoInst *ins_iconst;
6022                         guint32 opcode = 0;
6023
6024                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6025                                 opcode = OP_ATOMIC_ADD_I4;
6026                                 cfg->has_atomic_add_i4 = TRUE;
6027                         }
6028 #if SIZEOF_REGISTER == 8
6029                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6030                                 opcode = OP_ATOMIC_ADD_I8;
6031 #endif
6032                         if (opcode) {
6033                                 if (!mono_arch_opcode_supported (opcode))
6034                                         return NULL;
6035                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6036                                 ins_iconst->inst_c0 = 1;
6037                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6038                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6039
6040                                 MONO_INST_NEW (cfg, ins, opcode);
6041                                 ins->dreg = mono_alloc_ireg (cfg);
6042                                 ins->inst_basereg = args [0]->dreg;
6043                                 ins->inst_offset = 0;
6044                                 ins->sreg2 = ins_iconst->dreg;
6045                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6046                                 MONO_ADD_INS (cfg->cbb, ins);
6047                         }
6048                 } else if (strcmp (cmethod->name, "Decrement") == 0 && fsig->param_count == 1) {
6049                         MonoInst *ins_iconst;
6050                         guint32 opcode = 0;
6051
6052                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6053                                 opcode = OP_ATOMIC_ADD_I4;
6054                                 cfg->has_atomic_add_i4 = TRUE;
6055                         }
6056 #if SIZEOF_REGISTER == 8
6057                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6058                                 opcode = OP_ATOMIC_ADD_I8;
6059 #endif
6060                         if (opcode) {
6061                                 if (!mono_arch_opcode_supported (opcode))
6062                                         return NULL;
6063                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6064                                 ins_iconst->inst_c0 = -1;
6065                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6066                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6067
6068                                 MONO_INST_NEW (cfg, ins, opcode);
6069                                 ins->dreg = mono_alloc_ireg (cfg);
6070                                 ins->inst_basereg = args [0]->dreg;
6071                                 ins->inst_offset = 0;
6072                                 ins->sreg2 = ins_iconst->dreg;
6073                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6074                                 MONO_ADD_INS (cfg->cbb, ins);
6075                         }
6076                 } else if (strcmp (cmethod->name, "Add") == 0 && fsig->param_count == 2) {
6077                         guint32 opcode = 0;
6078
6079                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6080                                 opcode = OP_ATOMIC_ADD_I4;
6081                                 cfg->has_atomic_add_i4 = TRUE;
6082                         }
6083 #if SIZEOF_REGISTER == 8
6084                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6085                                 opcode = OP_ATOMIC_ADD_I8;
6086 #endif
6087                         if (opcode) {
6088                                 if (!mono_arch_opcode_supported (opcode))
6089                                         return NULL;
6090                                 MONO_INST_NEW (cfg, ins, opcode);
6091                                 ins->dreg = mono_alloc_ireg (cfg);
6092                                 ins->inst_basereg = args [0]->dreg;
6093                                 ins->inst_offset = 0;
6094                                 ins->sreg2 = args [1]->dreg;
6095                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6096                                 MONO_ADD_INS (cfg->cbb, ins);
6097                         }
6098                 }
6099                 else if (strcmp (cmethod->name, "Exchange") == 0 && fsig->param_count == 2) {
6100                         MonoInst *f2i = NULL, *i2f;
6101                         guint32 opcode, f2i_opcode, i2f_opcode;
6102                         gboolean is_ref = mini_type_is_reference (cfg, fsig->params [0]);
6103                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
6104
6105                         if (fsig->params [0]->type == MONO_TYPE_I4 ||
6106                             fsig->params [0]->type == MONO_TYPE_R4) {
6107                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6108                                 f2i_opcode = OP_MOVE_F_TO_I4;
6109                                 i2f_opcode = OP_MOVE_I4_TO_F;
6110                                 cfg->has_atomic_exchange_i4 = TRUE;
6111                         }
6112 #if SIZEOF_REGISTER == 8
6113                         else if (is_ref ||
6114                                  fsig->params [0]->type == MONO_TYPE_I8 ||
6115                                  fsig->params [0]->type == MONO_TYPE_R8 ||
6116                                  fsig->params [0]->type == MONO_TYPE_I) {
6117                                 opcode = OP_ATOMIC_EXCHANGE_I8;
6118                                 f2i_opcode = OP_MOVE_F_TO_I8;
6119                                 i2f_opcode = OP_MOVE_I8_TO_F;
6120                         }
6121 #else
6122                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I) {
6123                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6124                                 cfg->has_atomic_exchange_i4 = TRUE;
6125                         }
6126 #endif
6127                         else
6128                                 return NULL;
6129
6130                         if (!mono_arch_opcode_supported (opcode))
6131                                 return NULL;
6132
6133                         if (is_float) {
6134                                 /* TODO: Decompose these opcodes instead of bailing here. */
6135                                 if (COMPILE_SOFT_FLOAT (cfg))
6136                                         return NULL;
6137
6138                                 MONO_INST_NEW (cfg, f2i, f2i_opcode);
6139                                 f2i->dreg = mono_alloc_ireg (cfg);
6140                                 f2i->sreg1 = args [1]->dreg;
6141                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6142                                         f2i->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6143                                 MONO_ADD_INS (cfg->cbb, f2i);
6144                         }
6145
6146                         MONO_INST_NEW (cfg, ins, opcode);
6147                         ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : mono_alloc_ireg (cfg);
6148                         ins->inst_basereg = args [0]->dreg;
6149                         ins->inst_offset = 0;
6150                         ins->sreg2 = is_float ? f2i->dreg : args [1]->dreg;
6151                         MONO_ADD_INS (cfg->cbb, ins);
6152
6153                         switch (fsig->params [0]->type) {
6154                         case MONO_TYPE_I4:
6155                                 ins->type = STACK_I4;
6156                                 break;
6157                         case MONO_TYPE_I8:
6158                                 ins->type = STACK_I8;
6159                                 break;
6160                         case MONO_TYPE_I:
6161 #if SIZEOF_REGISTER == 8
6162                                 ins->type = STACK_I8;
6163 #else
6164                                 ins->type = STACK_I4;
6165 #endif
6166                                 break;
6167                         case MONO_TYPE_R4:
6168                         case MONO_TYPE_R8:
6169                                 ins->type = STACK_R8;
6170                                 break;
6171                         default:
6172                                 g_assert (mini_type_is_reference (cfg, fsig->params [0]));
6173                                 ins->type = STACK_OBJ;
6174                                 break;
6175                         }
6176
6177                         if (is_float) {
6178                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6179                                 i2f->dreg = mono_alloc_freg (cfg);
6180                                 i2f->sreg1 = ins->dreg;
6181                                 i2f->type = STACK_R8;
6182                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6183                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6184                                 MONO_ADD_INS (cfg->cbb, i2f);
6185
6186                                 ins = i2f;
6187                         }
6188
6189                         if (cfg->gen_write_barriers && is_ref)
6190                                 emit_write_barrier (cfg, args [0], args [1]);
6191                 }
6192                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 3) {
6193                         MonoInst *f2i_new = NULL, *f2i_cmp = NULL, *i2f;
6194                         guint32 opcode, f2i_opcode, i2f_opcode;
6195                         gboolean is_ref = mini_type_is_reference (cfg, fsig->params [1]);
6196                         gboolean is_float = fsig->params [1]->type == MONO_TYPE_R4 || fsig->params [1]->type == MONO_TYPE_R8;
6197
6198                         if (fsig->params [1]->type == MONO_TYPE_I4 ||
6199                             fsig->params [1]->type == MONO_TYPE_R4) {
6200                                 opcode = OP_ATOMIC_CAS_I4;
6201                                 f2i_opcode = OP_MOVE_F_TO_I4;
6202                                 i2f_opcode = OP_MOVE_I4_TO_F;
6203                                 cfg->has_atomic_cas_i4 = TRUE;
6204                         }
6205 #if SIZEOF_REGISTER == 8
6206                         else if (is_ref ||
6207                                  fsig->params [1]->type == MONO_TYPE_I8 ||
6208                                  fsig->params [1]->type == MONO_TYPE_R8 ||
6209                                  fsig->params [1]->type == MONO_TYPE_I) {
6210                                 opcode = OP_ATOMIC_CAS_I8;
6211                                 f2i_opcode = OP_MOVE_F_TO_I8;
6212                                 i2f_opcode = OP_MOVE_I8_TO_F;
6213                         }
6214 #else
6215                         else if (is_ref || fsig->params [1]->type == MONO_TYPE_I) {
6216                                 opcode = OP_ATOMIC_CAS_I4;
6217                                 cfg->has_atomic_cas_i4 = TRUE;
6218                         }
6219 #endif
6220                         else
6221                                 return NULL;
6222
6223                         if (!mono_arch_opcode_supported (opcode))
6224                                 return NULL;
6225
6226                         if (is_float) {
6227                                 /* TODO: Decompose these opcodes instead of bailing here. */
6228                                 if (COMPILE_SOFT_FLOAT (cfg))
6229                                         return NULL;
6230
6231                                 MONO_INST_NEW (cfg, f2i_new, f2i_opcode);
6232                                 f2i_new->dreg = mono_alloc_ireg (cfg);
6233                                 f2i_new->sreg1 = args [1]->dreg;
6234                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6235                                         f2i_new->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6236                                 MONO_ADD_INS (cfg->cbb, f2i_new);
6237
6238                                 MONO_INST_NEW (cfg, f2i_cmp, f2i_opcode);
6239                                 f2i_cmp->dreg = mono_alloc_ireg (cfg);
6240                                 f2i_cmp->sreg1 = args [2]->dreg;
6241                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6242                                         f2i_cmp->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6243                                 MONO_ADD_INS (cfg->cbb, f2i_cmp);
6244                         }
6245
6246                         MONO_INST_NEW (cfg, ins, opcode);
6247                         ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
6248                         ins->sreg1 = args [0]->dreg;
6249                         ins->sreg2 = is_float ? f2i_new->dreg : args [1]->dreg;
6250                         ins->sreg3 = is_float ? f2i_cmp->dreg : args [2]->dreg;
6251                         MONO_ADD_INS (cfg->cbb, ins);
6252
6253                         switch (fsig->params [0]->type) {
6254                         case MONO_TYPE_I4:
6255                                 ins->type = STACK_I4;
6256                                 break;
6257                         case MONO_TYPE_I8:
6258                                 ins->type = STACK_I8;
6259                                 break;
6260                         case MONO_TYPE_I:
6261 #if SIZEOF_REGISTER == 8
6262                                 ins->type = STACK_I8;
6263 #else
6264                                 ins->type = STACK_I4;
6265 #endif
6266                                 break;
6267                         case MONO_TYPE_R4:
6268                         case MONO_TYPE_R8:
6269                                 ins->type = STACK_R8;
6270                                 break;
6271                         default:
6272                                 g_assert (mini_type_is_reference (cfg, fsig->params [0]));
6273                                 ins->type = STACK_OBJ;
6274                                 break;
6275                         }
6276
6277                         if (is_float) {
6278                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6279                                 i2f->dreg = mono_alloc_freg (cfg);
6280                                 i2f->sreg1 = ins->dreg;
6281                                 i2f->type = STACK_R8;
6282                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6283                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6284                                 MONO_ADD_INS (cfg->cbb, i2f);
6285
6286                                 ins = i2f;
6287                         }
6288
6289                         if (cfg->gen_write_barriers && is_ref)
6290                                 emit_write_barrier (cfg, args [0], args [1]);
6291                 }
6292                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 4 &&
6293                          fsig->params [1]->type == MONO_TYPE_I4) {
6294                         MonoInst *cmp, *ceq;
6295
6296                         if (!mono_arch_opcode_supported (OP_ATOMIC_CAS_I4))
6297                                 return NULL;
6298
6299                         /* int32 r = CAS (location, value, comparand); */
6300                         MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
6301                         ins->dreg = alloc_ireg (cfg);
6302                         ins->sreg1 = args [0]->dreg;
6303                         ins->sreg2 = args [1]->dreg;
6304                         ins->sreg3 = args [2]->dreg;
6305                         ins->type = STACK_I4;
6306                         MONO_ADD_INS (cfg->cbb, ins);
6307
6308                         /* bool result = r == comparand; */
6309                         MONO_INST_NEW (cfg, cmp, OP_ICOMPARE);
6310                         cmp->sreg1 = ins->dreg;
6311                         cmp->sreg2 = args [2]->dreg;
6312                         cmp->type = STACK_I4;
6313                         MONO_ADD_INS (cfg->cbb, cmp);
6314
6315                         MONO_INST_NEW (cfg, ceq, OP_ICEQ);
6316                         ceq->dreg = alloc_ireg (cfg);
6317                         ceq->type = STACK_I4;
6318                         MONO_ADD_INS (cfg->cbb, ceq);
6319
6320                         /* *success = result; */
6321                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, args [3]->dreg, 0, ceq->dreg);
6322
6323                         cfg->has_atomic_cas_i4 = TRUE;
6324                 }
6325                 else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0)
6326                         ins = emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6327
6328                 if (ins)
6329                         return ins;
6330         } else if (cmethod->klass->image == mono_defaults.corlib &&
6331                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6332                            (strcmp (cmethod->klass->name, "Volatile") == 0)) {
6333                 ins = NULL;
6334
6335                 if (!strcmp (cmethod->name, "Read") && fsig->param_count == 1) {
6336                         guint32 opcode = 0;
6337                         gboolean is_ref = mini_type_is_reference (cfg, fsig->params [0]);
6338                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
6339
6340                         if (fsig->params [0]->type == MONO_TYPE_I1)
6341                                 opcode = OP_ATOMIC_LOAD_I1;
6342                         else if (fsig->params [0]->type == MONO_TYPE_U1 || fsig->params [0]->type == MONO_TYPE_BOOLEAN)
6343                                 opcode = OP_ATOMIC_LOAD_U1;
6344                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6345                                 opcode = OP_ATOMIC_LOAD_I2;
6346                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6347                                 opcode = OP_ATOMIC_LOAD_U2;
6348                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6349                                 opcode = OP_ATOMIC_LOAD_I4;
6350                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6351                                 opcode = OP_ATOMIC_LOAD_U4;
6352                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6353                                 opcode = OP_ATOMIC_LOAD_R4;
6354                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6355                                 opcode = OP_ATOMIC_LOAD_R8;
6356 #if SIZEOF_REGISTER == 8
6357                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_I)
6358                                 opcode = OP_ATOMIC_LOAD_I8;
6359                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U8 || fsig->params [0]->type == MONO_TYPE_U)
6360                                 opcode = OP_ATOMIC_LOAD_U8;
6361 #else
6362                         else if (fsig->params [0]->type == MONO_TYPE_I)
6363                                 opcode = OP_ATOMIC_LOAD_I4;
6364                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U)
6365                                 opcode = OP_ATOMIC_LOAD_U4;
6366 #endif
6367
6368                         if (opcode) {
6369                                 if (!mono_arch_opcode_supported (opcode))
6370                                         return NULL;
6371
6372                                 MONO_INST_NEW (cfg, ins, opcode);
6373                                 ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : (is_float ? mono_alloc_freg (cfg) : mono_alloc_ireg (cfg));
6374                                 ins->sreg1 = args [0]->dreg;
6375                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_ACQ;
6376                                 MONO_ADD_INS (cfg->cbb, ins);
6377
6378                                 switch (fsig->params [0]->type) {
6379                                 case MONO_TYPE_BOOLEAN:
6380                                 case MONO_TYPE_I1:
6381                                 case MONO_TYPE_U1:
6382                                 case MONO_TYPE_I2:
6383                                 case MONO_TYPE_U2:
6384                                 case MONO_TYPE_I4:
6385                                 case MONO_TYPE_U4:
6386                                         ins->type = STACK_I4;
6387                                         break;
6388                                 case MONO_TYPE_I8:
6389                                 case MONO_TYPE_U8:
6390                                         ins->type = STACK_I8;
6391                                         break;
6392                                 case MONO_TYPE_I:
6393                                 case MONO_TYPE_U:
6394 #if SIZEOF_REGISTER == 8
6395                                         ins->type = STACK_I8;
6396 #else
6397                                         ins->type = STACK_I4;
6398 #endif
6399                                         break;
6400                                 case MONO_TYPE_R4:
6401                                 case MONO_TYPE_R8:
6402                                         ins->type = STACK_R8;
6403                                         break;
6404                                 default:
6405                                         g_assert (mini_type_is_reference (cfg, fsig->params [0]));
6406                                         ins->type = STACK_OBJ;
6407                                         break;
6408                                 }
6409                         }
6410                 }
6411
6412                 if (!strcmp (cmethod->name, "Write") && fsig->param_count == 2) {
6413                         guint32 opcode = 0;
6414                         gboolean is_ref = mini_type_is_reference (cfg, fsig->params [0]);
6415
6416                         if (fsig->params [0]->type == MONO_TYPE_I1)
6417                                 opcode = OP_ATOMIC_STORE_I1;
6418                         else if (fsig->params [0]->type == MONO_TYPE_U1 || fsig->params [0]->type == MONO_TYPE_BOOLEAN)
6419                                 opcode = OP_ATOMIC_STORE_U1;
6420                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6421                                 opcode = OP_ATOMIC_STORE_I2;
6422                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6423                                 opcode = OP_ATOMIC_STORE_U2;
6424                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6425                                 opcode = OP_ATOMIC_STORE_I4;
6426                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6427                                 opcode = OP_ATOMIC_STORE_U4;
6428                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6429                                 opcode = OP_ATOMIC_STORE_R4;
6430                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6431                                 opcode = OP_ATOMIC_STORE_R8;
6432 #if SIZEOF_REGISTER == 8
6433                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_I)
6434                                 opcode = OP_ATOMIC_STORE_I8;
6435                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U8 || fsig->params [0]->type == MONO_TYPE_U)
6436                                 opcode = OP_ATOMIC_STORE_U8;
6437 #else
6438                         else if (fsig->params [0]->type == MONO_TYPE_I)
6439                                 opcode = OP_ATOMIC_STORE_I4;
6440                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U)
6441                                 opcode = OP_ATOMIC_STORE_U4;
6442 #endif
6443
6444                         if (opcode) {
6445                                 if (!mono_arch_opcode_supported (opcode))
6446                                         return NULL;
6447
6448                                 MONO_INST_NEW (cfg, ins, opcode);
6449                                 ins->dreg = args [0]->dreg;
6450                                 ins->sreg1 = args [1]->dreg;
6451                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_REL;
6452                                 MONO_ADD_INS (cfg->cbb, ins);
6453
6454                                 if (cfg->gen_write_barriers && is_ref)
6455                                         emit_write_barrier (cfg, args [0], args [1]);
6456                         }
6457                 }
6458
6459                 if (ins)
6460                         return ins;
6461         } else if (cmethod->klass->image == mono_defaults.corlib &&
6462                            (strcmp (cmethod->klass->name_space, "System.Diagnostics") == 0) &&
6463                            (strcmp (cmethod->klass->name, "Debugger") == 0)) {
6464                 if (!strcmp (cmethod->name, "Break") && fsig->param_count == 0) {
6465                         if (should_insert_brekpoint (cfg->method)) {
6466                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
6467                         } else {
6468                                 MONO_INST_NEW (cfg, ins, OP_NOP);
6469                                 MONO_ADD_INS (cfg->cbb, ins);
6470                         }
6471                         return ins;
6472                 }
6473         } else if (cmethod->klass->image == mono_defaults.corlib &&
6474                    (strcmp (cmethod->klass->name_space, "System") == 0) &&
6475                    (strcmp (cmethod->klass->name, "Environment") == 0)) {
6476                 if (!strcmp (cmethod->name, "get_IsRunningOnWindows") && fsig->param_count == 0) {
6477 #ifdef TARGET_WIN32
6478                         EMIT_NEW_ICONST (cfg, ins, 1);
6479 #else
6480                         EMIT_NEW_ICONST (cfg, ins, 0);
6481 #endif
6482                 }
6483         } else if (cmethod->klass == mono_defaults.math_class) {
6484                 /* 
6485                  * There is general branchless code for Min/Max, but it does not work for 
6486                  * all inputs:
6487                  * http://everything2.com/?node_id=1051618
6488                  */
6489         } else if ((!strcmp (cmethod->klass->image->assembly->aname.name, "MonoMac") ||
6490                     !strcmp (cmethod->klass->image->assembly->aname.name, "monotouch")) &&
6491                    !strcmp (cmethod->klass->name_space, "XamCore.ObjCRuntime") &&
6492                    !strcmp (cmethod->klass->name, "Selector")) {
6493 #ifdef MONO_ARCH_HAVE_OBJC_GET_SELECTOR
6494                 if (!strcmp (cmethod->klass->name, "GetHandle") && fsig->param_count == 1 &&
6495                     (args [0]->opcode == OP_GOT_ENTRY || args [0]->opcode == OP_AOTCONST) &&
6496                     cfg->compile_aot) {
6497                         MonoInst *pi;
6498                         MonoJumpInfoToken *ji;
6499                         MonoString *s;
6500
6501                         cfg->disable_llvm = TRUE;
6502
6503                         if (args [0]->opcode == OP_GOT_ENTRY) {
6504                                 pi = args [0]->inst_p1;
6505                                 g_assert (pi->opcode == OP_PATCH_INFO);
6506                                 g_assert (GPOINTER_TO_INT (pi->inst_p1) == MONO_PATCH_INFO_LDSTR);
6507                                 ji = pi->inst_p0;
6508                         } else {
6509                                 g_assert (GPOINTER_TO_INT (args [0]->inst_p1) == MONO_PATCH_INFO_LDSTR);
6510                                 ji = args [0]->inst_p0;
6511                         }
6512
6513                         NULLIFY_INS (args [0]);
6514
6515                         // FIXME: Ugly
6516                         s = mono_ldstr (cfg->domain, ji->image, mono_metadata_token_index (ji->token));
6517                         MONO_INST_NEW (cfg, ins, OP_OBJC_GET_SELECTOR);
6518                         ins->dreg = mono_alloc_ireg (cfg);
6519                         // FIXME: Leaks
6520                         ins->inst_p0 = mono_string_to_utf8 (s);
6521                         MONO_ADD_INS (cfg->cbb, ins);
6522                         return ins;
6523                 }
6524 #endif
6525         }
6526
6527 #ifdef MONO_ARCH_SIMD_INTRINSICS
6528         if (cfg->opt & MONO_OPT_SIMD) {
6529                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
6530                 if (ins)
6531                         return ins;
6532         }
6533 #endif
6534
6535         ins = mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
6536         if (ins)
6537                 return ins;
6538
6539         if (COMPILE_LLVM (cfg)) {
6540                 ins = llvm_emit_inst_for_method (cfg, cmethod, fsig, args);
6541                 if (ins)
6542                         return ins;
6543         }
6544
6545         return mono_arch_emit_inst_for_method (cfg, cmethod, fsig, args);
6546 }
6547
6548 /*
6549  * This entry point could be used later for arbitrary method
6550  * redirection.
6551  */
6552 inline static MonoInst*
6553 mini_redirect_call (MonoCompile *cfg, MonoMethod *method,  
6554                                         MonoMethodSignature *signature, MonoInst **args, MonoInst *this)
6555 {
6556         if (method->klass == mono_defaults.string_class) {
6557                 /* managed string allocation support */
6558                 if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && !(cfg->opt & MONO_OPT_SHARED)) {
6559                         MonoInst *iargs [2];
6560                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
6561                         MonoMethod *managed_alloc = NULL;
6562
6563                         g_assert (vtable); /*Should not fail since it System.String*/
6564 #ifndef MONO_CROSS_COMPILE
6565                         managed_alloc = mono_gc_get_managed_allocator (method->klass, FALSE, FALSE);
6566 #endif
6567                         if (!managed_alloc)
6568                                 return NULL;
6569                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
6570                         iargs [1] = args [0];
6571                         return mono_emit_method_call (cfg, managed_alloc, iargs, this);
6572                 }
6573         }
6574         return NULL;
6575 }
6576
6577 static void
6578 mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp)
6579 {
6580         MonoInst *store, *temp;
6581         int i;
6582
6583         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
6584                 MonoType *argtype = (sig->hasthis && (i == 0)) ? type_from_stack_type (*sp) : sig->params [i - sig->hasthis];
6585
6586                 /*
6587                  * FIXME: We should use *args++ = sp [0], but that would mean the arg
6588                  * would be different than the MonoInst's used to represent arguments, and
6589                  * the ldelema implementation can't deal with that.
6590                  * Solution: When ldelema is used on an inline argument, create a var for 
6591                  * it, emit ldelema on that var, and emit the saving code below in
6592                  * inline_method () if needed.
6593                  */
6594                 temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
6595                 cfg->args [i] = temp;
6596                 /* This uses cfg->args [i] which is set by the preceeding line */
6597                 EMIT_NEW_ARGSTORE (cfg, store, i, *sp);
6598                 store->cil_code = sp [0]->cil_code;
6599                 sp++;
6600         }
6601 }
6602
6603 #define MONO_INLINE_CALLED_LIMITED_METHODS 1
6604 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
6605
6606 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6607 static gboolean
6608 check_inline_called_method_name_limit (MonoMethod *called_method)
6609 {
6610         int strncmp_result;
6611         static const char *limit = NULL;
6612         
6613         if (limit == NULL) {
6614                 const char *limit_string = g_getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
6615
6616                 if (limit_string != NULL)
6617                         limit = limit_string;
6618                 else
6619                         limit = "";
6620         }
6621
6622         if (limit [0] != '\0') {
6623                 char *called_method_name = mono_method_full_name (called_method, TRUE);
6624
6625                 strncmp_result = strncmp (called_method_name, limit, strlen (limit));
6626                 g_free (called_method_name);
6627         
6628                 //return (strncmp_result <= 0);
6629                 return (strncmp_result == 0);
6630         } else {
6631                 return TRUE;
6632         }
6633 }
6634 #endif
6635
6636 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6637 static gboolean
6638 check_inline_caller_method_name_limit (MonoMethod *caller_method)
6639 {
6640         int strncmp_result;
6641         static const char *limit = NULL;
6642         
6643         if (limit == NULL) {
6644                 const char *limit_string = g_getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
6645                 if (limit_string != NULL) {
6646                         limit = limit_string;
6647                 } else {
6648                         limit = "";
6649                 }
6650         }
6651
6652         if (limit [0] != '\0') {
6653                 char *caller_method_name = mono_method_full_name (caller_method, TRUE);
6654
6655                 strncmp_result = strncmp (caller_method_name, limit, strlen (limit));
6656                 g_free (caller_method_name);
6657         
6658                 //return (strncmp_result <= 0);
6659                 return (strncmp_result == 0);
6660         } else {
6661                 return TRUE;
6662         }
6663 }
6664 #endif
6665
6666 static void
6667 emit_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6668 {
6669         static double r8_0 = 0.0;
6670         static float r4_0 = 0.0;
6671         MonoInst *ins;
6672         int t;
6673
6674         rtype = mini_replace_type (rtype);
6675         t = rtype->type;
6676
6677         if (rtype->byref) {
6678                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6679         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6680                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
6681         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6682                 MONO_EMIT_NEW_I8CONST (cfg, dreg, 0);
6683         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6684                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
6685                 ins->type = STACK_R4;
6686                 ins->inst_p0 = (void*)&r4_0;
6687                 ins->dreg = dreg;
6688                 MONO_ADD_INS (cfg->cbb, ins);
6689         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6690                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
6691                 ins->type = STACK_R8;
6692                 ins->inst_p0 = (void*)&r8_0;
6693                 ins->dreg = dreg;
6694                 MONO_ADD_INS (cfg->cbb, ins);
6695         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6696                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6697                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6698         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (cfg, rtype)) {
6699                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6700         } else {
6701                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6702         }
6703 }
6704
6705 static void
6706 emit_dummy_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6707 {
6708         int t;
6709
6710         rtype = mini_replace_type (rtype);
6711         t = rtype->type;
6712
6713         if (rtype->byref) {
6714                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_PCONST);
6715         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6716                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_ICONST);
6717         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6718                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_I8CONST);
6719         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6720                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R4CONST);
6721         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6722                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R8CONST);
6723         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6724                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6725                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6726         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (cfg, rtype)) {
6727                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6728         } else {
6729                 emit_init_rvar (cfg, dreg, rtype);
6730         }
6731 }
6732
6733 /* If INIT is FALSE, emit dummy initialization statements to keep the IR valid */
6734 static void
6735 emit_init_local (MonoCompile *cfg, int local, MonoType *type, gboolean init)
6736 {
6737         MonoInst *var = cfg->locals [local];
6738         if (COMPILE_SOFT_FLOAT (cfg)) {
6739                 MonoInst *store;
6740                 int reg = alloc_dreg (cfg, var->type);
6741                 emit_init_rvar (cfg, reg, type);
6742                 EMIT_NEW_LOCSTORE (cfg, store, local, cfg->cbb->last_ins);
6743         } else {
6744                 if (init)
6745                         emit_init_rvar (cfg, var->dreg, type);
6746                 else
6747                         emit_dummy_init_rvar (cfg, var->dreg, type);
6748         }
6749 }
6750
6751 /*
6752  * inline_method:
6753  *
6754  *   Return the cost of inlining CMETHOD.
6755  */
6756 static int
6757 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
6758                            guchar *ip, guint real_offset, gboolean inline_always, MonoBasicBlock **out_cbb)
6759 {
6760         MonoInst *ins, *rvar = NULL;
6761         MonoMethodHeader *cheader;
6762         MonoBasicBlock *ebblock, *sbblock;
6763         int i, costs;
6764         MonoMethod *prev_inlined_method;
6765         MonoInst **prev_locals, **prev_args;
6766         MonoType **prev_arg_types;
6767         guint prev_real_offset;
6768         GHashTable *prev_cbb_hash;
6769         MonoBasicBlock **prev_cil_offset_to_bb;
6770         MonoBasicBlock *prev_cbb;
6771         unsigned char* prev_cil_start;
6772         guint32 prev_cil_offset_to_bb_len;
6773         MonoMethod *prev_current_method;
6774         MonoGenericContext *prev_generic_context;
6775         gboolean ret_var_set, prev_ret_var_set, prev_disable_inline, virtual = FALSE;
6776
6777         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
6778
6779 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6780         if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod))
6781                 return 0;
6782 #endif
6783 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6784         if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method))
6785                 return 0;
6786 #endif
6787
6788         if (!fsig)
6789                 fsig = mono_method_signature (cmethod);
6790
6791         if (cfg->verbose_level > 2)
6792                 printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
6793
6794         if (!cmethod->inline_info) {
6795                 cfg->stat_inlineable_methods++;
6796                 cmethod->inline_info = 1;
6797         }
6798
6799         /* allocate local variables */
6800         cheader = mono_method_get_header (cmethod);
6801
6802         if (cheader == NULL || mono_loader_get_last_error ()) {
6803                 MonoLoaderError *error = mono_loader_get_last_error ();
6804
6805                 if (cheader)
6806                         mono_metadata_free_mh (cheader);
6807                 if (inline_always && error)
6808                         mono_cfg_set_exception (cfg, error->exception_type);
6809
6810                 mono_loader_clear_error ();
6811                 return 0;
6812         }
6813
6814         /*Must verify before creating locals as it can cause the JIT to assert.*/
6815         if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
6816                 mono_metadata_free_mh (cheader);
6817                 return 0;
6818         }
6819
6820         /* allocate space to store the return value */
6821         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
6822                 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
6823         }
6824
6825         prev_locals = cfg->locals;
6826         cfg->locals = mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));     
6827         for (i = 0; i < cheader->num_locals; ++i)
6828                 cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
6829
6830         /* allocate start and end blocks */
6831         /* This is needed so if the inline is aborted, we can clean up */
6832         NEW_BBLOCK (cfg, sbblock);
6833         sbblock->real_offset = real_offset;
6834
6835         NEW_BBLOCK (cfg, ebblock);
6836         ebblock->block_num = cfg->num_bblocks++;
6837         ebblock->real_offset = real_offset;
6838
6839         prev_args = cfg->args;
6840         prev_arg_types = cfg->arg_types;
6841         prev_inlined_method = cfg->inlined_method;
6842         cfg->inlined_method = cmethod;
6843         cfg->ret_var_set = FALSE;
6844         cfg->inline_depth ++;
6845         prev_real_offset = cfg->real_offset;
6846         prev_cbb_hash = cfg->cbb_hash;
6847         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
6848         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
6849         prev_cil_start = cfg->cil_start;
6850         prev_cbb = cfg->cbb;
6851         prev_current_method = cfg->current_method;
6852         prev_generic_context = cfg->generic_context;
6853         prev_ret_var_set = cfg->ret_var_set;
6854         prev_disable_inline = cfg->disable_inline;
6855
6856         if (ip && *ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
6857                 virtual = TRUE;
6858
6859         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, sp, real_offset, virtual);
6860
6861         ret_var_set = cfg->ret_var_set;
6862
6863         cfg->inlined_method = prev_inlined_method;
6864         cfg->real_offset = prev_real_offset;
6865         cfg->cbb_hash = prev_cbb_hash;
6866         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
6867         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
6868         cfg->cil_start = prev_cil_start;
6869         cfg->locals = prev_locals;
6870         cfg->args = prev_args;
6871         cfg->arg_types = prev_arg_types;
6872         cfg->current_method = prev_current_method;
6873         cfg->generic_context = prev_generic_context;
6874         cfg->ret_var_set = prev_ret_var_set;
6875         cfg->disable_inline = prev_disable_inline;
6876         cfg->inline_depth --;
6877
6878         if ((costs >= 0 && costs < 60) || inline_always) {
6879                 if (cfg->verbose_level > 2)
6880                         printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
6881                 
6882                 cfg->stat_inlined_methods++;
6883
6884                 /* always add some code to avoid block split failures */
6885                 MONO_INST_NEW (cfg, ins, OP_NOP);
6886                 MONO_ADD_INS (prev_cbb, ins);
6887
6888                 prev_cbb->next_bb = sbblock;
6889                 link_bblock (cfg, prev_cbb, sbblock);
6890
6891                 /* 
6892                  * Get rid of the begin and end bblocks if possible to aid local
6893                  * optimizations.
6894                  */
6895                 mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
6896
6897                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
6898                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
6899
6900                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
6901                         MonoBasicBlock *prev = ebblock->in_bb [0];
6902                         mono_merge_basic_blocks (cfg, prev, ebblock);
6903                         cfg->cbb = prev;
6904                         if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
6905                                 mono_merge_basic_blocks (cfg, prev_cbb, prev);
6906                                 cfg->cbb = prev_cbb;
6907                         }
6908                 } else {
6909                         /* 
6910                          * Its possible that the rvar is set in some prev bblock, but not in others.
6911                          * (#1835).
6912                          */
6913                         if (rvar) {
6914                                 MonoBasicBlock *bb;
6915
6916                                 for (i = 0; i < ebblock->in_count; ++i) {
6917                                         bb = ebblock->in_bb [i];
6918
6919                                         if (bb->last_ins && bb->last_ins->opcode == OP_NOT_REACHED) {
6920                                                 cfg->cbb = bb;
6921
6922                                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
6923                                         }
6924                                 }
6925                         }
6926
6927                         cfg->cbb = ebblock;
6928                 }
6929
6930                 if (out_cbb)
6931                         *out_cbb = cfg->cbb;
6932
6933                 if (rvar) {
6934                         /*
6935                          * If the inlined method contains only a throw, then the ret var is not 
6936                          * set, so set it to a dummy value.
6937                          */
6938                         if (!ret_var_set)
6939                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
6940
6941                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
6942                         *sp++ = ins;
6943                 }
6944                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
6945                 return costs + 1;
6946         } else {
6947                 if (cfg->verbose_level > 2)
6948                         printf ("INLINE ABORTED %s (cost %d)\n", mono_method_full_name (cmethod, TRUE), costs);
6949                 cfg->exception_type = MONO_EXCEPTION_NONE;
6950                 mono_loader_clear_error ();
6951
6952                 /* This gets rid of the newly added bblocks */
6953                 cfg->cbb = prev_cbb;
6954         }
6955         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
6956         return 0;
6957 }
6958
6959 /*
6960  * Some of these comments may well be out-of-date.
6961  * Design decisions: we do a single pass over the IL code (and we do bblock 
6962  * splitting/merging in the few cases when it's required: a back jump to an IL
6963  * address that was not already seen as bblock starting point).
6964  * Code is validated as we go (full verification is still better left to metadata/verify.c).
6965  * Complex operations are decomposed in simpler ones right away. We need to let the 
6966  * arch-specific code peek and poke inside this process somehow (except when the 
6967  * optimizations can take advantage of the full semantic info of coarse opcodes).
6968  * All the opcodes of the form opcode.s are 'normalized' to opcode.
6969  * MonoInst->opcode initially is the IL opcode or some simplification of that 
6970  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
6971  * opcode with value bigger than OP_LAST.
6972  * At this point the IR can be handed over to an interpreter, a dumb code generator
6973  * or to the optimizing code generator that will translate it to SSA form.
6974  *
6975  * Profiling directed optimizations.
6976  * We may compile by default with few or no optimizations and instrument the code
6977  * or the user may indicate what methods to optimize the most either in a config file
6978  * or through repeated runs where the compiler applies offline the optimizations to 
6979  * each method and then decides if it was worth it.
6980  */
6981
6982 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
6983 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
6984 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
6985 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
6986 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
6987 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
6988 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
6989 #define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) TYPE_LOAD_ERROR ((klass))
6990
6991 /* offset from br.s -> br like opcodes */
6992 #define BIG_BRANCH_OFFSET 13
6993
6994 static gboolean
6995 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
6996 {
6997         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
6998
6999         return b == NULL || b == bb;
7000 }
7001
7002 static int
7003 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
7004 {
7005         unsigned char *ip = start;
7006         unsigned char *target;
7007         int i;
7008         guint cli_addr;
7009         MonoBasicBlock *bblock;
7010         const MonoOpcode *opcode;
7011
7012         while (ip < end) {
7013                 cli_addr = ip - start;
7014                 i = mono_opcode_value ((const guint8 **)&ip, end);
7015                 if (i < 0)
7016                         UNVERIFIED;
7017                 opcode = &mono_opcodes [i];
7018                 switch (opcode->argument) {
7019                 case MonoInlineNone:
7020                         ip++; 
7021                         break;
7022                 case MonoInlineString:
7023                 case MonoInlineType:
7024                 case MonoInlineField:
7025                 case MonoInlineMethod:
7026                 case MonoInlineTok:
7027                 case MonoInlineSig:
7028                 case MonoShortInlineR:
7029                 case MonoInlineI:
7030                         ip += 5;
7031                         break;
7032                 case MonoInlineVar:
7033                         ip += 3;
7034                         break;
7035                 case MonoShortInlineVar:
7036                 case MonoShortInlineI:
7037                         ip += 2;
7038                         break;
7039                 case MonoShortInlineBrTarget:
7040                         target = start + cli_addr + 2 + (signed char)ip [1];
7041                         GET_BBLOCK (cfg, bblock, target);
7042                         ip += 2;
7043                         if (ip < end)
7044                                 GET_BBLOCK (cfg, bblock, ip);
7045                         break;
7046                 case MonoInlineBrTarget:
7047                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
7048                         GET_BBLOCK (cfg, bblock, target);
7049                         ip += 5;
7050                         if (ip < end)
7051                                 GET_BBLOCK (cfg, bblock, ip);
7052                         break;
7053                 case MonoInlineSwitch: {
7054                         guint32 n = read32 (ip + 1);
7055                         guint32 j;
7056                         ip += 5;
7057                         cli_addr += 5 + 4 * n;
7058                         target = start + cli_addr;
7059                         GET_BBLOCK (cfg, bblock, target);
7060                         
7061                         for (j = 0; j < n; ++j) {
7062                                 target = start + cli_addr + (gint32)read32 (ip);
7063                                 GET_BBLOCK (cfg, bblock, target);
7064                                 ip += 4;
7065                         }
7066                         break;
7067                 }
7068                 case MonoInlineR:
7069                 case MonoInlineI8:
7070                         ip += 9;
7071                         break;
7072                 default:
7073                         g_assert_not_reached ();
7074                 }
7075
7076                 if (i == CEE_THROW) {
7077                         unsigned char *bb_start = ip - 1;
7078                         
7079                         /* Find the start of the bblock containing the throw */
7080                         bblock = NULL;
7081                         while ((bb_start >= start) && !bblock) {
7082                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
7083                                 bb_start --;
7084                         }
7085                         if (bblock)
7086                                 bblock->out_of_line = 1;
7087                 }
7088         }
7089         return 0;
7090 unverified:
7091 exception_exit:
7092         *pos = ip;
7093         return 1;
7094 }
7095
7096 static inline MonoMethod *
7097 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
7098 {
7099         MonoMethod *method;
7100
7101         if (m->wrapper_type != MONO_WRAPPER_NONE) {
7102                 method = mono_method_get_wrapper_data (m, token);
7103                 if (context) {
7104                         MonoError error;
7105                         method = mono_class_inflate_generic_method_checked (method, context, &error);
7106                         g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
7107                 }
7108         } else {
7109                 method = mono_get_method_full (m->klass->image, token, klass, context);
7110         }
7111
7112         return method;
7113 }
7114
7115 static inline MonoMethod *
7116 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
7117 {
7118         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context);
7119
7120         if (method && cfg && !cfg->generic_sharing_context && mono_class_is_open_constructed_type (&method->klass->byval_arg))
7121                 return NULL;
7122
7123         return method;
7124 }
7125
7126 static inline MonoClass*
7127 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
7128 {
7129         MonoError error;
7130         MonoClass *klass;
7131
7132         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7133                 klass = mono_method_get_wrapper_data (method, token);
7134                 if (context)
7135                         klass = mono_class_inflate_generic_class (klass, context);
7136         } else {
7137                 klass = mono_class_get_and_inflate_typespec_checked (method->klass->image, token, context, &error);
7138                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
7139         }
7140         if (klass)
7141                 mono_class_init (klass);
7142         return klass;
7143 }
7144
7145 static inline MonoMethodSignature*
7146 mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context)
7147 {
7148         MonoMethodSignature *fsig;
7149
7150         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7151                 MonoError error;
7152
7153                 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
7154                 if (context) {
7155                         fsig = mono_inflate_generic_signature (fsig, context, &error);
7156                         // FIXME:
7157                         g_assert (mono_error_ok (&error));
7158                 }
7159         } else {
7160                 fsig = mono_metadata_parse_signature (method->klass->image, token);
7161         }
7162         return fsig;
7163 }
7164
7165 /*
7166  * Returns TRUE if the JIT should abort inlining because "callee"
7167  * is influenced by security attributes.
7168  */
7169 static
7170 gboolean check_linkdemand (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
7171 {
7172         guint32 result;
7173         
7174         if ((cfg->method != caller) && mono_security_method_has_declsec (callee)) {
7175                 return TRUE;
7176         }
7177         
7178         result = mono_declsec_linkdemand (cfg->domain, caller, callee);
7179         if (result == MONO_JIT_SECURITY_OK)
7180                 return FALSE;
7181
7182         if (result == MONO_JIT_LINKDEMAND_ECMA) {
7183                 /* Generate code to throw a SecurityException before the actual call/link */
7184                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
7185                 MonoInst *args [2];
7186
7187                 NEW_ICONST (cfg, args [0], 4);
7188                 NEW_METHODCONST (cfg, args [1], caller);
7189                 mono_emit_method_call (cfg, secman->linkdemandsecurityexception, args, NULL);
7190         } else if (cfg->exception_type == MONO_EXCEPTION_NONE) {
7191                  /* don't hide previous results */
7192                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_SECURITY_LINKDEMAND);
7193                 cfg->exception_data = result;
7194                 return TRUE;
7195         }
7196         
7197         return FALSE;
7198 }
7199
7200 static MonoMethod*
7201 throw_exception (void)
7202 {
7203         static MonoMethod *method = NULL;
7204
7205         if (!method) {
7206                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
7207                 method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
7208         }
7209         g_assert (method);
7210         return method;
7211 }
7212
7213 static void
7214 emit_throw_exception (MonoCompile *cfg, MonoException *ex)
7215 {
7216         MonoMethod *thrower = throw_exception ();
7217         MonoInst *args [1];
7218
7219         EMIT_NEW_PCONST (cfg, args [0], ex);
7220         mono_emit_method_call (cfg, thrower, args, NULL);
7221 }
7222
7223 /*
7224  * Return the original method is a wrapper is specified. We can only access 
7225  * the custom attributes from the original method.
7226  */
7227 static MonoMethod*
7228 get_original_method (MonoMethod *method)
7229 {
7230         if (method->wrapper_type == MONO_WRAPPER_NONE)
7231                 return method;
7232
7233         /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
7234         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
7235                 return NULL;
7236
7237         /* in other cases we need to find the original method */
7238         return mono_marshal_method_from_wrapper (method);
7239 }
7240
7241 static void
7242 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field,
7243                                           MonoBasicBlock *bblock, unsigned char *ip)
7244 {
7245         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7246         MonoException *ex = mono_security_core_clr_is_field_access_allowed (get_original_method (caller), field);
7247         if (ex)
7248                 emit_throw_exception (cfg, ex);
7249 }
7250
7251 static void
7252 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee,
7253                                          MonoBasicBlock *bblock, unsigned char *ip)
7254 {
7255         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7256         MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
7257         if (ex)
7258                 emit_throw_exception (cfg, ex);
7259 }
7260
7261 /*
7262  * Check that the IL instructions at ip are the array initialization
7263  * sequence and return the pointer to the data and the size.
7264  */
7265 static const char*
7266 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
7267 {
7268         /*
7269          * newarr[System.Int32]
7270          * dup
7271          * ldtoken field valuetype ...
7272          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
7273          */
7274         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
7275                 MonoError error;
7276                 guint32 token = read32 (ip + 7);
7277                 guint32 field_token = read32 (ip + 2);
7278                 guint32 field_index = field_token & 0xffffff;
7279                 guint32 rva;
7280                 const char *data_ptr;
7281                 int size = 0;
7282                 MonoMethod *cmethod;
7283                 MonoClass *dummy_class;
7284                 MonoClassField *field = mono_field_from_token_checked (method->klass->image, field_token, &dummy_class, NULL, &error);
7285                 int dummy_align;
7286
7287                 if (!field) {
7288                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7289                         return NULL;
7290                 }
7291
7292                 *out_field_token = field_token;
7293
7294                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
7295                 if (!cmethod)
7296                         return NULL;
7297                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
7298                         return NULL;
7299                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
7300                 case MONO_TYPE_BOOLEAN:
7301                 case MONO_TYPE_I1:
7302                 case MONO_TYPE_U1:
7303                         size = 1; break;
7304                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
7305 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
7306                 case MONO_TYPE_CHAR:
7307                 case MONO_TYPE_I2:
7308                 case MONO_TYPE_U2:
7309                         size = 2; break;
7310                 case MONO_TYPE_I4:
7311                 case MONO_TYPE_U4:
7312                 case MONO_TYPE_R4:
7313                         size = 4; break;
7314                 case MONO_TYPE_R8:
7315                 case MONO_TYPE_I8:
7316                 case MONO_TYPE_U8:
7317                         size = 8; break;
7318 #endif
7319                 default:
7320                         return NULL;
7321                 }
7322                 size *= len;
7323                 if (size > mono_type_size (field->type, &dummy_align))
7324                     return NULL;
7325                 *out_size = size;
7326                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
7327                 if (!image_is_dynamic (method->klass->image)) {
7328                         field_index = read32 (ip + 2) & 0xffffff;
7329                         mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
7330                         data_ptr = mono_image_rva_map (method->klass->image, rva);
7331                         /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
7332                         /* for aot code we do the lookup on load */
7333                         if (aot && data_ptr)
7334                                 return GUINT_TO_POINTER (rva);
7335                 } else {
7336                         /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
7337                         g_assert (!aot);
7338                         data_ptr = mono_field_get_data (field);
7339                 }
7340                 return data_ptr;
7341         }
7342         return NULL;
7343 }
7344
7345 static void
7346 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
7347 {
7348         char *method_fname = mono_method_full_name (method, TRUE);
7349         char *method_code;
7350         MonoMethodHeader *header = mono_method_get_header (method);
7351
7352         if (header->code_size == 0)
7353                 method_code = g_strdup ("method body is empty.");
7354         else
7355                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
7356         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
7357         cfg->exception_message = g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code);
7358         g_free (method_fname);
7359         g_free (method_code);
7360         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
7361 }
7362
7363 static void
7364 set_exception_object (MonoCompile *cfg, MonoException *exception)
7365 {
7366         mono_cfg_set_exception (cfg, MONO_EXCEPTION_OBJECT_SUPPLIED);
7367         MONO_GC_REGISTER_ROOT_SINGLE (cfg->exception_ptr);
7368         cfg->exception_ptr = exception;
7369 }
7370
7371 static void
7372 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
7373 {
7374         MonoInst *ins;
7375         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
7376         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
7377                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
7378                 /* Optimize reg-reg moves away */
7379                 /* 
7380                  * Can't optimize other opcodes, since sp[0] might point to
7381                  * the last ins of a decomposed opcode.
7382                  */
7383                 sp [0]->dreg = (cfg)->locals [n]->dreg;
7384         } else {
7385                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
7386         }
7387 }
7388
7389 /*
7390  * ldloca inhibits many optimizations so try to get rid of it in common
7391  * cases.
7392  */
7393 static inline unsigned char *
7394 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
7395 {
7396         int local, token;
7397         MonoClass *klass;
7398         MonoType *type;
7399
7400         if (size == 1) {
7401                 local = ip [1];
7402                 ip += 2;
7403         } else {
7404                 local = read16 (ip + 2);
7405                 ip += 4;
7406         }
7407         
7408         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
7409                 /* From the INITOBJ case */
7410                 token = read32 (ip + 2);
7411                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
7412                 CHECK_TYPELOAD (klass);
7413                 type = mini_replace_type (&klass->byval_arg);
7414                 emit_init_local (cfg, local, type, TRUE);
7415                 return ip + 6;
7416         }
7417  exception_exit:
7418         return NULL;
7419 }
7420
7421 static gboolean
7422 is_exception_class (MonoClass *class)
7423 {
7424         while (class) {
7425                 if (class == mono_defaults.exception_class)
7426                         return TRUE;
7427                 class = class->parent;
7428         }
7429         return FALSE;
7430 }
7431
7432 /*
7433  * is_jit_optimizer_disabled:
7434  *
7435  *   Determine whenever M's assembly has a DebuggableAttribute with the
7436  * IsJITOptimizerDisabled flag set.
7437  */
7438 static gboolean
7439 is_jit_optimizer_disabled (MonoMethod *m)
7440 {
7441         MonoAssembly *ass = m->klass->image->assembly;
7442         MonoCustomAttrInfo* attrs;
7443         static MonoClass *klass;
7444         int i;
7445         gboolean val = FALSE;
7446
7447         g_assert (ass);
7448         if (ass->jit_optimizer_disabled_inited)
7449                 return ass->jit_optimizer_disabled;
7450
7451         if (!klass)
7452                 klass = mono_class_from_name (mono_defaults.corlib, "System.Diagnostics", "DebuggableAttribute");
7453         if (!klass) {
7454                 /* Linked away */
7455                 ass->jit_optimizer_disabled = FALSE;
7456                 mono_memory_barrier ();
7457                 ass->jit_optimizer_disabled_inited = TRUE;
7458                 return FALSE;
7459         }
7460
7461         attrs = mono_custom_attrs_from_assembly (ass);
7462         if (attrs) {
7463                 for (i = 0; i < attrs->num_attrs; ++i) {
7464                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
7465                         const gchar *p;
7466                         int len;
7467                         MonoMethodSignature *sig;
7468
7469                         if (!attr->ctor || attr->ctor->klass != klass)
7470                                 continue;
7471                         /* Decode the attribute. See reflection.c */
7472                         len = attr->data_size;
7473                         p = (const char*)attr->data;
7474                         g_assert (read16 (p) == 0x0001);
7475                         p += 2;
7476
7477                         // FIXME: Support named parameters
7478                         sig = mono_method_signature (attr->ctor);
7479                         if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
7480                                 continue;
7481                         /* Two boolean arguments */
7482                         p ++;
7483                         val = *p;
7484                 }
7485                 mono_custom_attrs_free (attrs);
7486         }
7487
7488         ass->jit_optimizer_disabled = val;
7489         mono_memory_barrier ();
7490         ass->jit_optimizer_disabled_inited = TRUE;
7491
7492         return val;
7493 }
7494
7495 static gboolean
7496 is_supported_tail_call (MonoCompile *cfg, MonoMethod *method, MonoMethod *cmethod, MonoMethodSignature *fsig, int call_opcode)
7497 {
7498         gboolean supported_tail_call;
7499         int i;
7500
7501 #ifdef MONO_ARCH_HAVE_OP_TAIL_CALL
7502         supported_tail_call = mono_arch_tail_call_supported (cfg, mono_method_signature (method), mono_method_signature (cmethod));
7503 #else
7504         supported_tail_call = mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod)) && !MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->ret);
7505 #endif
7506
7507         for (i = 0; i < fsig->param_count; ++i) {
7508                 if (fsig->params [i]->byref || fsig->params [i]->type == MONO_TYPE_PTR || fsig->params [i]->type == MONO_TYPE_FNPTR)
7509                         /* These can point to the current method's stack */
7510                         supported_tail_call = FALSE;
7511         }
7512         if (fsig->hasthis && cmethod->klass->valuetype)
7513                 /* this might point to the current method's stack */
7514                 supported_tail_call = FALSE;
7515         if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
7516                 supported_tail_call = FALSE;
7517         if (cfg->method->save_lmf)
7518                 supported_tail_call = FALSE;
7519         if (cmethod->wrapper_type && cmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
7520                 supported_tail_call = FALSE;
7521         if (call_opcode != CEE_CALL)
7522                 supported_tail_call = FALSE;
7523
7524         /* Debugging support */
7525 #if 0
7526         if (supported_tail_call) {
7527                 if (!mono_debug_count ())
7528                         supported_tail_call = FALSE;
7529         }
7530 #endif
7531
7532         return supported_tail_call;
7533 }
7534
7535 /* the JIT intercepts ldflda instructions to the tlsdata field in ThreadLocal<T> and redirects
7536  * it to the thread local value based on the tls_offset field. Every other kind of access to
7537  * the field causes an assert.
7538  */
7539 static gboolean
7540 is_magic_tls_access (MonoClassField *field)
7541 {
7542         if (strcmp (field->name, "tlsdata"))
7543                 return FALSE;
7544         if (strcmp (field->parent->name, "ThreadLocal`1"))
7545                 return FALSE;
7546         return field->parent->image == mono_defaults.corlib;
7547 }
7548
7549 /* emits the code needed to access a managed tls var (like ThreadStatic)
7550  * with the value of the tls offset in offset_reg. thread_ins represents the MonoInternalThread
7551  * pointer for the current thread.
7552  * Returns the MonoInst* representing the address of the tls var.
7553  */
7554 static MonoInst*
7555 emit_managed_static_data_access (MonoCompile *cfg, MonoInst *thread_ins, int offset_reg)
7556 {
7557         MonoInst *addr;
7558         int static_data_reg, array_reg, dreg;
7559         int offset2_reg, idx_reg;
7560         // inlined access to the tls data
7561         // idx = (offset >> 24) - 1;
7562         // return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
7563         static_data_reg = alloc_ireg (cfg);
7564         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
7565         idx_reg = alloc_ireg (cfg);
7566         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_IMM, idx_reg, offset_reg, 24);
7567         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, idx_reg, idx_reg, 1);
7568         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
7569         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
7570         array_reg = alloc_ireg (cfg);
7571         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
7572         offset2_reg = alloc_ireg (cfg);
7573         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset_reg, 0xffffff);
7574         dreg = alloc_ireg (cfg);
7575         EMIT_NEW_BIALU (cfg, addr, OP_PADD, dreg, array_reg, offset2_reg);
7576         return addr;
7577 }
7578
7579 /*
7580  * redirect access to the tlsdata field to the tls var given by the tls_offset field.
7581  * this address is cached per-method in cached_tls_addr.
7582  */
7583 static MonoInst*
7584 create_magic_tls_access (MonoCompile *cfg, MonoClassField *tls_field, MonoInst **cached_tls_addr, MonoInst *thread_local)
7585 {
7586         MonoInst *load, *addr, *temp, *store, *thread_ins;
7587         MonoClassField *offset_field;
7588
7589         if (*cached_tls_addr) {
7590                 EMIT_NEW_TEMPLOAD (cfg, addr, (*cached_tls_addr)->inst_c0);
7591                 return addr;
7592         }
7593         thread_ins = mono_get_thread_intrinsic (cfg);
7594         offset_field = mono_class_get_field_from_name (tls_field->parent, "tls_offset");
7595
7596         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, offset_field->type, thread_local->dreg, offset_field->offset);
7597         if (thread_ins) {
7598                 MONO_ADD_INS (cfg->cbb, thread_ins);
7599         } else {
7600                 MonoMethod *thread_method;
7601                 thread_method = mono_class_get_method_from_name (mono_get_thread_class(), "CurrentInternalThread_internal", 0);
7602                 thread_ins = mono_emit_method_call (cfg, thread_method, NULL, NULL);
7603         }
7604         addr = emit_managed_static_data_access (cfg, thread_ins, load->dreg);
7605         addr->klass = mono_class_from_mono_type (tls_field->type);
7606         addr->type = STACK_MP;
7607         *cached_tls_addr = temp = mono_compile_create_var (cfg, type_from_stack_type (addr), OP_LOCAL);
7608         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, addr);
7609
7610         EMIT_NEW_TEMPLOAD (cfg, addr, temp->inst_c0);
7611         return addr;
7612 }
7613
7614 /*
7615  * handle_ctor_call:
7616  *
7617  *   Handle calls made to ctors from NEWOBJ opcodes.
7618  *
7619  *   REF_BBLOCK will point to the current bblock after the call.
7620  */
7621 static void
7622 handle_ctor_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used,
7623                                   MonoInst **sp, guint8 *ip, MonoBasicBlock **ref_bblock, int *inline_costs)
7624 {
7625         MonoInst *vtable_arg = NULL, *callvirt_this_arg = NULL, *ins;
7626         MonoBasicBlock *bblock = *ref_bblock;
7627
7628         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
7629                                         mono_method_is_generic_sharable (cmethod, TRUE)) {
7630                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
7631                         mono_class_vtable (cfg->domain, cmethod->klass);
7632                         CHECK_TYPELOAD (cmethod->klass);
7633
7634                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
7635                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
7636                 } else {
7637                         if (context_used) {
7638                                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
7639                                                                                                    cmethod->klass, MONO_RGCTX_INFO_VTABLE);
7640                         } else {
7641                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
7642
7643                                 CHECK_TYPELOAD (cmethod->klass);
7644                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
7645                         }
7646                 }
7647         }
7648
7649         /* Avoid virtual calls to ctors if possible */
7650         if (mono_class_is_marshalbyref (cmethod->klass))
7651                 callvirt_this_arg = sp [0];
7652
7653         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
7654                 g_assert (MONO_TYPE_IS_VOID (fsig->ret));
7655                 CHECK_CFG_EXCEPTION;
7656         } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
7657                            mono_method_check_inlining (cfg, cmethod) &&
7658                            !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE)) {
7659                 int costs;
7660
7661                 if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, FALSE, &bblock))) {
7662                         cfg->real_offset += 5;
7663
7664                         *inline_costs += costs - 5;
7665                         *ref_bblock = bblock;
7666                 } else {
7667                         INLINE_FAILURE ("inline failure");
7668                         // FIXME-VT: Clean this up
7669                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))
7670                                 GSHAREDVT_FAILURE(*ip);
7671                         mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, callvirt_this_arg, NULL, NULL);
7672                 }
7673         } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig)) {
7674                 MonoInst *addr;
7675
7676                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
7677                 mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
7678         } else if (context_used &&
7679                            ((!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
7680                                  !mono_class_generic_sharing_enabled (cmethod->klass)) || cfg->gsharedvt)) {
7681                 MonoInst *cmethod_addr;
7682
7683                 /* Generic calls made out of gsharedvt methods cannot be patched, so use an indirect call */
7684
7685                 cmethod_addr = emit_get_rgctx_method (cfg, context_used,
7686                                                                                           cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
7687
7688                 mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
7689         } else {
7690                 INLINE_FAILURE ("ctor call");
7691                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
7692                                                                                   callvirt_this_arg, NULL, vtable_arg);
7693         }
7694  exception_exit:
7695         return;
7696 }
7697
7698 /*
7699  * mono_method_to_ir:
7700  *
7701  *   Translate the .net IL into linear IR.
7702  */
7703 int
7704 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
7705                    MonoInst *return_var, MonoInst **inline_args, 
7706                    guint inline_offset, gboolean is_virtual_call)
7707 {
7708         MonoError error;
7709         MonoInst *ins, **sp, **stack_start;
7710         MonoBasicBlock *bblock, *tblock = NULL, *init_localsbb = NULL;
7711         MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
7712         MonoMethod *cmethod, *method_definition;
7713         MonoInst **arg_array;
7714         MonoMethodHeader *header;
7715         MonoImage *image;
7716         guint32 token, ins_flag;
7717         MonoClass *klass;
7718         MonoClass *constrained_call = NULL;
7719         unsigned char *ip, *end, *target, *err_pos;
7720         MonoMethodSignature *sig;
7721         MonoGenericContext *generic_context = NULL;
7722         MonoGenericContainer *generic_container = NULL;
7723         MonoType **param_types;
7724         int i, n, start_new_bblock, dreg;
7725         int num_calls = 0, inline_costs = 0;
7726         int breakpoint_id = 0;
7727         guint num_args;
7728         MonoBoolean security, pinvoke;
7729         MonoSecurityManager* secman = NULL;
7730         MonoDeclSecurityActions actions;
7731         GSList *class_inits = NULL;
7732         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
7733         int context_used;
7734         gboolean init_locals, seq_points, skip_dead_blocks;
7735         gboolean sym_seq_points = FALSE;
7736         MonoInst *cached_tls_addr = NULL;
7737         MonoDebugMethodInfo *minfo;
7738         MonoBitSet *seq_point_locs = NULL;
7739         MonoBitSet *seq_point_set_locs = NULL;
7740
7741         cfg->disable_inline = is_jit_optimizer_disabled (method);
7742
7743         /* serialization and xdomain stuff may need access to private fields and methods */
7744         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
7745         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
7746         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
7747         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
7748         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
7749         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
7750
7751         dont_verify |= mono_security_smcs_hack_enabled ();
7752
7753         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
7754         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
7755         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
7756         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
7757         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF;
7758
7759         image = method->klass->image;
7760         header = mono_method_get_header (method);
7761         if (!header) {
7762                 MonoLoaderError *error;
7763
7764                 if ((error = mono_loader_get_last_error ())) {
7765                         mono_cfg_set_exception (cfg, error->exception_type);
7766                 } else {
7767                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
7768                         cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
7769                 }
7770                 goto exception_exit;
7771         }
7772         generic_container = mono_method_get_generic_container (method);
7773         sig = mono_method_signature (method);
7774         num_args = sig->hasthis + sig->param_count;
7775         ip = (unsigned char*)header->code;
7776         cfg->cil_start = ip;
7777         end = ip + header->code_size;
7778         cfg->stat_cil_code_size += header->code_size;
7779
7780         seq_points = cfg->gen_seq_points && cfg->method == method;
7781 #ifdef PLATFORM_ANDROID
7782         seq_points &= cfg->method->wrapper_type == MONO_WRAPPER_NONE;
7783 #endif
7784
7785         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
7786                 /* We could hit a seq point before attaching to the JIT (#8338) */
7787                 seq_points = FALSE;
7788         }
7789
7790         if (cfg->gen_seq_points_debug_data && cfg->method == method) {
7791                 minfo = mono_debug_lookup_method (method);
7792                 if (minfo) {
7793                         int i, n_il_offsets;
7794                         int *il_offsets;
7795                         int *line_numbers;
7796
7797                         mono_debug_symfile_get_line_numbers_full (minfo, NULL, NULL, &n_il_offsets, &il_offsets, &line_numbers, NULL, NULL, NULL, NULL);
7798                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7799                         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);
7800                         sym_seq_points = TRUE;
7801                         for (i = 0; i < n_il_offsets; ++i) {
7802                                 if (il_offsets [i] < header->code_size)
7803                                         mono_bitset_set_fast (seq_point_locs, il_offsets [i]);
7804                         }
7805                         g_free (il_offsets);
7806                         g_free (line_numbers);
7807                 } else if (!method->wrapper_type && !method->dynamic && mono_debug_image_has_debug_info (method->klass->image)) {
7808                         /* Methods without line number info like auto-generated property accessors */
7809                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7810                         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);
7811                         sym_seq_points = TRUE;
7812                 }
7813         }
7814
7815         /* 
7816          * Methods without init_locals set could cause asserts in various passes
7817          * (#497220). To work around this, we emit dummy initialization opcodes
7818          * (OP_DUMMY_ICONST etc.) which generate no code. These are only supported
7819          * on some platforms.
7820          */
7821         if ((cfg->opt & MONO_OPT_UNSAFE) && ARCH_HAVE_DUMMY_INIT)
7822                 init_locals = header->init_locals;
7823         else
7824                 init_locals = TRUE;
7825
7826         method_definition = method;
7827         while (method_definition->is_inflated) {
7828                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
7829                 method_definition = imethod->declaring;
7830         }
7831
7832         /* SkipVerification is not allowed if core-clr is enabled */
7833         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
7834                 dont_verify = TRUE;
7835                 dont_verify_stloc = TRUE;
7836         }
7837
7838         if (sig->is_inflated)
7839                 generic_context = mono_method_get_context (method);
7840         else if (generic_container)
7841                 generic_context = &generic_container->context;
7842         cfg->generic_context = generic_context;
7843
7844         if (!cfg->generic_sharing_context)
7845                 g_assert (!sig->has_type_parameters);
7846
7847         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
7848                 g_assert (method->is_inflated);
7849                 g_assert (mono_method_get_context (method)->method_inst);
7850         }
7851         if (method->is_inflated && mono_method_get_context (method)->method_inst)
7852                 g_assert (sig->generic_param_count);
7853
7854         if (cfg->method == method) {
7855                 cfg->real_offset = 0;
7856         } else {
7857                 cfg->real_offset = inline_offset;
7858         }
7859
7860         cfg->cil_offset_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
7861         cfg->cil_offset_to_bb_len = header->code_size;
7862
7863         cfg->current_method = method;
7864
7865         if (cfg->verbose_level > 2)
7866                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
7867
7868         param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
7869         if (sig->hasthis)
7870                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
7871         for (n = 0; n < sig->param_count; ++n)
7872                 param_types [n + sig->hasthis] = sig->params [n];
7873         cfg->arg_types = param_types;
7874
7875         cfg->dont_inline = g_list_prepend (cfg->dont_inline, method);
7876         if (cfg->method == method) {
7877
7878                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
7879                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
7880
7881                 /* ENTRY BLOCK */
7882                 NEW_BBLOCK (cfg, start_bblock);
7883                 cfg->bb_entry = start_bblock;
7884                 start_bblock->cil_code = NULL;
7885                 start_bblock->cil_length = 0;
7886 #if defined(__native_client_codegen__)
7887                 MONO_INST_NEW (cfg, ins, OP_NACL_GC_SAFE_POINT);
7888                 ins->dreg = alloc_dreg (cfg, STACK_I4);
7889                 MONO_ADD_INS (start_bblock, ins);
7890 #endif
7891
7892                 /* EXIT BLOCK */
7893                 NEW_BBLOCK (cfg, end_bblock);
7894                 cfg->bb_exit = end_bblock;
7895                 end_bblock->cil_code = NULL;
7896                 end_bblock->cil_length = 0;
7897                 end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
7898                 g_assert (cfg->num_bblocks == 2);
7899
7900                 arg_array = cfg->args;
7901
7902                 if (header->num_clauses) {
7903                         cfg->spvars = g_hash_table_new (NULL, NULL);
7904                         cfg->exvars = g_hash_table_new (NULL, NULL);
7905                 }
7906                 /* handle exception clauses */
7907                 for (i = 0; i < header->num_clauses; ++i) {
7908                         MonoBasicBlock *try_bb;
7909                         MonoExceptionClause *clause = &header->clauses [i];
7910                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
7911                         try_bb->real_offset = clause->try_offset;
7912                         try_bb->try_start = TRUE;
7913                         try_bb->region = ((i + 1) << 8) | clause->flags;
7914                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
7915                         tblock->real_offset = clause->handler_offset;
7916                         tblock->flags |= BB_EXCEPTION_HANDLER;
7917
7918                         /*
7919                          * Linking the try block with the EH block hinders inlining as we won't be able to 
7920                          * merge the bblocks from inlining and produce an artificial hole for no good reason.
7921                          */
7922                         if (COMPILE_LLVM (cfg))
7923                                 link_bblock (cfg, try_bb, tblock);
7924
7925                         if (*(ip + clause->handler_offset) == CEE_POP)
7926                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
7927
7928                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
7929                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
7930                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
7931                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
7932                                 MONO_ADD_INS (tblock, ins);
7933
7934                                 if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY) {
7935                                         /* finally clauses already have a seq point */
7936                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
7937                                         MONO_ADD_INS (tblock, ins);
7938                                 }
7939
7940                                 /* todo: is a fault block unsafe to optimize? */
7941                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
7942                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
7943                         }
7944
7945
7946                         /*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);
7947                           while (p < end) {
7948                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
7949                           }*/
7950                         /* catch and filter blocks get the exception object on the stack */
7951                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
7952                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7953                                 MonoInst *dummy_use;
7954
7955                                 /* mostly like handle_stack_args (), but just sets the input args */
7956                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
7957                                 tblock->in_scount = 1;
7958                                 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
7959                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
7960
7961                                 /* 
7962                                  * Add a dummy use for the exvar so its liveness info will be
7963                                  * correct.
7964                                  */
7965                                 cfg->cbb = tblock;
7966                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
7967                                 
7968                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7969                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
7970                                         tblock->flags |= BB_EXCEPTION_HANDLER;
7971                                         tblock->real_offset = clause->data.filter_offset;
7972                                         tblock->in_scount = 1;
7973                                         tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
7974                                         /* The filter block shares the exvar with the handler block */
7975                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
7976                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
7977                                         MONO_ADD_INS (tblock, ins);
7978                                 }
7979                         }
7980
7981                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
7982                                         clause->data.catch_class &&
7983                                         cfg->generic_sharing_context &&
7984                                         mono_class_check_context_used (clause->data.catch_class)) {
7985                                 /*
7986                                  * In shared generic code with catch
7987                                  * clauses containing type variables
7988                                  * the exception handling code has to
7989                                  * be able to get to the rgctx.
7990                                  * Therefore we have to make sure that
7991                                  * the vtable/mrgctx argument (for
7992                                  * static or generic methods) or the
7993                                  * "this" argument (for non-static
7994                                  * methods) are live.
7995                                  */
7996                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
7997                                                 mini_method_get_context (method)->method_inst ||
7998                                                 method->klass->valuetype) {
7999                                         mono_get_vtable_var (cfg);
8000                                 } else {
8001                                         MonoInst *dummy_use;
8002
8003                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
8004                                 }
8005                         }
8006                 }
8007         } else {
8008                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
8009                 cfg->cbb = start_bblock;
8010                 cfg->args = arg_array;
8011                 mono_save_args (cfg, sig, inline_args);
8012         }
8013
8014         /* FIRST CODE BLOCK */
8015         NEW_BBLOCK (cfg, bblock);
8016         bblock->cil_code = ip;
8017         cfg->cbb = bblock;
8018         cfg->ip = ip;
8019
8020         ADD_BBLOCK (cfg, bblock);
8021
8022         if (cfg->method == method) {
8023                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
8024                 if (breakpoint_id) {
8025                         MONO_INST_NEW (cfg, ins, OP_BREAK);
8026                         MONO_ADD_INS (bblock, ins);
8027                 }
8028         }
8029
8030         if (mono_security_cas_enabled ())
8031                 secman = mono_security_manager_get_methods ();
8032
8033         security = (secman && mono_security_method_has_declsec (method));
8034         /* at this point having security doesn't mean we have any code to generate */
8035         if (security && (cfg->method == method)) {
8036                 /* Only Demand, NonCasDemand and DemandChoice requires code generation.
8037                  * And we do not want to enter the next section (with allocation) if we
8038                  * have nothing to generate */
8039                 security = mono_declsec_get_demands (method, &actions);
8040         }
8041
8042         /* we must Demand SecurityPermission.Unmanaged before P/Invoking */
8043         pinvoke = (secman && (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE));
8044         if (pinvoke) {
8045                 MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
8046                 if (wrapped && (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
8047                         MonoCustomAttrInfo* custom = mono_custom_attrs_from_method (wrapped);
8048
8049                         /* unless the method or it's class has the [SuppressUnmanagedCodeSecurity] attribute */
8050                         if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
8051                                 pinvoke = FALSE;
8052                         }
8053                         if (custom)
8054                                 mono_custom_attrs_free (custom);
8055
8056                         if (pinvoke) {
8057                                 custom = mono_custom_attrs_from_class (wrapped->klass);
8058                                 if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
8059                                         pinvoke = FALSE;
8060                                 }
8061                                 if (custom)
8062                                         mono_custom_attrs_free (custom);
8063                         }
8064                 } else {
8065                         /* not a P/Invoke after all */
8066                         pinvoke = FALSE;
8067                 }
8068         }
8069         
8070         /* we use a separate basic block for the initialization code */
8071         NEW_BBLOCK (cfg, init_localsbb);
8072         cfg->bb_init = init_localsbb;
8073         init_localsbb->real_offset = cfg->real_offset;
8074         start_bblock->next_bb = init_localsbb;
8075         init_localsbb->next_bb = bblock;
8076         link_bblock (cfg, start_bblock, init_localsbb);
8077         link_bblock (cfg, init_localsbb, bblock);
8078                 
8079         cfg->cbb = init_localsbb;
8080
8081         if (cfg->gsharedvt && cfg->method == method) {
8082                 MonoGSharedVtMethodInfo *info;
8083                 MonoInst *var, *locals_var;
8084                 int dreg;
8085
8086                 info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoGSharedVtMethodInfo));
8087                 info->method = cfg->method;
8088                 info->count_entries = 16;
8089                 info->entries = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
8090                 cfg->gsharedvt_info = info;
8091
8092                 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8093                 /* prevent it from being register allocated */
8094                 //var->flags |= MONO_INST_VOLATILE;
8095                 cfg->gsharedvt_info_var = var;
8096
8097                 ins = emit_get_rgctx_gsharedvt_method (cfg, mini_method_check_context_used (cfg, method), method, info);
8098                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, var->dreg, ins->dreg);
8099
8100                 /* Allocate locals */
8101                 locals_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8102                 /* prevent it from being register allocated */
8103                 //locals_var->flags |= MONO_INST_VOLATILE;
8104                 cfg->gsharedvt_locals_var = locals_var;
8105
8106                 dreg = alloc_ireg (cfg);
8107                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, dreg, var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, locals_size));
8108
8109                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
8110                 ins->dreg = locals_var->dreg;
8111                 ins->sreg1 = dreg;
8112                 MONO_ADD_INS (cfg->cbb, ins);
8113                 cfg->gsharedvt_locals_var_ins = ins;
8114                 
8115                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
8116                 /*
8117                 if (init_locals)
8118                         ins->flags |= MONO_INST_INIT;
8119                 */
8120         }
8121
8122         /* at this point we know, if security is TRUE, that some code needs to be generated */
8123         if (security && (cfg->method == method)) {
8124                 MonoInst *args [2];
8125
8126                 cfg->stat_cas_demand_generation++;
8127
8128                 if (actions.demand.blob) {
8129                         /* Add code for SecurityAction.Demand */
8130                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.demand);
8131                         EMIT_NEW_ICONST (cfg, args [1], actions.demand.size);
8132                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
8133                         mono_emit_method_call (cfg, secman->demand, args, NULL);
8134                 }
8135                 if (actions.noncasdemand.blob) {
8136                         /* CLR 1.x uses a .noncasdemand (but 2.x doesn't) */
8137                         /* For Mono we re-route non-CAS Demand to Demand (as the managed code must deal with it anyway) */
8138                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.noncasdemand);
8139                         EMIT_NEW_ICONST (cfg, args [1], actions.noncasdemand.size);
8140                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
8141                         mono_emit_method_call (cfg, secman->demand, args, NULL);
8142                 }
8143                 if (actions.demandchoice.blob) {
8144                         /* New in 2.0, Demand must succeed for one of the permissions (i.e. not all) */
8145                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.demandchoice);
8146                         EMIT_NEW_ICONST (cfg, args [1], actions.demandchoice.size);
8147                         /* Calls static void SecurityManager.InternalDemandChoice (byte* permissions, int size); */
8148                         mono_emit_method_call (cfg, secman->demandchoice, args, NULL);
8149                 }
8150         }
8151
8152         /* we must Demand SecurityPermission.Unmanaged before p/invoking */
8153         if (pinvoke) {
8154                 mono_emit_method_call (cfg, secman->demandunmanaged, NULL, NULL);
8155         }
8156
8157         if (mono_security_core_clr_enabled ()) {
8158                 /* check if this is native code, e.g. an icall or a p/invoke */
8159                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
8160                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
8161                         if (wrapped) {
8162                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
8163                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
8164
8165                                 /* if this ia a native call then it can only be JITted from platform code */
8166                                 if ((icall || pinvk) && method->klass && method->klass->image) {
8167                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
8168                                                 MonoException *ex = icall ? mono_get_exception_security () : 
8169                                                         mono_get_exception_method_access ();
8170                                                 emit_throw_exception (cfg, ex);
8171                                         }
8172                                 }
8173                         }
8174                 }
8175         }
8176
8177         CHECK_CFG_EXCEPTION;
8178
8179         if (header->code_size == 0)
8180                 UNVERIFIED;
8181
8182         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
8183                 ip = err_pos;
8184                 UNVERIFIED;
8185         }
8186
8187         if (cfg->method == method)
8188                 mono_debug_init_method (cfg, bblock, breakpoint_id);
8189
8190         for (n = 0; n < header->num_locals; ++n) {
8191                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
8192                         UNVERIFIED;
8193         }
8194         class_inits = NULL;
8195
8196         /* We force the vtable variable here for all shared methods
8197            for the possibility that they might show up in a stack
8198            trace where their exact instantiation is needed. */
8199         if (cfg->generic_sharing_context && method == cfg->method) {
8200                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8201                                 mini_method_get_context (method)->method_inst ||
8202                                 method->klass->valuetype) {
8203                         mono_get_vtable_var (cfg);
8204                 } else {
8205                         /* FIXME: Is there a better way to do this?
8206                            We need the variable live for the duration
8207                            of the whole method. */
8208                         cfg->args [0]->flags |= MONO_INST_VOLATILE;
8209                 }
8210         }
8211
8212         /* add a check for this != NULL to inlined methods */
8213         if (is_virtual_call) {
8214                 MonoInst *arg_ins;
8215
8216                 NEW_ARGLOAD (cfg, arg_ins, 0);
8217                 MONO_ADD_INS (cfg->cbb, arg_ins);
8218                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
8219         }
8220
8221         skip_dead_blocks = !dont_verify;
8222         if (skip_dead_blocks) {
8223                 original_bb = bb = mono_basic_block_split (method, &cfg->error);
8224                 CHECK_CFG_ERROR;
8225                 g_assert (bb);
8226         }
8227
8228         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
8229         stack_start = sp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
8230
8231         ins_flag = 0;
8232         start_new_bblock = 0;
8233         cfg->cbb = bblock;
8234         while (ip < end) {
8235                 if (cfg->method == method)
8236                         cfg->real_offset = ip - header->code;
8237                 else
8238                         cfg->real_offset = inline_offset;
8239                 cfg->ip = ip;
8240
8241                 context_used = 0;
8242                 
8243                 if (start_new_bblock) {
8244                         bblock->cil_length = ip - bblock->cil_code;
8245                         if (start_new_bblock == 2) {
8246                                 g_assert (ip == tblock->cil_code);
8247                         } else {
8248                                 GET_BBLOCK (cfg, tblock, ip);
8249                         }
8250                         bblock->next_bb = tblock;
8251                         bblock = tblock;
8252                         cfg->cbb = bblock;
8253                         start_new_bblock = 0;
8254                         for (i = 0; i < bblock->in_scount; ++i) {
8255                                 if (cfg->verbose_level > 3)
8256                                         printf ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                            
8257                                 EMIT_NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
8258                                 *sp++ = ins;
8259                         }
8260                         if (class_inits)
8261                                 g_slist_free (class_inits);
8262                         class_inits = NULL;
8263                 } else {
8264                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != bblock)) {
8265                                 link_bblock (cfg, bblock, tblock);
8266                                 if (sp != stack_start) {
8267                                         handle_stack_args (cfg, stack_start, sp - stack_start);
8268                                         sp = stack_start;
8269                                         CHECK_UNVERIFIABLE (cfg);
8270                                 }
8271                                 bblock->next_bb = tblock;
8272                                 bblock = tblock;
8273                                 cfg->cbb = bblock;
8274                                 for (i = 0; i < bblock->in_scount; ++i) {
8275                                         if (cfg->verbose_level > 3)
8276                                                 printf ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                            
8277                                         EMIT_NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
8278                                         *sp++ = ins;
8279                                 }
8280                                 g_slist_free (class_inits);
8281                                 class_inits = NULL;
8282                         }
8283                 }
8284
8285                 if (skip_dead_blocks) {
8286                         int ip_offset = ip - header->code;
8287
8288                         if (ip_offset == bb->end)
8289                                 bb = bb->next;
8290
8291                         if (bb->dead) {
8292                                 int op_size = mono_opcode_size (ip, end);
8293                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
8294
8295                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
8296
8297                                 if (ip_offset + op_size == bb->end) {
8298                                         MONO_INST_NEW (cfg, ins, OP_NOP);
8299                                         MONO_ADD_INS (bblock, ins);
8300                                         start_new_bblock = 1;
8301                                 }
8302
8303                                 ip += op_size;
8304                                 continue;
8305                         }
8306                 }
8307                 /*
8308                  * Sequence points are points where the debugger can place a breakpoint.
8309                  * Currently, we generate these automatically at points where the IL
8310                  * stack is empty.
8311                  */
8312                 if (seq_points && ((!sym_seq_points && (sp == stack_start)) || (sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code)))) {
8313                         /*
8314                          * Make methods interruptable at the beginning, and at the targets of
8315                          * backward branches.
8316                          * Also, do this at the start of every bblock in methods with clauses too,
8317                          * to be able to handle instructions with inprecise control flow like
8318                          * throw/endfinally.
8319                          * Backward branches are handled at the end of method-to-ir ().
8320                          */
8321                         gboolean intr_loc = ip == header->code || (!cfg->cbb->last_ins && cfg->header->num_clauses);
8322
8323                         /* Avoid sequence points on empty IL like .volatile */
8324                         // FIXME: Enable this
8325                         //if (!(cfg->cbb->last_ins && cfg->cbb->last_ins->opcode == OP_SEQ_POINT)) {
8326                         NEW_SEQ_POINT (cfg, ins, ip - header->code, intr_loc);
8327                         if (sp != stack_start)
8328                                 ins->flags |= MONO_INST_NONEMPTY_STACK;
8329                         MONO_ADD_INS (cfg->cbb, ins);
8330
8331                         if (sym_seq_points)
8332                                 mono_bitset_set_fast (seq_point_set_locs, ip - header->code);
8333                 }
8334
8335                 bblock->real_offset = cfg->real_offset;
8336
8337                 if ((cfg->method == method) && cfg->coverage_info) {
8338                         guint32 cil_offset = ip - header->code;
8339                         cfg->coverage_info->data [cil_offset].cil_code = ip;
8340
8341                         /* TODO: Use an increment here */
8342 #if defined(TARGET_X86)
8343                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
8344                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
8345                         ins->inst_imm = 1;
8346                         MONO_ADD_INS (cfg->cbb, ins);
8347 #else
8348                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
8349                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
8350 #endif
8351                 }
8352
8353                 if (cfg->verbose_level > 3)
8354                         printf ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
8355
8356                 switch (*ip) {
8357                 case CEE_NOP:
8358                         if (seq_points && !sym_seq_points && sp != stack_start) {
8359                                 /*
8360                                  * The C# compiler uses these nops to notify the JIT that it should
8361                                  * insert seq points.
8362                                  */
8363                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, FALSE);
8364                                 MONO_ADD_INS (cfg->cbb, ins);
8365                         }
8366                         if (cfg->keep_cil_nops)
8367                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
8368                         else
8369                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8370                         ip++;
8371                         MONO_ADD_INS (bblock, ins);
8372                         break;
8373                 case CEE_BREAK:
8374                         if (should_insert_brekpoint (cfg->method)) {
8375                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
8376                         } else {
8377                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8378                         }
8379                         ip++;
8380                         MONO_ADD_INS (bblock, ins);
8381                         break;
8382                 case CEE_LDARG_0:
8383                 case CEE_LDARG_1:
8384                 case CEE_LDARG_2:
8385                 case CEE_LDARG_3:
8386                         CHECK_STACK_OVF (1);
8387                         n = (*ip)-CEE_LDARG_0;
8388                         CHECK_ARG (n);
8389                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8390                         ip++;
8391                         *sp++ = ins;
8392                         break;
8393                 case CEE_LDLOC_0:
8394                 case CEE_LDLOC_1:
8395                 case CEE_LDLOC_2:
8396                 case CEE_LDLOC_3:
8397                         CHECK_STACK_OVF (1);
8398                         n = (*ip)-CEE_LDLOC_0;
8399                         CHECK_LOCAL (n);
8400                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8401                         ip++;
8402                         *sp++ = ins;
8403                         break;
8404                 case CEE_STLOC_0:
8405                 case CEE_STLOC_1:
8406                 case CEE_STLOC_2:
8407                 case CEE_STLOC_3: {
8408                         CHECK_STACK (1);
8409                         n = (*ip)-CEE_STLOC_0;
8410                         CHECK_LOCAL (n);
8411                         --sp;
8412                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
8413                                 UNVERIFIED;
8414                         emit_stloc_ir (cfg, sp, header, n);
8415                         ++ip;
8416                         inline_costs += 1;
8417                         break;
8418                         }
8419                 case CEE_LDARG_S:
8420                         CHECK_OPSIZE (2);
8421                         CHECK_STACK_OVF (1);
8422                         n = ip [1];
8423                         CHECK_ARG (n);
8424                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8425                         *sp++ = ins;
8426                         ip += 2;
8427                         break;
8428                 case CEE_LDARGA_S:
8429                         CHECK_OPSIZE (2);
8430                         CHECK_STACK_OVF (1);
8431                         n = ip [1];
8432                         CHECK_ARG (n);
8433                         NEW_ARGLOADA (cfg, ins, n);
8434                         MONO_ADD_INS (cfg->cbb, ins);
8435                         *sp++ = ins;
8436                         ip += 2;
8437                         break;
8438                 case CEE_STARG_S:
8439                         CHECK_OPSIZE (2);
8440                         CHECK_STACK (1);
8441                         --sp;
8442                         n = ip [1];
8443                         CHECK_ARG (n);
8444                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
8445                                 UNVERIFIED;
8446                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
8447                         ip += 2;
8448                         break;
8449                 case CEE_LDLOC_S:
8450                         CHECK_OPSIZE (2);
8451                         CHECK_STACK_OVF (1);
8452                         n = ip [1];
8453                         CHECK_LOCAL (n);
8454                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8455                         *sp++ = ins;
8456                         ip += 2;
8457                         break;
8458                 case CEE_LDLOCA_S: {
8459                         unsigned char *tmp_ip;
8460                         CHECK_OPSIZE (2);
8461                         CHECK_STACK_OVF (1);
8462                         CHECK_LOCAL (ip [1]);
8463
8464                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
8465                                 ip = tmp_ip;
8466                                 inline_costs += 1;
8467                                 break;
8468                         }
8469
8470                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
8471                         *sp++ = ins;
8472                         ip += 2;
8473                         break;
8474                 }
8475                 case CEE_STLOC_S:
8476                         CHECK_OPSIZE (2);
8477                         CHECK_STACK (1);
8478                         --sp;
8479                         CHECK_LOCAL (ip [1]);
8480                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
8481                                 UNVERIFIED;
8482                         emit_stloc_ir (cfg, sp, header, ip [1]);
8483                         ip += 2;
8484                         inline_costs += 1;
8485                         break;
8486                 case CEE_LDNULL:
8487                         CHECK_STACK_OVF (1);
8488                         EMIT_NEW_PCONST (cfg, ins, NULL);
8489                         ins->type = STACK_OBJ;
8490                         ++ip;
8491                         *sp++ = ins;
8492                         break;
8493                 case CEE_LDC_I4_M1:
8494                         CHECK_STACK_OVF (1);
8495                         EMIT_NEW_ICONST (cfg, ins, -1);
8496                         ++ip;
8497                         *sp++ = ins;
8498                         break;
8499                 case CEE_LDC_I4_0:
8500                 case CEE_LDC_I4_1:
8501                 case CEE_LDC_I4_2:
8502                 case CEE_LDC_I4_3:
8503                 case CEE_LDC_I4_4:
8504                 case CEE_LDC_I4_5:
8505                 case CEE_LDC_I4_6:
8506                 case CEE_LDC_I4_7:
8507                 case CEE_LDC_I4_8:
8508                         CHECK_STACK_OVF (1);
8509                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
8510                         ++ip;
8511                         *sp++ = ins;
8512                         break;
8513                 case CEE_LDC_I4_S:
8514                         CHECK_OPSIZE (2);
8515                         CHECK_STACK_OVF (1);
8516                         ++ip;
8517                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
8518                         ++ip;
8519                         *sp++ = ins;
8520                         break;
8521                 case CEE_LDC_I4:
8522                         CHECK_OPSIZE (5);
8523                         CHECK_STACK_OVF (1);
8524                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
8525                         ip += 5;
8526                         *sp++ = ins;
8527                         break;
8528                 case CEE_LDC_I8:
8529                         CHECK_OPSIZE (9);
8530                         CHECK_STACK_OVF (1);
8531                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
8532                         ins->type = STACK_I8;
8533                         ins->dreg = alloc_dreg (cfg, STACK_I8);
8534                         ++ip;
8535                         ins->inst_l = (gint64)read64 (ip);
8536                         MONO_ADD_INS (bblock, ins);
8537                         ip += 8;
8538                         *sp++ = ins;
8539                         break;
8540                 case CEE_LDC_R4: {
8541                         float *f;
8542                         gboolean use_aotconst = FALSE;
8543
8544 #ifdef TARGET_POWERPC
8545                         /* FIXME: Clean this up */
8546                         if (cfg->compile_aot)
8547                                 use_aotconst = TRUE;
8548 #endif
8549
8550                         /* FIXME: we should really allocate this only late in the compilation process */
8551                         f = mono_domain_alloc (cfg->domain, sizeof (float));
8552                         CHECK_OPSIZE (5);
8553                         CHECK_STACK_OVF (1);
8554
8555                         if (use_aotconst) {
8556                                 MonoInst *cons;
8557                                 int dreg;
8558
8559                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
8560
8561                                 dreg = alloc_freg (cfg);
8562                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
8563                                 ins->type = cfg->r4_stack_type;
8564                         } else {
8565                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
8566                                 ins->type = cfg->r4_stack_type;
8567                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8568                                 ins->inst_p0 = f;
8569                                 MONO_ADD_INS (bblock, ins);
8570                         }
8571                         ++ip;
8572                         readr4 (ip, f);
8573                         ip += 4;
8574                         *sp++ = ins;                    
8575                         break;
8576                 }
8577                 case CEE_LDC_R8: {
8578                         double *d;
8579                         gboolean use_aotconst = FALSE;
8580
8581 #ifdef TARGET_POWERPC
8582                         /* FIXME: Clean this up */
8583                         if (cfg->compile_aot)
8584                                 use_aotconst = TRUE;
8585 #endif
8586
8587                         /* FIXME: we should really allocate this only late in the compilation process */
8588                         d = mono_domain_alloc (cfg->domain, sizeof (double));
8589                         CHECK_OPSIZE (9);
8590                         CHECK_STACK_OVF (1);
8591
8592                         if (use_aotconst) {
8593                                 MonoInst *cons;
8594                                 int dreg;
8595
8596                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
8597
8598                                 dreg = alloc_freg (cfg);
8599                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
8600                                 ins->type = STACK_R8;
8601                         } else {
8602                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
8603                                 ins->type = STACK_R8;
8604                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8605                                 ins->inst_p0 = d;
8606                                 MONO_ADD_INS (bblock, ins);
8607                         }
8608                         ++ip;
8609                         readr8 (ip, d);
8610                         ip += 8;
8611                         *sp++ = ins;
8612                         break;
8613                 }
8614                 case CEE_DUP: {
8615                         MonoInst *temp, *store;
8616                         CHECK_STACK (1);
8617                         CHECK_STACK_OVF (1);
8618                         sp--;
8619                         ins = *sp;
8620
8621                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
8622                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
8623
8624                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8625                         *sp++ = ins;
8626
8627                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8628                         *sp++ = ins;
8629
8630                         ++ip;
8631                         inline_costs += 2;
8632                         break;
8633                 }
8634                 case CEE_POP:
8635                         CHECK_STACK (1);
8636                         ip++;
8637                         --sp;
8638
8639 #ifdef TARGET_X86
8640                         if (sp [0]->type == STACK_R8)
8641                                 /* we need to pop the value from the x86 FP stack */
8642                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
8643 #endif
8644                         break;
8645                 case CEE_JMP: {
8646                         MonoCallInst *call;
8647
8648                         INLINE_FAILURE ("jmp");
8649                         GSHAREDVT_FAILURE (*ip);
8650
8651                         CHECK_OPSIZE (5);
8652                         if (stack_start != sp)
8653                                 UNVERIFIED;
8654                         token = read32 (ip + 1);
8655                         /* FIXME: check the signature matches */
8656                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8657
8658                         if (!cmethod || mono_loader_get_last_error ())
8659                                 LOAD_ERROR;
8660  
8661                         if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod))
8662                                 GENERIC_SHARING_FAILURE (CEE_JMP);
8663
8664                         if (mono_security_cas_enabled ())
8665                                 CHECK_CFG_EXCEPTION;
8666
8667                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
8668
8669                         if (ARCH_HAVE_OP_TAIL_CALL) {
8670                                 MonoMethodSignature *fsig = mono_method_signature (cmethod);
8671                                 int i, n;
8672
8673                                 /* Handle tail calls similarly to calls */
8674                                 n = fsig->param_count + fsig->hasthis;
8675
8676                                 DISABLE_AOT (cfg);
8677
8678                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
8679                                 call->method = cmethod;
8680                                 call->tail_call = TRUE;
8681                                 call->signature = mono_method_signature (cmethod);
8682                                 call->args = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
8683                                 call->inst.inst_p0 = cmethod;
8684                                 for (i = 0; i < n; ++i)
8685                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
8686
8687                                 mono_arch_emit_call (cfg, call);
8688                                 cfg->param_area = MAX(cfg->param_area, call->stack_usage);
8689                                 MONO_ADD_INS (bblock, (MonoInst*)call);
8690                         } else {
8691                                 for (i = 0; i < num_args; ++i)
8692                                         /* Prevent arguments from being optimized away */
8693                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
8694
8695                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
8696                                 ins = (MonoInst*)call;
8697                                 ins->inst_p0 = cmethod;
8698                                 MONO_ADD_INS (bblock, ins);
8699                         }
8700
8701                         ip += 5;
8702                         start_new_bblock = 1;
8703                         break;
8704                 }
8705                 case CEE_CALLI:
8706                 case CEE_CALL:
8707                 case CEE_CALLVIRT: {
8708                         MonoInst *addr = NULL;
8709                         MonoMethodSignature *fsig = NULL;
8710                         int array_rank = 0;
8711                         int virtual = *ip == CEE_CALLVIRT;
8712                         int calli = *ip == CEE_CALLI;
8713                         gboolean pass_imt_from_rgctx = FALSE;
8714                         MonoInst *imt_arg = NULL;
8715                         MonoInst *keep_this_alive = NULL;
8716                         gboolean pass_vtable = FALSE;
8717                         gboolean pass_mrgctx = FALSE;
8718                         MonoInst *vtable_arg = NULL;
8719                         gboolean check_this = FALSE;
8720                         gboolean supported_tail_call = FALSE;
8721                         gboolean tail_call = FALSE;
8722                         gboolean need_seq_point = FALSE;
8723                         guint32 call_opcode = *ip;
8724                         gboolean emit_widen = TRUE;
8725                         gboolean push_res = TRUE;
8726                         gboolean skip_ret = FALSE;
8727                         gboolean delegate_invoke = FALSE;
8728
8729                         CHECK_OPSIZE (5);
8730                         token = read32 (ip + 1);
8731
8732                         ins = NULL;
8733
8734                         if (calli) {
8735                                 //GSHAREDVT_FAILURE (*ip);
8736                                 cmethod = NULL;
8737                                 CHECK_STACK (1);
8738                                 --sp;
8739                                 addr = *sp;
8740                                 fsig = mini_get_signature (method, token, generic_context);
8741                                 n = fsig->param_count + fsig->hasthis;
8742
8743                                 if (method->dynamic && fsig->pinvoke) {
8744                                         MonoInst *args [3];
8745
8746                                         /*
8747                                          * This is a call through a function pointer using a pinvoke
8748                                          * signature. Have to create a wrapper and call that instead.
8749                                          * FIXME: This is very slow, need to create a wrapper at JIT time
8750                                          * instead based on the signature.
8751                                          */
8752                                         EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
8753                                         EMIT_NEW_PCONST (cfg, args [1], fsig);
8754                                         args [2] = addr;
8755                                         addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
8756                                 }
8757                         } else {
8758                                 MonoMethod *cil_method;
8759
8760                                 cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8761                                 cil_method = cmethod;
8762                                 
8763                                 if (constrained_call) {
8764                                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
8765                                                 if (cfg->verbose_level > 2)
8766                                                         printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_call));
8767                                                 if (!((constrained_call->byval_arg.type == MONO_TYPE_VAR ||
8768                                                            constrained_call->byval_arg.type == MONO_TYPE_MVAR) &&
8769                                                           cfg->generic_sharing_context)) {
8770                                                         cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_call, generic_context, &cfg->error);
8771                                                         CHECK_CFG_ERROR;
8772                                                 }
8773                                         } else {
8774                                                 if (cfg->verbose_level > 2)
8775                                                         printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_call));
8776
8777                                                 if ((constrained_call->byval_arg.type == MONO_TYPE_VAR || constrained_call->byval_arg.type == MONO_TYPE_MVAR) && cfg->generic_sharing_context) {
8778                                                         /* 
8779                                                          * This is needed since get_method_constrained can't find 
8780                                                          * the method in klass representing a type var.
8781                                                          * The type var is guaranteed to be a reference type in this
8782                                                          * case.
8783                                                          */
8784                                                         if (!mini_is_gsharedvt_klass (cfg, constrained_call))
8785                                                                 g_assert (!cmethod->klass->valuetype);
8786                                                 } else {
8787                                                         cmethod = mono_get_method_constrained_checked (image, token, constrained_call, generic_context, &cil_method, &cfg->error);
8788                                                         CHECK_CFG_ERROR;
8789                                                 }
8790                                         }
8791                                 }
8792                                         
8793                                 if (!cmethod || mono_loader_get_last_error ())
8794                                         LOAD_ERROR;
8795                                 if (!dont_verify && !cfg->skip_visibility) {
8796                                         MonoMethod *target_method = cil_method;
8797                                         if (method->is_inflated) {
8798                                                 target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context));
8799                                         }
8800                                         if (!mono_method_can_access_method (method_definition, target_method) &&
8801                                                 !mono_method_can_access_method (method, cil_method))
8802                                                 METHOD_ACCESS_FAILURE (method, cil_method);
8803                                 }
8804
8805                                 if (mono_security_core_clr_enabled ())
8806                                         ensure_method_is_allowed_to_call_method (cfg, method, cil_method, bblock, ip);
8807
8808                                 if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
8809                                         /* MS.NET seems to silently convert this to a callvirt */
8810                                         virtual = 1;
8811
8812                                 {
8813                                         /*
8814                                          * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
8815                                          * converts to a callvirt.
8816                                          *
8817                                          * tests/bug-515884.il is an example of this behavior
8818                                          */
8819                                         const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
8820                                         const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
8821                                         if (!virtual && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
8822                                                 virtual = 1;
8823                                 }
8824
8825                                 if (!cmethod->klass->inited)
8826                                         if (!mono_class_init (cmethod->klass))
8827                                                 TYPE_LOAD_ERROR (cmethod->klass);
8828
8829                                 if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
8830                                     mini_class_is_system_array (cmethod->klass)) {
8831                                         array_rank = cmethod->klass->rank;
8832                                         fsig = mono_method_signature (cmethod);
8833                                 } else {
8834                                         fsig = mono_method_signature (cmethod);
8835
8836                                         if (!fsig)
8837                                                 LOAD_ERROR;
8838
8839                                         if (fsig->pinvoke) {
8840                                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod,
8841                                                         check_for_pending_exc, cfg->compile_aot);
8842                                                 fsig = mono_method_signature (wrapper);
8843                                         } else if (constrained_call) {
8844                                                 fsig = mono_method_signature (cmethod);
8845                                         } else {
8846                                                 fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
8847                                                 CHECK_CFG_ERROR;
8848                                         }
8849                                 }
8850
8851                                 mono_save_token_info (cfg, image, token, cil_method);
8852
8853                                 if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip + 5 - header->code)))
8854                                         need_seq_point = TRUE;
8855
8856                                 n = fsig->param_count + fsig->hasthis;
8857
8858                                 /* Don't support calls made using type arguments for now */
8859                                 /*
8860                                 if (cfg->gsharedvt) {
8861                                         if (mini_is_gsharedvt_signature (cfg, fsig))
8862                                                 GSHAREDVT_FAILURE (*ip);
8863                                 }
8864                                 */
8865
8866                                 if (mono_security_cas_enabled ()) {
8867                                         if (check_linkdemand (cfg, method, cmethod))
8868                                                 INLINE_FAILURE ("linkdemand");
8869                                         CHECK_CFG_EXCEPTION;
8870                                 }
8871
8872                                 if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
8873                                         g_assert_not_reached ();
8874                         }
8875
8876                         if (!cfg->generic_sharing_context && cmethod && cmethod->klass->generic_container)
8877                                 UNVERIFIED;
8878
8879                         if (!cfg->generic_sharing_context && cmethod)
8880                                 g_assert (!mono_method_check_context_used (cmethod));
8881
8882                         CHECK_STACK (n);
8883
8884                         //g_assert (!virtual || fsig->hasthis);
8885
8886                         sp -= n;
8887
8888                         if (constrained_call) {
8889                                 if (mini_is_gsharedvt_klass (cfg, constrained_call)) {
8890                                         if ((cmethod->klass != mono_defaults.object_class) && constrained_call->valuetype && cmethod->klass->valuetype) {
8891                                                 /* The 'Own method' case below */
8892                                         } else if (cmethod->klass->image != mono_defaults.corlib && !(cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !cmethod->klass->valuetype) {
8893                                                 /* 'The type parameter is instantiated as a reference type' case below. */
8894                                         } else {
8895                                                 ins = handle_constrained_gsharedvt_call (cfg, cmethod, fsig, sp, constrained_call, &emit_widen, &bblock);
8896                                                 CHECK_CFG_EXCEPTION;
8897                                                 g_assert (ins);
8898                                                 goto call_end;
8899                                         }
8900                                 }
8901
8902                                 /*
8903                                  * We have the `constrained.' prefix opcode.
8904                                  */
8905                                 if (constrained_call->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
8906                                         /*
8907                                          * The type parameter is instantiated as a valuetype,
8908                                          * but that type doesn't override the method we're
8909                                          * calling, so we need to box `this'.
8910                                          */
8911                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_call->byval_arg, sp [0]->dreg, 0);
8912                                         ins->klass = constrained_call;
8913                                         sp [0] = handle_box (cfg, ins, constrained_call, mono_class_check_context_used (constrained_call), &bblock);
8914                                         CHECK_CFG_EXCEPTION;
8915                                 } else if (!constrained_call->valuetype) {
8916                                         int dreg = alloc_ireg_ref (cfg);
8917
8918                                         /*
8919                                          * The type parameter is instantiated as a reference
8920                                          * type.  We have a managed pointer on the stack, so
8921                                          * we need to dereference it here.
8922                                          */
8923                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
8924                                         ins->type = STACK_OBJ;
8925                                         sp [0] = ins;
8926                                 } else {
8927                                         if (cmethod->klass->valuetype) {
8928                                                 /* Own method */
8929                                         } else {
8930                                                 /* Interface method */
8931                                                 int ioffset, slot;
8932
8933                                                 mono_class_setup_vtable (constrained_call);
8934                                                 CHECK_TYPELOAD (constrained_call);
8935                                                 ioffset = mono_class_interface_offset (constrained_call, cmethod->klass);
8936                                                 if (ioffset == -1)
8937                                                         TYPE_LOAD_ERROR (constrained_call);
8938                                                 slot = mono_method_get_vtable_slot (cmethod);
8939                                                 if (slot == -1)
8940                                                         TYPE_LOAD_ERROR (cmethod->klass);
8941                                                 cmethod = constrained_call->vtable [ioffset + slot];
8942
8943                                                 if (cmethod->klass == mono_defaults.enum_class) {
8944                                                         /* Enum implements some interfaces, so treat this as the first case */
8945                                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_call->byval_arg, sp [0]->dreg, 0);
8946                                                         ins->klass = constrained_call;
8947                                                         sp [0] = handle_box (cfg, ins, constrained_call, mono_class_check_context_used (constrained_call), &bblock);
8948                                                         CHECK_CFG_EXCEPTION;
8949                                                 }
8950                                         }
8951                                         virtual = 0;
8952                                 }
8953                                 constrained_call = NULL;
8954                         }
8955
8956                         if (!calli && check_call_signature (cfg, fsig, sp))
8957                                 UNVERIFIED;
8958
8959 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
8960                         if (cmethod && (cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
8961                                 delegate_invoke = TRUE;
8962 #endif
8963
8964                         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
8965                                 bblock = cfg->cbb;
8966                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8967                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
8968                                         emit_widen = FALSE;
8969                                 }
8970
8971                                 goto call_end;
8972                         }
8973
8974                         /* 
8975                          * If the callee is a shared method, then its static cctor
8976                          * might not get called after the call was patched.
8977                          */
8978                         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)) {
8979                                 emit_generic_class_init (cfg, cmethod->klass);
8980                                 CHECK_TYPELOAD (cmethod->klass);
8981                         }
8982
8983                         if (cmethod)
8984                                 check_method_sharing (cfg, cmethod, &pass_vtable, &pass_mrgctx);
8985
8986                         if (cfg->generic_sharing_context && cmethod) {
8987                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
8988
8989                                 context_used = mini_method_check_context_used (cfg, cmethod);
8990
8991                                 if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
8992                                         /* Generic method interface
8993                                            calls are resolved via a
8994                                            helper function and don't
8995                                            need an imt. */
8996                                         if (!cmethod_context || !cmethod_context->method_inst)
8997                                                 pass_imt_from_rgctx = TRUE;
8998                                 }
8999
9000                                 /*
9001                                  * If a shared method calls another
9002                                  * shared method then the caller must
9003                                  * have a generic sharing context
9004                                  * because the magic trampoline
9005                                  * requires it.  FIXME: We shouldn't
9006                                  * have to force the vtable/mrgctx
9007                                  * variable here.  Instead there
9008                                  * should be a flag in the cfg to
9009                                  * request a generic sharing context.
9010                                  */
9011                                 if (context_used &&
9012                                                 ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
9013                                         mono_get_vtable_var (cfg);
9014                         }
9015
9016                         if (pass_vtable) {
9017                                 if (context_used) {
9018                                         vtable_arg = emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
9019                                 } else {
9020                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
9021
9022                                         CHECK_TYPELOAD (cmethod->klass);
9023                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
9024                                 }
9025                         }
9026
9027                         if (pass_mrgctx) {
9028                                 g_assert (!vtable_arg);
9029
9030                                 if (!cfg->compile_aot) {
9031                                         /* 
9032                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
9033                                          * for type load errors before.
9034                                          */
9035                                         mono_class_setup_vtable (cmethod->klass);
9036                                         CHECK_TYPELOAD (cmethod->klass);
9037                                 }
9038
9039                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
9040
9041                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
9042                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
9043                                          MONO_METHOD_IS_FINAL (cmethod)) &&
9044                                         !mono_class_is_marshalbyref (cmethod->klass)) {
9045                                         if (virtual)
9046                                                 check_this = TRUE;
9047                                         virtual = 0;
9048                                 }
9049                         }
9050
9051                         if (pass_imt_from_rgctx) {
9052                                 g_assert (!pass_vtable);
9053                                 g_assert (cmethod);
9054
9055                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9056                                         cmethod, MONO_RGCTX_INFO_METHOD);
9057                         }
9058
9059                         if (check_this)
9060                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9061
9062                         /* Calling virtual generic methods */
9063                         if (cmethod && virtual && 
9064                             (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) && 
9065                             !(MONO_METHOD_IS_FINAL (cmethod) && 
9066                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
9067                             fsig->generic_param_count && 
9068                                 !(cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))) {
9069                                 MonoInst *this_temp, *this_arg_temp, *store;
9070                                 MonoInst *iargs [4];
9071                                 gboolean use_imt = FALSE;
9072
9073                                 g_assert (fsig->is_inflated);
9074
9075                                 /* Prevent inlining of methods that contain indirect calls */
9076                                 INLINE_FAILURE ("virtual generic call");
9077
9078                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))
9079                                         GSHAREDVT_FAILURE (*ip);
9080
9081 #if MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK && defined(MONO_ARCH_GSHARED_SUPPORTED)
9082                                 if (cmethod->wrapper_type == MONO_WRAPPER_NONE && mono_use_imt)
9083                                         use_imt = TRUE;
9084 #endif
9085
9086                                 if (use_imt) {
9087                                         g_assert (!imt_arg);
9088                                         if (!context_used)
9089                                                 g_assert (cmethod->is_inflated);
9090                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
9091                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
9092                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, sp [0], imt_arg, NULL);
9093                                 } else {
9094                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
9095                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
9096                                         MONO_ADD_INS (bblock, store);
9097
9098                                         /* FIXME: This should be a managed pointer */
9099                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
9100
9101                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
9102                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
9103                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
9104                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
9105                                         addr = mono_emit_jit_icall (cfg,
9106                                                                                                 mono_helper_compile_generic_method, iargs);
9107
9108                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
9109
9110                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9111                                 }
9112
9113                                 goto call_end;
9114                         }
9115
9116                         /*
9117                          * Implement a workaround for the inherent races involved in locking:
9118                          * Monitor.Enter ()
9119                          * try {
9120                          * } finally {
9121                          *    Monitor.Exit ()
9122                          * }
9123                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
9124                          * try block, the Exit () won't be executed, see:
9125                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
9126                          * To work around this, we extend such try blocks to include the last x bytes
9127                          * of the Monitor.Enter () call.
9128                          */
9129                         if (cmethod && cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
9130                                 MonoBasicBlock *tbb;
9131
9132                                 GET_BBLOCK (cfg, tbb, ip + 5);
9133                                 /* 
9134                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
9135                                  * from Monitor.Enter like ArgumentNullException.
9136                                  */
9137                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
9138                                         /* Mark this bblock as needing to be extended */
9139                                         tbb->extend_try_block = TRUE;
9140                                 }
9141                         }
9142
9143                         /* Conversion to a JIT intrinsic */
9144                         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
9145                                 bblock = cfg->cbb;
9146                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9147                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9148                                         emit_widen = FALSE;
9149                                 }
9150                                 goto call_end;
9151                         }
9152
9153                         /* Inlining */
9154                         if (cmethod && (cfg->opt & MONO_OPT_INLINE) &&
9155                                 (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
9156                             mono_method_check_inlining (cfg, cmethod)) {
9157                                 int costs;
9158                                 gboolean always = FALSE;
9159
9160                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
9161                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
9162                                         /* Prevent inlining of methods that call wrappers */
9163                                         INLINE_FAILURE ("wrapper call");
9164                                         cmethod = mono_marshal_get_native_wrapper (cmethod, check_for_pending_exc, FALSE);
9165                                         always = TRUE;
9166                                 }
9167
9168                                 costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, always, &bblock);
9169                                 if (costs) {
9170                                         cfg->real_offset += 5;
9171
9172                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9173                                                 /* *sp is already set by inline_method */
9174                                                 sp++;
9175                                                 push_res = FALSE;
9176                                         }
9177
9178                                         inline_costs += costs;
9179
9180                                         goto call_end;
9181                                 }
9182                         }
9183
9184                         /* Tail recursion elimination */
9185                         if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
9186                                 gboolean has_vtargs = FALSE;
9187                                 int i;
9188
9189                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9190                                 INLINE_FAILURE ("tail call");
9191
9192                                 /* keep it simple */
9193                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
9194                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
9195                                                 has_vtargs = TRUE;
9196                                 }
9197
9198                                 if (!has_vtargs) {
9199                                         for (i = 0; i < n; ++i)
9200                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9201                                         MONO_INST_NEW (cfg, ins, OP_BR);
9202                                         MONO_ADD_INS (bblock, ins);
9203                                         tblock = start_bblock->out_bb [0];
9204                                         link_bblock (cfg, bblock, tblock);
9205                                         ins->inst_target_bb = tblock;
9206                                         start_new_bblock = 1;
9207
9208                                         /* skip the CEE_RET, too */
9209                                         if (ip_in_bb (cfg, bblock, ip + 5))
9210                                                 skip_ret = TRUE;
9211                                         push_res = FALSE;
9212                                         goto call_end;
9213                                 }
9214                         }
9215
9216                         inline_costs += 10 * num_calls++;
9217
9218                         /*
9219                          * Making generic calls out of gsharedvt methods.
9220                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9221                          * patching gshared method addresses into a gsharedvt method.
9222                          */
9223                         if (cmethod && cfg->gsharedvt && (mini_is_gsharedvt_signature (cfg, fsig) || cmethod->is_inflated || cmethod->klass->generic_class) &&
9224                                 !(cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY)) {
9225                                 MonoRgctxInfoType info_type;
9226
9227                                 if (virtual) {
9228                                         //if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
9229                                                 //GSHAREDVT_FAILURE (*ip);
9230                                         // disable for possible remoting calls
9231                                         if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
9232                                                 GSHAREDVT_FAILURE (*ip);
9233                                         if (fsig->generic_param_count) {
9234                                                 /* virtual generic call */
9235                                                 g_assert (mono_use_imt);
9236                                                 g_assert (!imt_arg);
9237                                                 /* Same as the virtual generic case above */
9238                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9239                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9240                                                 /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
9241                                                 vtable_arg = NULL;
9242                                         } else if ((cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !imt_arg) {
9243                                                 /* This can happen when we call a fully instantiated iface method */
9244                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9245                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9246                                                 vtable_arg = NULL;
9247                                         }
9248                                 }
9249
9250                                 if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
9251                                         keep_this_alive = sp [0];
9252
9253                                 if (virtual && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
9254                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
9255                                 else
9256                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
9257                                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
9258
9259                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9260                                 goto call_end;
9261                         } else if (calli && cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig)) {
9262                                 /*
9263                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
9264                                  */
9265                                 MonoInst *callee = addr;
9266
9267                                 if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
9268                                         /* Not tested */
9269                                         GSHAREDVT_FAILURE (*ip);
9270
9271                                 addr = emit_get_rgctx_sig (cfg, context_used,
9272                                                                                           fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
9273                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
9274                                 goto call_end;
9275                         }
9276
9277                         /* Generic sharing */
9278
9279                         /*
9280                          * Use this if the callee is gsharedvt sharable too, since
9281                          * at runtime we might find an instantiation so the call cannot
9282                          * be patched (the 'no_patch' code path in mini-trampolines.c).
9283                          */
9284                         if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
9285                                 (!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
9286                                  !mono_class_generic_sharing_enabled (cmethod->klass)) &&
9287                                 (!virtual || MONO_METHOD_IS_FINAL (cmethod) ||
9288                                  !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
9289                                 INLINE_FAILURE ("gshared");
9290
9291                                 g_assert (cfg->generic_sharing_context && cmethod);
9292                                 g_assert (!addr);
9293
9294                                 /*
9295                                  * We are compiling a call to a
9296                                  * generic method from shared code,
9297                                  * which means that we have to look up
9298                                  * the method in the rgctx and do an
9299                                  * indirect call.
9300                                  */
9301                                 if (fsig->hasthis)
9302                                         MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9303
9304                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9305                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9306                                 goto call_end;
9307                         }
9308
9309                         /* Indirect calls */
9310                         if (addr) {
9311                                 if (call_opcode == CEE_CALL)
9312                                         g_assert (context_used);
9313                                 else if (call_opcode == CEE_CALLI)
9314                                         g_assert (!vtable_arg);
9315                                 else
9316                                         /* FIXME: what the hell is this??? */
9317                                         g_assert (cmethod->flags & METHOD_ATTRIBUTE_FINAL ||
9318                                                         !(cmethod->flags & METHOD_ATTRIBUTE_FINAL));
9319
9320                                 /* Prevent inlining of methods with indirect calls */
9321                                 INLINE_FAILURE ("indirect call");
9322
9323                                 if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
9324                                         int info_type;
9325                                         gpointer info_data;
9326
9327                                         /* 
9328                                          * Instead of emitting an indirect call, emit a direct call
9329                                          * with the contents of the aotconst as the patch info.
9330                                          */
9331                                         if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
9332                                                 info_type = addr->inst_c1;
9333                                                 info_data = addr->inst_p0;
9334                                         } else {
9335                                                 info_type = addr->inst_right->inst_c1;
9336                                                 info_data = addr->inst_right->inst_left;
9337                                         }
9338                                         
9339                                         if (info_type == MONO_PATCH_INFO_ICALL_ADDR || info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
9340                                                 ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
9341                                                 NULLIFY_INS (addr);
9342                                                 goto call_end;
9343                                         }
9344                                 }
9345                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9346                                 goto call_end;
9347                         }
9348                                         
9349                         /* Array methods */
9350                         if (array_rank) {
9351                                 MonoInst *addr;
9352
9353                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
9354                                         MonoInst *val = sp [fsig->param_count];
9355
9356                                         if (val->type == STACK_OBJ) {
9357                                                 MonoInst *iargs [2];
9358
9359                                                 iargs [0] = sp [0];
9360                                                 iargs [1] = val;
9361                                                 
9362                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
9363                                         }
9364                                         
9365                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
9366                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
9367                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !(val->opcode == OP_PCONST && val->inst_c0 == 0))
9368                                                 emit_write_barrier (cfg, addr, val);
9369                                         if (cfg->gen_write_barriers && mini_is_gsharedvt_klass (cfg, cmethod->klass))
9370                                                 GSHAREDVT_FAILURE (*ip);
9371                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
9372                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9373
9374                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
9375                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
9376                                         if (!cmethod->klass->element_class->valuetype && !readonly)
9377                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
9378                                         CHECK_TYPELOAD (cmethod->klass);
9379                                         
9380                                         readonly = FALSE;
9381                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9382                                         ins = addr;
9383                                 } else {
9384                                         g_assert_not_reached ();
9385                                 }
9386
9387                                 emit_widen = FALSE;
9388                                 goto call_end;
9389                         }
9390
9391                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL);
9392                         if (ins)
9393                                 goto call_end;
9394
9395                         /* Tail prefix / tail call optimization */
9396
9397                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
9398                         /* FIXME: runtime generic context pointer for jumps? */
9399                         /* FIXME: handle this for generic sharing eventually */
9400                         if (cmethod && (ins_flag & MONO_INST_TAILCALL) &&
9401                                 !vtable_arg && !cfg->generic_sharing_context && is_supported_tail_call (cfg, method, cmethod, fsig, call_opcode))
9402                                 supported_tail_call = TRUE;
9403
9404                         if (supported_tail_call) {
9405                                 MonoCallInst *call;
9406
9407                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9408                                 INLINE_FAILURE ("tail call");
9409
9410                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
9411
9412                                 if (ARCH_HAVE_OP_TAIL_CALL) {
9413                                         /* Handle tail calls similarly to normal calls */
9414                                         tail_call = TRUE;
9415                                 } else {
9416                                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
9417
9418                                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9419                                         call->tail_call = TRUE;
9420                                         call->method = cmethod;
9421                                         call->signature = mono_method_signature (cmethod);
9422
9423                                         /*
9424                                          * We implement tail calls by storing the actual arguments into the 
9425                                          * argument variables, then emitting a CEE_JMP.
9426                                          */
9427                                         for (i = 0; i < n; ++i) {
9428                                                 /* Prevent argument from being register allocated */
9429                                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
9430                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9431                                         }
9432                                         ins = (MonoInst*)call;
9433                                         ins->inst_p0 = cmethod;
9434                                         ins->inst_p1 = arg_array [0];
9435                                         MONO_ADD_INS (bblock, ins);
9436                                         link_bblock (cfg, bblock, end_bblock);                  
9437                                         start_new_bblock = 1;
9438
9439                                         // FIXME: Eliminate unreachable epilogs
9440
9441                                         /*
9442                                          * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9443                                          * only reachable from this call.
9444                                          */
9445                                         GET_BBLOCK (cfg, tblock, ip + 5);
9446                                         if (tblock == bblock || tblock->in_count == 0)
9447                                                 skip_ret = TRUE;
9448                                         push_res = FALSE;
9449
9450                                         goto call_end;
9451                                 }
9452                         }
9453
9454                         /* 
9455                          * Synchronized wrappers.
9456                          * Its hard to determine where to replace a method with its synchronized
9457                          * wrapper without causing an infinite recursion. The current solution is
9458                          * to add the synchronized wrapper in the trampolines, and to
9459                          * change the called method to a dummy wrapper, and resolve that wrapper
9460                          * to the real method in mono_jit_compile_method ().
9461                          */
9462                         if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
9463                                 MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
9464                                 if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
9465                                         cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
9466                         }
9467
9468                         /* Common call */
9469                         INLINE_FAILURE ("call");
9470                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual ? sp [0] : NULL,
9471                                                                                           imt_arg, vtable_arg);
9472
9473                         if (tail_call) {
9474                                 link_bblock (cfg, bblock, end_bblock);                  
9475                                 start_new_bblock = 1;
9476
9477                                 // FIXME: Eliminate unreachable epilogs
9478
9479                                 /*
9480                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9481                                  * only reachable from this call.
9482                                  */
9483                                 GET_BBLOCK (cfg, tblock, ip + 5);
9484                                 if (tblock == bblock || tblock->in_count == 0)
9485                                         skip_ret = TRUE;
9486                                 push_res = FALSE;
9487                         }
9488
9489                         call_end:
9490
9491                         /* End of call, INS should contain the result of the call, if any */
9492
9493                         if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
9494                                 g_assert (ins);
9495                                 if (emit_widen)
9496                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
9497                                 else
9498                                         *sp++ = ins;
9499                         }
9500
9501                         if (keep_this_alive) {
9502                                 MonoInst *dummy_use;
9503
9504                                 /* See mono_emit_method_call_full () */
9505                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
9506                         }
9507
9508                         CHECK_CFG_EXCEPTION;
9509
9510                         ip += 5;
9511                         if (skip_ret) {
9512                                 g_assert (*ip == CEE_RET);
9513                                 ip += 1;
9514                         }
9515                         ins_flag = 0;
9516                         constrained_call = NULL;
9517                         if (need_seq_point)
9518                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
9519                         break;
9520                 }
9521                 case CEE_RET:
9522                         if (cfg->method != method) {
9523                                 /* return from inlined method */
9524                                 /* 
9525                                  * If in_count == 0, that means the ret is unreachable due to
9526                                  * being preceeded by a throw. In that case, inline_method () will
9527                                  * handle setting the return value 
9528                                  * (test case: test_0_inline_throw ()).
9529                                  */
9530                                 if (return_var && cfg->cbb->in_count) {
9531                                         MonoType *ret_type = mono_method_signature (method)->ret;
9532
9533                                         MonoInst *store;
9534                                         CHECK_STACK (1);
9535                                         --sp;
9536
9537                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9538                                                 UNVERIFIED;
9539
9540                                         //g_assert (returnvar != -1);
9541                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
9542                                         cfg->ret_var_set = TRUE;
9543                                 } 
9544                         } else {
9545                                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
9546
9547                                 if (cfg->lmf_var && cfg->cbb->in_count)
9548                                         emit_pop_lmf (cfg);
9549
9550                                 if (cfg->ret) {
9551                                         MonoType *ret_type = mini_replace_type (mono_method_signature (method)->ret);
9552
9553                                         if (seq_points && !sym_seq_points) {
9554                                                 /* 
9555                                                  * Place a seq point here too even through the IL stack is not
9556                                                  * empty, so a step over on
9557                                                  * call <FOO>
9558                                                  * ret
9559                                                  * will work correctly.
9560                                                  */
9561                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
9562                                                 MONO_ADD_INS (cfg->cbb, ins);
9563                                         }
9564
9565                                         g_assert (!return_var);
9566                                         CHECK_STACK (1);
9567                                         --sp;
9568
9569                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9570                                                 UNVERIFIED;
9571
9572                                         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
9573                                                 MonoInst *ret_addr;
9574
9575                                                 if (!cfg->vret_addr) {
9576                                                         MonoInst *ins;
9577
9578                                                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, (*sp));
9579                                                 } else {
9580                                                         EMIT_NEW_RETLOADA (cfg, ret_addr);
9581
9582                                                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, (*sp)->dreg);
9583                                                         ins->klass = mono_class_from_mono_type (ret_type);
9584                                                 }
9585                                         } else {
9586 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
9587                                                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
9588                                                         MonoInst *iargs [1];
9589                                                         MonoInst *conv;
9590
9591                                                         iargs [0] = *sp;
9592                                                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
9593                                                         mono_arch_emit_setret (cfg, method, conv);
9594                                                 } else {
9595                                                         mono_arch_emit_setret (cfg, method, *sp);
9596                                                 }
9597 #else
9598                                                 mono_arch_emit_setret (cfg, method, *sp);
9599 #endif
9600                                         }
9601                                 }
9602                         }
9603                         if (sp != stack_start)
9604                                 UNVERIFIED;
9605                         MONO_INST_NEW (cfg, ins, OP_BR);
9606                         ip++;
9607                         ins->inst_target_bb = end_bblock;
9608                         MONO_ADD_INS (bblock, ins);
9609                         link_bblock (cfg, bblock, end_bblock);
9610                         start_new_bblock = 1;
9611                         break;
9612                 case CEE_BR_S:
9613                         CHECK_OPSIZE (2);
9614                         MONO_INST_NEW (cfg, ins, OP_BR);
9615                         ip++;
9616                         target = ip + 1 + (signed char)(*ip);
9617                         ++ip;
9618                         GET_BBLOCK (cfg, tblock, target);
9619                         link_bblock (cfg, bblock, tblock);
9620                         ins->inst_target_bb = tblock;
9621                         if (sp != stack_start) {
9622                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9623                                 sp = stack_start;
9624                                 CHECK_UNVERIFIABLE (cfg);
9625                         }
9626                         MONO_ADD_INS (bblock, ins);
9627                         start_new_bblock = 1;
9628                         inline_costs += BRANCH_COST;
9629                         break;
9630                 case CEE_BEQ_S:
9631                 case CEE_BGE_S:
9632                 case CEE_BGT_S:
9633                 case CEE_BLE_S:
9634                 case CEE_BLT_S:
9635                 case CEE_BNE_UN_S:
9636                 case CEE_BGE_UN_S:
9637                 case CEE_BGT_UN_S:
9638                 case CEE_BLE_UN_S:
9639                 case CEE_BLT_UN_S:
9640                         CHECK_OPSIZE (2);
9641                         CHECK_STACK (2);
9642                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
9643                         ip++;
9644                         target = ip + 1 + *(signed char*)ip;
9645                         ip++;
9646
9647                         ADD_BINCOND (NULL);
9648
9649                         sp = stack_start;
9650                         inline_costs += BRANCH_COST;
9651                         break;
9652                 case CEE_BR:
9653                         CHECK_OPSIZE (5);
9654                         MONO_INST_NEW (cfg, ins, OP_BR);
9655                         ip++;
9656
9657                         target = ip + 4 + (gint32)read32(ip);
9658                         ip += 4;
9659                         GET_BBLOCK (cfg, tblock, target);
9660                         link_bblock (cfg, bblock, tblock);
9661                         ins->inst_target_bb = tblock;
9662                         if (sp != stack_start) {
9663                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9664                                 sp = stack_start;
9665                                 CHECK_UNVERIFIABLE (cfg);
9666                         }
9667
9668                         MONO_ADD_INS (bblock, ins);
9669
9670                         start_new_bblock = 1;
9671                         inline_costs += BRANCH_COST;
9672                         break;
9673                 case CEE_BRFALSE_S:
9674                 case CEE_BRTRUE_S:
9675                 case CEE_BRFALSE:
9676                 case CEE_BRTRUE: {
9677                         MonoInst *cmp;
9678                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
9679                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
9680                         guint32 opsize = is_short ? 1 : 4;
9681
9682                         CHECK_OPSIZE (opsize);
9683                         CHECK_STACK (1);
9684                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
9685                                 UNVERIFIED;
9686                         ip ++;
9687                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
9688                         ip += opsize;
9689
9690                         sp--;
9691
9692                         GET_BBLOCK (cfg, tblock, target);
9693                         link_bblock (cfg, bblock, tblock);
9694                         GET_BBLOCK (cfg, tblock, ip);
9695                         link_bblock (cfg, bblock, tblock);
9696
9697                         if (sp != stack_start) {
9698                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9699                                 CHECK_UNVERIFIABLE (cfg);
9700                         }
9701
9702                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
9703                         cmp->sreg1 = sp [0]->dreg;
9704                         type_from_op (cfg, cmp, sp [0], NULL);
9705                         CHECK_TYPE (cmp);
9706
9707 #if SIZEOF_REGISTER == 4
9708                         if (cmp->opcode == OP_LCOMPARE_IMM) {
9709                                 /* Convert it to OP_LCOMPARE */
9710                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
9711                                 ins->type = STACK_I8;
9712                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
9713                                 ins->inst_l = 0;
9714                                 MONO_ADD_INS (bblock, ins);
9715                                 cmp->opcode = OP_LCOMPARE;
9716                                 cmp->sreg2 = ins->dreg;
9717                         }
9718 #endif
9719                         MONO_ADD_INS (bblock, cmp);
9720
9721                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
9722                         type_from_op (cfg, ins, sp [0], NULL);
9723                         MONO_ADD_INS (bblock, ins);
9724                         ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
9725                         GET_BBLOCK (cfg, tblock, target);
9726                         ins->inst_true_bb = tblock;
9727                         GET_BBLOCK (cfg, tblock, ip);
9728                         ins->inst_false_bb = tblock;
9729                         start_new_bblock = 2;
9730
9731                         sp = stack_start;
9732                         inline_costs += BRANCH_COST;
9733                         break;
9734                 }
9735                 case CEE_BEQ:
9736                 case CEE_BGE:
9737                 case CEE_BGT:
9738                 case CEE_BLE:
9739                 case CEE_BLT:
9740                 case CEE_BNE_UN:
9741                 case CEE_BGE_UN:
9742                 case CEE_BGT_UN:
9743                 case CEE_BLE_UN:
9744                 case CEE_BLT_UN:
9745                         CHECK_OPSIZE (5);
9746                         CHECK_STACK (2);
9747                         MONO_INST_NEW (cfg, ins, *ip);
9748                         ip++;
9749                         target = ip + 4 + (gint32)read32(ip);
9750                         ip += 4;
9751
9752                         ADD_BINCOND (NULL);
9753
9754                         sp = stack_start;
9755                         inline_costs += BRANCH_COST;
9756                         break;
9757                 case CEE_SWITCH: {
9758                         MonoInst *src1;
9759                         MonoBasicBlock **targets;
9760                         MonoBasicBlock *default_bblock;
9761                         MonoJumpInfoBBTable *table;
9762                         int offset_reg = alloc_preg (cfg);
9763                         int target_reg = alloc_preg (cfg);
9764                         int table_reg = alloc_preg (cfg);
9765                         int sum_reg = alloc_preg (cfg);
9766                         gboolean use_op_switch;
9767
9768                         CHECK_OPSIZE (5);
9769                         CHECK_STACK (1);
9770                         n = read32 (ip + 1);
9771                         --sp;
9772                         src1 = sp [0];
9773                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
9774                                 UNVERIFIED;
9775
9776                         ip += 5;
9777                         CHECK_OPSIZE (n * sizeof (guint32));
9778                         target = ip + n * sizeof (guint32);
9779
9780                         GET_BBLOCK (cfg, default_bblock, target);
9781                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
9782
9783                         targets = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
9784                         for (i = 0; i < n; ++i) {
9785                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
9786                                 targets [i] = tblock;
9787                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
9788                                 ip += 4;
9789                         }
9790
9791                         if (sp != stack_start) {
9792                                 /* 
9793                                  * Link the current bb with the targets as well, so handle_stack_args
9794                                  * will set their in_stack correctly.
9795                                  */
9796                                 link_bblock (cfg, bblock, default_bblock);
9797                                 for (i = 0; i < n; ++i)
9798                                         link_bblock (cfg, bblock, targets [i]);
9799
9800                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9801                                 sp = stack_start;
9802                                 CHECK_UNVERIFIABLE (cfg);
9803                         }
9804
9805                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
9806                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
9807                         bblock = cfg->cbb;
9808
9809                         for (i = 0; i < n; ++i)
9810                                 link_bblock (cfg, bblock, targets [i]);
9811
9812                         table = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
9813                         table->table = targets;
9814                         table->table_size = n;
9815
9816                         use_op_switch = FALSE;
9817 #ifdef TARGET_ARM
9818                         /* ARM implements SWITCH statements differently */
9819                         /* FIXME: Make it use the generic implementation */
9820                         if (!cfg->compile_aot)
9821                                 use_op_switch = TRUE;
9822 #endif
9823
9824                         if (COMPILE_LLVM (cfg))
9825                                 use_op_switch = TRUE;
9826
9827                         cfg->cbb->has_jump_table = 1;
9828
9829                         if (use_op_switch) {
9830                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
9831                                 ins->sreg1 = src1->dreg;
9832                                 ins->inst_p0 = table;
9833                                 ins->inst_many_bb = targets;
9834                                 ins->klass = GUINT_TO_POINTER (n);
9835                                 MONO_ADD_INS (cfg->cbb, ins);
9836                         } else {
9837                                 if (sizeof (gpointer) == 8)
9838                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
9839                                 else
9840                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
9841
9842 #if SIZEOF_REGISTER == 8
9843                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
9844                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
9845 #endif
9846
9847                                 if (cfg->compile_aot) {
9848                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
9849                                 } else {
9850                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
9851                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
9852                                         ins->inst_p0 = table;
9853                                         ins->dreg = table_reg;
9854                                         MONO_ADD_INS (cfg->cbb, ins);
9855                                 }
9856
9857                                 /* FIXME: Use load_memindex */
9858                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
9859                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
9860                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
9861                         }
9862                         start_new_bblock = 1;
9863                         inline_costs += (BRANCH_COST * 2);
9864                         break;
9865                 }
9866                 case CEE_LDIND_I1:
9867                 case CEE_LDIND_U1:
9868                 case CEE_LDIND_I2:
9869                 case CEE_LDIND_U2:
9870                 case CEE_LDIND_I4:
9871                 case CEE_LDIND_U4:
9872                 case CEE_LDIND_I8:
9873                 case CEE_LDIND_I:
9874                 case CEE_LDIND_R4:
9875                 case CEE_LDIND_R8:
9876                 case CEE_LDIND_REF:
9877                         CHECK_STACK (1);
9878                         --sp;
9879
9880                         switch (*ip) {
9881                         case CEE_LDIND_R4:
9882                         case CEE_LDIND_R8:
9883                                 dreg = alloc_freg (cfg);
9884                                 break;
9885                         case CEE_LDIND_I8:
9886                                 dreg = alloc_lreg (cfg);
9887                                 break;
9888                         case CEE_LDIND_REF:
9889                                 dreg = alloc_ireg_ref (cfg);
9890                                 break;
9891                         default:
9892                                 dreg = alloc_preg (cfg);
9893                         }
9894
9895                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
9896                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
9897                         if (*ip == CEE_LDIND_R4)
9898                                 ins->type = cfg->r4_stack_type;
9899                         ins->flags |= ins_flag;
9900                         MONO_ADD_INS (bblock, ins);
9901                         *sp++ = ins;
9902                         if (ins_flag & MONO_INST_VOLATILE) {
9903                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
9904                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
9905                         }
9906                         ins_flag = 0;
9907                         ++ip;
9908                         break;
9909                 case CEE_STIND_REF:
9910                 case CEE_STIND_I1:
9911                 case CEE_STIND_I2:
9912                 case CEE_STIND_I4:
9913                 case CEE_STIND_I8:
9914                 case CEE_STIND_R4:
9915                 case CEE_STIND_R8:
9916                 case CEE_STIND_I:
9917                         CHECK_STACK (2);
9918                         sp -= 2;
9919
9920                         if (ins_flag & MONO_INST_VOLATILE) {
9921                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
9922                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
9923                         }
9924
9925                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
9926                         ins->flags |= ins_flag;
9927                         ins_flag = 0;
9928
9929                         MONO_ADD_INS (bblock, ins);
9930
9931                         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)))
9932                                 emit_write_barrier (cfg, sp [0], sp [1]);
9933
9934                         inline_costs += 1;
9935                         ++ip;
9936                         break;
9937
9938                 case CEE_MUL:
9939                         CHECK_STACK (2);
9940
9941                         MONO_INST_NEW (cfg, ins, (*ip));
9942                         sp -= 2;
9943                         ins->sreg1 = sp [0]->dreg;
9944                         ins->sreg2 = sp [1]->dreg;
9945                         type_from_op (cfg, ins, sp [0], sp [1]);
9946                         CHECK_TYPE (ins);
9947                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
9948
9949                         /* Use the immediate opcodes if possible */
9950                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
9951                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
9952                                 if (imm_opcode != -1) {
9953                                         ins->opcode = imm_opcode;
9954                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
9955                                         ins->sreg2 = -1;
9956
9957                                         NULLIFY_INS (sp [1]);
9958                                 }
9959                         }
9960
9961                         MONO_ADD_INS ((cfg)->cbb, (ins));
9962
9963                         *sp++ = mono_decompose_opcode (cfg, ins, &bblock);
9964                         ip++;
9965                         break;
9966                 case CEE_ADD:
9967                 case CEE_SUB:
9968                 case CEE_DIV:
9969                 case CEE_DIV_UN:
9970                 case CEE_REM:
9971                 case CEE_REM_UN:
9972                 case CEE_AND:
9973                 case CEE_OR:
9974                 case CEE_XOR:
9975                 case CEE_SHL:
9976                 case CEE_SHR:
9977                 case CEE_SHR_UN:
9978                         CHECK_STACK (2);
9979
9980                         MONO_INST_NEW (cfg, ins, (*ip));
9981                         sp -= 2;
9982                         ins->sreg1 = sp [0]->dreg;
9983                         ins->sreg2 = sp [1]->dreg;
9984                         type_from_op (cfg, ins, sp [0], sp [1]);
9985                         CHECK_TYPE (ins);
9986                         add_widen_op (cfg, ins, &sp [0], &sp [1]);
9987                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
9988
9989                         /* FIXME: Pass opcode to is_inst_imm */
9990
9991                         /* Use the immediate opcodes if possible */
9992                         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)) {
9993                                 int imm_opcode;
9994
9995                                 imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
9996 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
9997                                 /* Keep emulated opcodes which are optimized away later */
9998                                 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) {
9999                                         imm_opcode = mono_op_to_op_imm (ins->opcode);
10000                                 }
10001 #endif
10002                                 if (imm_opcode != -1) {
10003                                         ins->opcode = imm_opcode;
10004                                         if (sp [1]->opcode == OP_I8CONST) {
10005 #if SIZEOF_REGISTER == 8
10006                                                 ins->inst_imm = sp [1]->inst_l;
10007 #else
10008                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
10009                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
10010 #endif
10011                                         }
10012                                         else
10013                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
10014                                         ins->sreg2 = -1;
10015
10016                                         /* Might be followed by an instruction added by add_widen_op */
10017                                         if (sp [1]->next == NULL)
10018                                                 NULLIFY_INS (sp [1]);
10019                                 }
10020                         }
10021                         MONO_ADD_INS ((cfg)->cbb, (ins));
10022
10023                         *sp++ = mono_decompose_opcode (cfg, ins, &bblock);
10024                         ip++;
10025                         break;
10026                 case CEE_NEG:
10027                 case CEE_NOT:
10028                 case CEE_CONV_I1:
10029                 case CEE_CONV_I2:
10030                 case CEE_CONV_I4:
10031                 case CEE_CONV_R4:
10032                 case CEE_CONV_R8:
10033                 case CEE_CONV_U4:
10034                 case CEE_CONV_I8:
10035                 case CEE_CONV_U8:
10036                 case CEE_CONV_OVF_I8:
10037                 case CEE_CONV_OVF_U8:
10038                 case CEE_CONV_R_UN:
10039                         CHECK_STACK (1);
10040
10041                         /* Special case this earlier so we have long constants in the IR */
10042                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
10043                                 int data = sp [-1]->inst_c0;
10044                                 sp [-1]->opcode = OP_I8CONST;
10045                                 sp [-1]->type = STACK_I8;
10046 #if SIZEOF_REGISTER == 8
10047                                 if ((*ip) == CEE_CONV_U8)
10048                                         sp [-1]->inst_c0 = (guint32)data;
10049                                 else
10050                                         sp [-1]->inst_c0 = data;
10051 #else
10052                                 sp [-1]->inst_ls_word = data;
10053                                 if ((*ip) == CEE_CONV_U8)
10054                                         sp [-1]->inst_ms_word = 0;
10055                                 else
10056                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
10057 #endif
10058                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
10059                         }
10060                         else {
10061                                 ADD_UNOP (*ip);
10062                         }
10063                         ip++;
10064                         break;
10065                 case CEE_CONV_OVF_I4:
10066                 case CEE_CONV_OVF_I1:
10067                 case CEE_CONV_OVF_I2:
10068                 case CEE_CONV_OVF_I:
10069                 case CEE_CONV_OVF_U:
10070                         CHECK_STACK (1);
10071
10072                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10073                                 ADD_UNOP (CEE_CONV_OVF_I8);
10074                                 ADD_UNOP (*ip);
10075                         } else {
10076                                 ADD_UNOP (*ip);
10077                         }
10078                         ip++;
10079                         break;
10080                 case CEE_CONV_OVF_U1:
10081                 case CEE_CONV_OVF_U2:
10082                 case CEE_CONV_OVF_U4:
10083                         CHECK_STACK (1);
10084
10085                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10086                                 ADD_UNOP (CEE_CONV_OVF_U8);
10087                                 ADD_UNOP (*ip);
10088                         } else {
10089                                 ADD_UNOP (*ip);
10090                         }
10091                         ip++;
10092                         break;
10093                 case CEE_CONV_OVF_I1_UN:
10094                 case CEE_CONV_OVF_I2_UN:
10095                 case CEE_CONV_OVF_I4_UN:
10096                 case CEE_CONV_OVF_I8_UN:
10097                 case CEE_CONV_OVF_U1_UN:
10098                 case CEE_CONV_OVF_U2_UN:
10099                 case CEE_CONV_OVF_U4_UN:
10100                 case CEE_CONV_OVF_U8_UN:
10101                 case CEE_CONV_OVF_I_UN:
10102                 case CEE_CONV_OVF_U_UN:
10103                 case CEE_CONV_U2:
10104                 case CEE_CONV_U1:
10105                 case CEE_CONV_I:
10106                 case CEE_CONV_U:
10107                         CHECK_STACK (1);
10108                         ADD_UNOP (*ip);
10109                         CHECK_CFG_EXCEPTION;
10110                         ip++;
10111                         break;
10112                 case CEE_ADD_OVF:
10113                 case CEE_ADD_OVF_UN:
10114                 case CEE_MUL_OVF:
10115                 case CEE_MUL_OVF_UN:
10116                 case CEE_SUB_OVF:
10117                 case CEE_SUB_OVF_UN:
10118                         CHECK_STACK (2);
10119                         ADD_BINOP (*ip);
10120                         ip++;
10121                         break;
10122                 case CEE_CPOBJ:
10123                         GSHAREDVT_FAILURE (*ip);
10124                         CHECK_OPSIZE (5);
10125                         CHECK_STACK (2);
10126                         token = read32 (ip + 1);
10127                         klass = mini_get_class (method, token, generic_context);
10128                         CHECK_TYPELOAD (klass);
10129                         sp -= 2;
10130                         if (generic_class_is_reference_type (cfg, klass)) {
10131                                 MonoInst *store, *load;
10132                                 int dreg = alloc_ireg_ref (cfg);
10133
10134                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
10135                                 load->flags |= ins_flag;
10136                                 MONO_ADD_INS (cfg->cbb, load);
10137
10138                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
10139                                 store->flags |= ins_flag;
10140                                 MONO_ADD_INS (cfg->cbb, store);
10141
10142                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
10143                                         emit_write_barrier (cfg, sp [0], sp [1]);
10144                         } else {
10145                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10146                         }
10147                         ins_flag = 0;
10148                         ip += 5;
10149                         break;
10150                 case CEE_LDOBJ: {
10151                         int loc_index = -1;
10152                         int stloc_len = 0;
10153
10154                         CHECK_OPSIZE (5);
10155                         CHECK_STACK (1);
10156                         --sp;
10157                         token = read32 (ip + 1);
10158                         klass = mini_get_class (method, token, generic_context);
10159                         CHECK_TYPELOAD (klass);
10160
10161                         /* Optimize the common ldobj+stloc combination */
10162                         switch (ip [5]) {
10163                         case CEE_STLOC_S:
10164                                 loc_index = ip [6];
10165                                 stloc_len = 2;
10166                                 break;
10167                         case CEE_STLOC_0:
10168                         case CEE_STLOC_1:
10169                         case CEE_STLOC_2:
10170                         case CEE_STLOC_3:
10171                                 loc_index = ip [5] - CEE_STLOC_0;
10172                                 stloc_len = 1;
10173                                 break;
10174                         default:
10175                                 break;
10176                         }
10177
10178                         if ((loc_index != -1) && ip_in_bb (cfg, bblock, ip + 5)) {
10179                                 CHECK_LOCAL (loc_index);
10180
10181                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10182                                 ins->dreg = cfg->locals [loc_index]->dreg;
10183                                 ins->flags |= ins_flag;
10184                                 ip += 5;
10185                                 ip += stloc_len;
10186                                 if (ins_flag & MONO_INST_VOLATILE) {
10187                                         /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10188                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10189                                 }
10190                                 ins_flag = 0;
10191                                 break;
10192                         }
10193
10194                         /* Optimize the ldobj+stobj combination */
10195                         /* The reference case ends up being a load+store anyway */
10196                         /* Skip this if the operation is volatile. */
10197                         if (((ip [5] == CEE_STOBJ) && ip_in_bb (cfg, bblock, ip + 5) && read32 (ip + 6) == token) && !generic_class_is_reference_type (cfg, klass) && !(ins_flag & MONO_INST_VOLATILE)) {
10198                                 CHECK_STACK (1);
10199
10200                                 sp --;
10201
10202                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10203
10204                                 ip += 5 + 5;
10205                                 ins_flag = 0;
10206                                 break;
10207                         }
10208
10209                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10210                         ins->flags |= ins_flag;
10211                         *sp++ = ins;
10212
10213                         if (ins_flag & MONO_INST_VOLATILE) {
10214                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10215                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10216                         }
10217
10218                         ip += 5;
10219                         ins_flag = 0;
10220                         inline_costs += 1;
10221                         break;
10222                 }
10223                 case CEE_LDSTR:
10224                         CHECK_STACK_OVF (1);
10225                         CHECK_OPSIZE (5);
10226                         n = read32 (ip + 1);
10227
10228                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
10229                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
10230                                 ins->type = STACK_OBJ;
10231                                 *sp = ins;
10232                         }
10233                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
10234                                 MonoInst *iargs [1];
10235                                 char *str = mono_method_get_wrapper_data (method, n);
10236
10237                                 if (cfg->compile_aot)
10238                                         EMIT_NEW_LDSTRLITCONST (cfg, iargs [0], str);
10239                                 else
10240                                         EMIT_NEW_PCONST (cfg, iargs [0], str);
10241                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
10242                         } else {
10243                                 if (cfg->opt & MONO_OPT_SHARED) {
10244                                         MonoInst *iargs [3];
10245
10246                                         if (cfg->compile_aot) {
10247                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
10248                                         }
10249                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10250                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
10251                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
10252                                         *sp = mono_emit_jit_icall (cfg, mono_ldstr, iargs);
10253                                         mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
10254                                 } else {
10255                                         if (bblock->out_of_line) {
10256                                                 MonoInst *iargs [2];
10257
10258                                                 if (image == mono_defaults.corlib) {
10259                                                         /* 
10260                                                          * Avoid relocations in AOT and save some space by using a 
10261                                                          * version of helper_ldstr specialized to mscorlib.
10262                                                          */
10263                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
10264                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
10265                                                 } else {
10266                                                         /* Avoid creating the string object */
10267                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
10268                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
10269                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
10270                                                 }
10271                                         } 
10272                                         else
10273                                         if (cfg->compile_aot) {
10274                                                 NEW_LDSTRCONST (cfg, ins, image, n);
10275                                                 *sp = ins;
10276                                                 MONO_ADD_INS (bblock, ins);
10277                                         } 
10278                                         else {
10279                                                 NEW_PCONST (cfg, ins, NULL);
10280                                                 ins->type = STACK_OBJ;
10281                                                 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
10282                                                 if (!ins->inst_p0)
10283                                                         OUT_OF_MEMORY_FAILURE;
10284
10285                                                 *sp = ins;
10286                                                 MONO_ADD_INS (bblock, ins);
10287                                         }
10288                                 }
10289                         }
10290
10291                         sp++;
10292                         ip += 5;
10293                         break;
10294                 case CEE_NEWOBJ: {
10295                         MonoInst *iargs [2];
10296                         MonoMethodSignature *fsig;
10297                         MonoInst this_ins;
10298                         MonoInst *alloc;
10299                         MonoInst *vtable_arg = NULL;
10300
10301                         CHECK_OPSIZE (5);
10302                         token = read32 (ip + 1);
10303                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
10304                         if (!cmethod || mono_loader_get_last_error ())
10305                                 LOAD_ERROR;
10306                         fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
10307                         CHECK_CFG_ERROR;
10308
10309                         mono_save_token_info (cfg, image, token, cmethod);
10310
10311                         if (!mono_class_init (cmethod->klass))
10312                                 TYPE_LOAD_ERROR (cmethod->klass);
10313
10314                         context_used = mini_method_check_context_used (cfg, cmethod);
10315
10316                         if (mono_security_cas_enabled ()) {
10317                                 if (check_linkdemand (cfg, method, cmethod))
10318                                         INLINE_FAILURE ("linkdemand");
10319                                 CHECK_CFG_EXCEPTION;
10320                         } else if (mono_security_core_clr_enabled ()) {
10321                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
10322                         }
10323
10324                         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)) {
10325                                 emit_generic_class_init (cfg, cmethod->klass);
10326                                 CHECK_TYPELOAD (cmethod->klass);
10327                         }
10328
10329                         /*
10330                         if (cfg->gsharedvt) {
10331                                 if (mini_is_gsharedvt_variable_signature (sig))
10332                                         GSHAREDVT_FAILURE (*ip);
10333                         }
10334                         */
10335
10336                         n = fsig->param_count;
10337                         CHECK_STACK (n);
10338
10339                         /* 
10340                          * Generate smaller code for the common newobj <exception> instruction in
10341                          * argument checking code.
10342                          */
10343                         if (bblock->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
10344                                 is_exception_class (cmethod->klass) && n <= 2 &&
10345                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
10346                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
10347                                 MonoInst *iargs [3];
10348
10349                                 sp -= n;
10350
10351                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
10352                                 switch (n) {
10353                                 case 0:
10354                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
10355                                         break;
10356                                 case 1:
10357                                         iargs [1] = sp [0];
10358                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
10359                                         break;
10360                                 case 2:
10361                                         iargs [1] = sp [0];
10362                                         iargs [2] = sp [1];
10363                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
10364                                         break;
10365                                 default:
10366                                         g_assert_not_reached ();
10367                                 }
10368
10369                                 ip += 5;
10370                                 inline_costs += 5;
10371                                 break;
10372                         }
10373
10374                         /* move the args to allow room for 'this' in the first position */
10375                         while (n--) {
10376                                 --sp;
10377                                 sp [1] = sp [0];
10378                         }
10379
10380                         /* check_call_signature () requires sp[0] to be set */
10381                         this_ins.type = STACK_OBJ;
10382                         sp [0] = &this_ins;
10383                         if (check_call_signature (cfg, fsig, sp))
10384                                 UNVERIFIED;
10385
10386                         iargs [0] = NULL;
10387
10388                         if (mini_class_is_system_array (cmethod->klass)) {
10389                                 *sp = emit_get_rgctx_method (cfg, context_used,
10390                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
10391
10392                                 /* Avoid varargs in the common case */
10393                                 if (fsig->param_count == 1)
10394                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
10395                                 else if (fsig->param_count == 2)
10396                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
10397                                 else if (fsig->param_count == 3)
10398                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
10399                                 else if (fsig->param_count == 4)
10400                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
10401                                 else
10402                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
10403                         } else if (cmethod->string_ctor) {
10404                                 g_assert (!context_used);
10405                                 g_assert (!vtable_arg);
10406                                 /* we simply pass a null pointer */
10407                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
10408                                 /* now call the string ctor */
10409                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
10410                         } else {
10411                                 if (cmethod->klass->valuetype) {
10412                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
10413                                         emit_init_rvar (cfg, iargs [0]->dreg, &cmethod->klass->byval_arg);
10414                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
10415
10416                                         alloc = NULL;
10417
10418                                         /* 
10419                                          * The code generated by mini_emit_virtual_call () expects
10420                                          * iargs [0] to be a boxed instance, but luckily the vcall
10421                                          * will be transformed into a normal call there.
10422                                          */
10423                                 } else if (context_used) {
10424                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
10425                                         *sp = alloc;
10426                                 } else {
10427                                         MonoVTable *vtable = NULL;
10428
10429                                         if (!cfg->compile_aot)
10430                                                 vtable = mono_class_vtable (cfg->domain, cmethod->klass);
10431                                         CHECK_TYPELOAD (cmethod->klass);
10432
10433                                         /*
10434                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
10435                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
10436                                          * As a workaround, we call class cctors before allocating objects.
10437                                          */
10438                                         if (mini_field_access_needs_cctor_run (cfg, method, cmethod->klass, vtable) && !(g_slist_find (class_inits, cmethod->klass))) {
10439                                                 mono_emit_abs_call (cfg, MONO_PATCH_INFO_CLASS_INIT, cmethod->klass, helper_sig_class_init_trampoline, NULL);
10440                                                 if (cfg->verbose_level > 2)
10441                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
10442                                                 class_inits = g_slist_prepend (class_inits, cmethod->klass);
10443                                         }
10444
10445                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
10446                                         *sp = alloc;
10447                                 }
10448                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
10449
10450                                 if (alloc)
10451                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
10452
10453                                 /* Now call the actual ctor */
10454                                 handle_ctor_call (cfg, cmethod, fsig, context_used, sp, ip, &bblock, &inline_costs);
10455                                 CHECK_CFG_EXCEPTION;
10456                         }
10457
10458                         if (alloc == NULL) {
10459                                 /* Valuetype */
10460                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
10461                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
10462                                 *sp++= ins;
10463                         } else {
10464                                 *sp++ = alloc;
10465                         }
10466                         
10467                         ip += 5;
10468                         inline_costs += 5;
10469                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip - header->code)))
10470                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10471                         break;
10472                 }
10473                 case CEE_CASTCLASS:
10474                         CHECK_STACK (1);
10475                         --sp;
10476                         CHECK_OPSIZE (5);
10477                         token = read32 (ip + 1);
10478                         klass = mini_get_class (method, token, generic_context);
10479                         CHECK_TYPELOAD (klass);
10480                         if (sp [0]->type != STACK_OBJ)
10481                                 UNVERIFIED;
10482
10483                         ins = handle_castclass (cfg, klass, *sp, ip, &bblock, &inline_costs);
10484                         CHECK_CFG_EXCEPTION;
10485
10486                         *sp ++ = ins;
10487                         ip += 5;
10488                         break;
10489                 case CEE_ISINST: {
10490                         CHECK_STACK (1);
10491                         --sp;
10492                         CHECK_OPSIZE (5);
10493                         token = read32 (ip + 1);
10494                         klass = mini_get_class (method, token, generic_context);
10495                         CHECK_TYPELOAD (klass);
10496                         if (sp [0]->type != STACK_OBJ)
10497                                 UNVERIFIED;
10498  
10499                         context_used = mini_class_check_context_used (cfg, klass);
10500
10501                         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
10502                                 MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
10503                                 MonoInst *args [3];
10504
10505                                 /* obj */
10506                                 args [0] = *sp;
10507
10508                                 /* klass */
10509                                 EMIT_NEW_CLASSCONST (cfg, args [1], klass);
10510
10511                                 /* inline cache*/
10512                                 if (cfg->compile_aot)
10513                                         EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, NULL);
10514                                 else
10515                                         EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
10516
10517                                 *sp++ = mono_emit_method_call (cfg, mono_isinst, args, NULL);
10518                                 ip += 5;
10519                                 inline_costs += 2;
10520                         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
10521                                 MonoMethod *mono_isinst;
10522                                 MonoInst *iargs [1];
10523                                 int costs;
10524
10525                                 mono_isinst = mono_marshal_get_isinst (klass); 
10526                                 iargs [0] = sp [0];
10527
10528                                 costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), 
10529                                                                            iargs, ip, cfg->real_offset, TRUE, &bblock);
10530                                 CHECK_CFG_EXCEPTION;
10531                                 g_assert (costs > 0);
10532                                 
10533                                 ip += 5;
10534                                 cfg->real_offset += 5;
10535
10536                                 *sp++= iargs [0];
10537
10538                                 inline_costs += costs;
10539                         }
10540                         else {
10541                                 ins = handle_isinst (cfg, klass, *sp, context_used);
10542                                 CHECK_CFG_EXCEPTION;
10543                                 bblock = cfg->cbb;
10544                                 *sp ++ = ins;
10545                                 ip += 5;
10546                         }
10547                         break;
10548                 }
10549                 case CEE_UNBOX_ANY: {
10550                         MonoInst *res, *addr;
10551
10552                         CHECK_STACK (1);
10553                         --sp;
10554                         CHECK_OPSIZE (5);
10555                         token = read32 (ip + 1);
10556                         klass = mini_get_class (method, token, generic_context);
10557                         CHECK_TYPELOAD (klass);
10558  
10559                         mono_save_token_info (cfg, image, token, klass);
10560
10561                         context_used = mini_class_check_context_used (cfg, klass);
10562
10563                         if (mini_is_gsharedvt_klass (cfg, klass)) {
10564                                 res = handle_unbox_gsharedvt (cfg, klass, *sp, &bblock);
10565                                 inline_costs += 2;
10566                         } else if (generic_class_is_reference_type (cfg, klass)) {
10567                                 res = handle_castclass (cfg, klass, *sp, ip, &bblock, &inline_costs);
10568                                 CHECK_CFG_EXCEPTION;
10569                         } else if (mono_class_is_nullable (klass)) {
10570                                 res = handle_unbox_nullable (cfg, *sp, klass, context_used);
10571                         } else {
10572                                 addr = handle_unbox (cfg, klass, sp, context_used);
10573                                 /* LDOBJ */
10574                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
10575                                 res = ins;
10576                                 inline_costs += 2;
10577                         }
10578
10579                         *sp ++ = res;
10580                         ip += 5;
10581                         break;
10582                 }
10583                 case CEE_BOX: {
10584                         MonoInst *val;
10585                         MonoClass *enum_class;
10586                         MonoMethod *has_flag;
10587
10588                         CHECK_STACK (1);
10589                         --sp;
10590                         val = *sp;
10591                         CHECK_OPSIZE (5);
10592                         token = read32 (ip + 1);
10593                         klass = mini_get_class (method, token, generic_context);
10594                         CHECK_TYPELOAD (klass);
10595
10596                         mono_save_token_info (cfg, image, token, klass);
10597
10598                         context_used = mini_class_check_context_used (cfg, klass);
10599
10600                         if (generic_class_is_reference_type (cfg, klass)) {
10601                                 *sp++ = val;
10602                                 ip += 5;
10603                                 break;
10604                         }
10605
10606                         if (klass == mono_defaults.void_class)
10607                                 UNVERIFIED;
10608                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
10609                                 UNVERIFIED;
10610                         /* frequent check in generic code: box (struct), brtrue */
10611
10612                         /*
10613                          * Look for:
10614                          *
10615                          *   <push int/long ptr>
10616                          *   <push int/long>
10617                          *   box MyFlags
10618                          *   constrained. MyFlags
10619                          *   callvirt instace bool class [mscorlib] System.Enum::HasFlag (class [mscorlib] System.Enum)
10620                          *
10621                          * If we find this sequence and the operand types on box and constrained
10622                          * are equal, we can emit a specialized instruction sequence instead of
10623                          * the very slow HasFlag () call.
10624                          */
10625                         if ((cfg->opt & MONO_OPT_INTRINS) &&
10626                             /* Cheap checks first. */
10627                             ip + 5 + 6 + 5 < end &&
10628                             ip [5] == CEE_PREFIX1 &&
10629                             ip [6] == CEE_CONSTRAINED_ &&
10630                             ip [11] == CEE_CALLVIRT &&
10631                             ip_in_bb (cfg, bblock, ip + 5 + 6 + 5) &&
10632                             mono_class_is_enum (klass) &&
10633                             (enum_class = mini_get_class (method, read32 (ip + 7), generic_context)) &&
10634                             (has_flag = mini_get_method (cfg, method, read32 (ip + 12), NULL, generic_context)) &&
10635                             has_flag->klass == mono_defaults.enum_class &&
10636                             !strcmp (has_flag->name, "HasFlag") &&
10637                             has_flag->signature->hasthis &&
10638                             has_flag->signature->param_count == 1) {
10639                                 CHECK_TYPELOAD (enum_class);
10640
10641                                 if (enum_class == klass) {
10642                                         MonoInst *enum_this, *enum_flag;
10643
10644                                         ip += 5 + 6 + 5;
10645                                         --sp;
10646
10647                                         enum_this = sp [0];
10648                                         enum_flag = sp [1];
10649
10650                                         *sp++ = handle_enum_has_flag (cfg, klass, enum_this, enum_flag);
10651                                         break;
10652                                 }
10653                         }
10654
10655                         // FIXME: LLVM can't handle the inconsistent bb linking
10656                         if (!mono_class_is_nullable (klass) &&
10657                                 ip + 5 < end && ip_in_bb (cfg, bblock, ip + 5) &&
10658                                 (ip [5] == CEE_BRTRUE || 
10659                                  ip [5] == CEE_BRTRUE_S ||
10660                                  ip [5] == CEE_BRFALSE ||
10661                                  ip [5] == CEE_BRFALSE_S)) {
10662                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
10663                                 int dreg;
10664                                 MonoBasicBlock *true_bb, *false_bb;
10665
10666                                 ip += 5;
10667
10668                                 if (cfg->verbose_level > 3) {
10669                                         printf ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
10670                                         printf ("<box+brtrue opt>\n");
10671                                 }
10672
10673                                 switch (*ip) {
10674                                 case CEE_BRTRUE_S:
10675                                 case CEE_BRFALSE_S:
10676                                         CHECK_OPSIZE (2);
10677                                         ip++;
10678                                         target = ip + 1 + (signed char)(*ip);
10679                                         ip++;
10680                                         break;
10681                                 case CEE_BRTRUE:
10682                                 case CEE_BRFALSE:
10683                                         CHECK_OPSIZE (5);
10684                                         ip++;
10685                                         target = ip + 4 + (gint)(read32 (ip));
10686                                         ip += 4;
10687                                         break;
10688                                 default:
10689                                         g_assert_not_reached ();
10690                                 }
10691
10692                                 /* 
10693                                  * We need to link both bblocks, since it is needed for handling stack
10694                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
10695                                  * Branching to only one of them would lead to inconsistencies, so
10696                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
10697                                  */
10698                                 GET_BBLOCK (cfg, true_bb, target);
10699                                 GET_BBLOCK (cfg, false_bb, ip);
10700
10701                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
10702                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
10703
10704                                 if (sp != stack_start) {
10705                                         handle_stack_args (cfg, stack_start, sp - stack_start);
10706                                         sp = stack_start;
10707                                         CHECK_UNVERIFIABLE (cfg);
10708                                 }
10709
10710                                 if (COMPILE_LLVM (cfg)) {
10711                                         dreg = alloc_ireg (cfg);
10712                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
10713                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
10714
10715                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
10716                                 } else {
10717                                         /* The JIT can't eliminate the iconst+compare */
10718                                         MONO_INST_NEW (cfg, ins, OP_BR);
10719                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
10720                                         MONO_ADD_INS (cfg->cbb, ins);
10721                                 }
10722
10723                                 start_new_bblock = 1;
10724                                 break;
10725                         }
10726
10727                         *sp++ = handle_box (cfg, val, klass, context_used, &bblock);
10728
10729                         CHECK_CFG_EXCEPTION;
10730                         ip += 5;
10731                         inline_costs += 1;
10732                         break;
10733                 }
10734                 case CEE_UNBOX: {
10735                         CHECK_STACK (1);
10736                         --sp;
10737                         CHECK_OPSIZE (5);
10738                         token = read32 (ip + 1);
10739                         klass = mini_get_class (method, token, generic_context);
10740                         CHECK_TYPELOAD (klass);
10741
10742                         mono_save_token_info (cfg, image, token, klass);
10743
10744                         context_used = mini_class_check_context_used (cfg, klass);
10745
10746                         if (mono_class_is_nullable (klass)) {
10747                                 MonoInst *val;
10748
10749                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
10750                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
10751
10752                                 *sp++= ins;
10753                         } else {
10754                                 ins = handle_unbox (cfg, klass, sp, context_used);
10755                                 *sp++ = ins;
10756                         }
10757                         ip += 5;
10758                         inline_costs += 2;
10759                         break;
10760                 }
10761                 case CEE_LDFLD:
10762                 case CEE_LDFLDA:
10763                 case CEE_STFLD:
10764                 case CEE_LDSFLD:
10765                 case CEE_LDSFLDA:
10766                 case CEE_STSFLD: {
10767                         MonoClassField *field;
10768 #ifndef DISABLE_REMOTING
10769                         int costs;
10770 #endif
10771                         guint foffset;
10772                         gboolean is_instance;
10773                         int op;
10774                         gpointer addr = NULL;
10775                         gboolean is_special_static;
10776                         MonoType *ftype;
10777                         MonoInst *store_val = NULL;
10778                         MonoInst *thread_ins;
10779
10780                         op = *ip;
10781                         is_instance = (op == CEE_LDFLD || op == CEE_LDFLDA || op == CEE_STFLD);
10782                         if (is_instance) {
10783                                 if (op == CEE_STFLD) {
10784                                         CHECK_STACK (2);
10785                                         sp -= 2;
10786                                         store_val = sp [1];
10787                                 } else {
10788                                         CHECK_STACK (1);
10789                                         --sp;
10790                                 }
10791                                 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
10792                                         UNVERIFIED;
10793                                 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
10794                                         UNVERIFIED;
10795                         } else {
10796                                 if (op == CEE_STSFLD) {
10797                                         CHECK_STACK (1);
10798                                         sp--;
10799                                         store_val = sp [0];
10800                                 }
10801                         }
10802
10803                         CHECK_OPSIZE (5);
10804                         token = read32 (ip + 1);
10805                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
10806                                 field = mono_method_get_wrapper_data (method, token);
10807                                 klass = field->parent;
10808                         }
10809                         else {
10810                                 field = mono_field_from_token_checked (image, token, &klass, generic_context, &cfg->error);
10811                                 CHECK_CFG_ERROR;
10812                         }
10813                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
10814                                 FIELD_ACCESS_FAILURE (method, field);
10815                         mono_class_init (klass);
10816
10817                         if (is_instance && *ip != CEE_LDFLDA && is_magic_tls_access (field))
10818                                 UNVERIFIED;
10819
10820                         /* if the class is Critical then transparent code cannot access it's fields */
10821                         if (!is_instance && mono_security_core_clr_enabled ())
10822                                 ensure_method_is_allowed_to_access_field (cfg, method, field, bblock, ip);
10823
10824                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
10825                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
10826                         if (mono_security_core_clr_enabled ())
10827                                 ensure_method_is_allowed_to_access_field (cfg, method, field, bblock, ip);
10828                         */
10829
10830                         /*
10831                          * LDFLD etc. is usable on static fields as well, so convert those cases to
10832                          * the static case.
10833                          */
10834                         if (is_instance && field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
10835                                 switch (op) {
10836                                 case CEE_LDFLD:
10837                                         op = CEE_LDSFLD;
10838                                         break;
10839                                 case CEE_STFLD:
10840                                         op = CEE_STSFLD;
10841                                         break;
10842                                 case CEE_LDFLDA:
10843                                         op = CEE_LDSFLDA;
10844                                         break;
10845                                 default:
10846                                         g_assert_not_reached ();
10847                                 }
10848                                 is_instance = FALSE;
10849                         }
10850
10851                         context_used = mini_class_check_context_used (cfg, klass);
10852
10853                         /* INSTANCE CASE */
10854
10855                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
10856                         if (op == CEE_STFLD) {
10857                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
10858                                         UNVERIFIED;
10859 #ifndef DISABLE_REMOTING
10860                                 if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
10861                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
10862                                         MonoInst *iargs [5];
10863
10864                                         GSHAREDVT_FAILURE (op);
10865
10866                                         iargs [0] = sp [0];
10867                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10868                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
10869                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
10870                                                     field->offset);
10871                                         iargs [4] = sp [1];
10872
10873                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
10874                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
10875                                                                                            iargs, ip, cfg->real_offset, TRUE, &bblock);
10876                                                 CHECK_CFG_EXCEPTION;
10877                                                 g_assert (costs > 0);
10878                                                       
10879                                                 cfg->real_offset += 5;
10880
10881                                                 inline_costs += costs;
10882                                         } else {
10883                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
10884                                         }
10885                                 } else
10886 #endif
10887                                 {
10888                                         MonoInst *store;
10889
10890                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
10891
10892                                         if (mini_is_gsharedvt_klass (cfg, klass)) {
10893                                                 MonoInst *offset_ins;
10894
10895                                                 context_used = mini_class_check_context_used (cfg, klass);
10896
10897                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10898                                                 dreg = alloc_ireg_mp (cfg);
10899                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10900                                                 /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
10901                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
10902                                         } else {
10903                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
10904                                         }
10905                                         if (sp [0]->opcode != OP_LDADDR)
10906                                                 store->flags |= MONO_INST_FAULT;
10907
10908                                 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)) {
10909                                         /* insert call to write barrier */
10910                                         MonoInst *ptr;
10911                                         int dreg;
10912
10913                                         dreg = alloc_ireg_mp (cfg);
10914                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
10915                                         emit_write_barrier (cfg, ptr, sp [1]);
10916                                 }
10917
10918                                         store->flags |= ins_flag;
10919                                 }
10920                                 ins_flag = 0;
10921                                 ip += 5;
10922                                 break;
10923                         }
10924
10925 #ifndef DISABLE_REMOTING
10926                         if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
10927                                 MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
10928                                 MonoInst *iargs [4];
10929
10930                                 GSHAREDVT_FAILURE (op);
10931
10932                                 iargs [0] = sp [0];
10933                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10934                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
10935                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
10936                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
10937                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
10938                                                                                    iargs, ip, cfg->real_offset, TRUE, &bblock);
10939                                         CHECK_CFG_EXCEPTION;
10940                                         g_assert (costs > 0);
10941                                                       
10942                                         cfg->real_offset += 5;
10943
10944                                         *sp++ = iargs [0];
10945
10946                                         inline_costs += costs;
10947                                 } else {
10948                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
10949                                         *sp++ = ins;
10950                                 }
10951                         } else 
10952 #endif
10953                         if (is_instance) {
10954                                 if (sp [0]->type == STACK_VTYPE) {
10955                                         MonoInst *var;
10956
10957                                         /* Have to compute the address of the variable */
10958
10959                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
10960                                         if (!var)
10961                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
10962                                         else
10963                                                 g_assert (var->klass == klass);
10964                                         
10965                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
10966                                         sp [0] = ins;
10967                                 }
10968
10969                                 if (op == CEE_LDFLDA) {
10970                                         if (is_magic_tls_access (field)) {
10971                                                 GSHAREDVT_FAILURE (*ip);
10972                                                 ins = sp [0];
10973                                                 *sp++ = create_magic_tls_access (cfg, field, &cached_tls_addr, ins);
10974                                         } else {
10975                                                 if (sp [0]->type == STACK_OBJ) {
10976                                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
10977                                                         MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
10978                                                 }
10979
10980                                                 dreg = alloc_ireg_mp (cfg);
10981
10982                                                 if (mini_is_gsharedvt_klass (cfg, klass)) {
10983                                                         MonoInst *offset_ins;
10984
10985                                                         offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10986                                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10987                                                 } else {
10988                                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
10989                                                 }
10990                                                 ins->klass = mono_class_from_mono_type (field->type);
10991                                                 ins->type = STACK_MP;
10992                                                 *sp++ = ins;
10993                                         }
10994                                 } else {
10995                                         MonoInst *load;
10996
10997                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
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                                                 dreg = alloc_ireg_mp (cfg);
11004                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11005                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
11006                                         } else {
11007                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
11008                                         }
11009                                         load->flags |= ins_flag;
11010                                         if (sp [0]->opcode != OP_LDADDR)
11011                                                 load->flags |= MONO_INST_FAULT;
11012                                         *sp++ = load;
11013                                 }
11014                         }
11015
11016                         if (is_instance) {
11017                                 ins_flag = 0;
11018                                 ip += 5;
11019                                 break;
11020                         }
11021
11022                         /* STATIC CASE */
11023
11024                         /*
11025                          * We can only support shared generic static
11026                          * field access on architectures where the
11027                          * trampoline code has been extended to handle
11028                          * the generic class init.
11029                          */
11030 #ifndef MONO_ARCH_VTABLE_REG
11031                         GENERIC_SHARING_FAILURE (op);
11032 #endif
11033
11034                         context_used = mini_class_check_context_used (cfg, klass);
11035
11036                         ftype = mono_field_get_type (field);
11037
11038                         if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL)
11039                                 UNVERIFIED;
11040
11041                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
11042                          * to be called here.
11043                          */
11044                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
11045                                 mono_class_vtable (cfg->domain, klass);
11046                                 CHECK_TYPELOAD (klass);
11047                         }
11048                         mono_domain_lock (cfg->domain);
11049                         if (cfg->domain->special_static_fields)
11050                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
11051                         mono_domain_unlock (cfg->domain);
11052
11053                         is_special_static = mono_class_field_is_special_static (field);
11054
11055                         if (is_special_static && ((gsize)addr & 0x80000000) == 0)
11056                                 thread_ins = mono_get_thread_intrinsic (cfg);
11057                         else
11058                                 thread_ins = NULL;
11059
11060                         /* Generate IR to compute the field address */
11061                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && thread_ins && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
11062                                 /*
11063                                  * Fast access to TLS data
11064                                  * Inline version of get_thread_static_data () in
11065                                  * threads.c.
11066                                  */
11067                                 guint32 offset;
11068                                 int idx, static_data_reg, array_reg, dreg;
11069
11070                                 GSHAREDVT_FAILURE (op);
11071
11072                                 // offset &= 0x7fffffff;
11073                                 // idx = (offset >> 24) - 1;
11074                                 //      return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
11075                                 MONO_ADD_INS (cfg->cbb, thread_ins);
11076                                 static_data_reg = alloc_ireg (cfg);
11077                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
11078
11079                                 if (cfg->compile_aot) {
11080                                         int offset_reg, offset2_reg, idx_reg;
11081
11082                                         /* For TLS variables, this will return the TLS offset */
11083                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
11084                                         offset_reg = ins->dreg;
11085                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
11086                                         idx_reg = alloc_ireg (cfg);
11087                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_IMM, idx_reg, offset_reg, 24);
11088                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, idx_reg, idx_reg, 1);
11089                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
11090                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
11091                                         array_reg = alloc_ireg (cfg);
11092                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
11093                                         offset2_reg = alloc_ireg (cfg);
11094                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset_reg, 0xffffff);
11095                                         dreg = alloc_ireg (cfg);
11096                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
11097                                 } else {
11098                                         offset = (gsize)addr & 0x7fffffff;
11099                                         idx = (offset >> 24) - 1;
11100
11101                                         array_reg = alloc_ireg (cfg);
11102                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
11103                                         dreg = alloc_ireg (cfg);
11104                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, (offset & 0xffffff));
11105                                 }
11106                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
11107                                         (cfg->compile_aot && is_special_static) ||
11108                                         (context_used && is_special_static)) {
11109                                 MonoInst *iargs [2];
11110
11111                                 g_assert (field->parent);
11112                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11113                                 if (context_used) {
11114                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
11115                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
11116                                 } else {
11117                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11118                                 }
11119                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11120                         } else if (context_used) {
11121                                 MonoInst *static_data;
11122
11123                                 /*
11124                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
11125                                         method->klass->name_space, method->klass->name, method->name,
11126                                         depth, field->offset);
11127                                 */
11128
11129                                 if (mono_class_needs_cctor_run (klass, method))
11130                                         emit_generic_class_init (cfg, klass);
11131
11132                                 /*
11133                                  * The pointer we're computing here is
11134                                  *
11135                                  *   super_info.static_data + field->offset
11136                                  */
11137                                 static_data = emit_get_rgctx_klass (cfg, context_used,
11138                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
11139
11140                                 if (mini_is_gsharedvt_klass (cfg, klass)) {
11141                                         MonoInst *offset_ins;
11142
11143                                         offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11144                                         dreg = alloc_ireg_mp (cfg);
11145                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
11146                                 } else if (field->offset == 0) {
11147                                         ins = static_data;
11148                                 } else {
11149                                         int addr_reg = mono_alloc_preg (cfg);
11150                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
11151                                 }
11152                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
11153                                 MonoInst *iargs [2];
11154
11155                                 g_assert (field->parent);
11156                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11157                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11158                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11159                         } else {
11160                                 MonoVTable *vtable = NULL;
11161
11162                                 if (!cfg->compile_aot)
11163                                         vtable = mono_class_vtable (cfg->domain, klass);
11164                                 CHECK_TYPELOAD (klass);
11165
11166                                 if (!addr) {
11167                                         if (mini_field_access_needs_cctor_run (cfg, method, klass, vtable)) {
11168                                                 if (!(g_slist_find (class_inits, klass))) {
11169                                                         mono_emit_abs_call (cfg, MONO_PATCH_INFO_CLASS_INIT, klass, helper_sig_class_init_trampoline, NULL);
11170                                                         if (cfg->verbose_level > 2)
11171                                                                 printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
11172                                                         class_inits = g_slist_prepend (class_inits, klass);
11173                                                 }
11174                                         } else {
11175                                                 if (cfg->run_cctors) {
11176                                                         MonoException *ex;
11177                                                         /* This makes so that inline cannot trigger */
11178                                                         /* .cctors: too many apps depend on them */
11179                                                         /* running with a specific order... */
11180                                                         g_assert (vtable);
11181                                                         if (! vtable->initialized)
11182                                                                 INLINE_FAILURE ("class init");
11183                                                         ex = mono_runtime_class_init_full (vtable, FALSE);
11184                                                         if (ex) {
11185                                                                 set_exception_object (cfg, ex);
11186                                                                 goto exception_exit;
11187                                                         }
11188                                                 }
11189                                         }
11190                                         if (cfg->compile_aot)
11191                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
11192                                         else {
11193                                                 g_assert (vtable);
11194                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11195                                                 g_assert (addr);
11196                                                 EMIT_NEW_PCONST (cfg, ins, addr);
11197                                         }
11198                                 } else {
11199                                         MonoInst *iargs [1];
11200                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
11201                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
11202                                 }
11203                         }
11204
11205                         /* Generate IR to do the actual load/store operation */
11206
11207                         if ((op == CEE_STFLD || op == CEE_STSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11208                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11209                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11210                         }
11211
11212                         if (op == CEE_LDSFLDA) {
11213                                 ins->klass = mono_class_from_mono_type (ftype);
11214                                 ins->type = STACK_PTR;
11215                                 *sp++ = ins;
11216                         } else if (op == CEE_STSFLD) {
11217                                 MonoInst *store;
11218
11219                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
11220                                 store->flags |= ins_flag;
11221                         } else {
11222                                 gboolean is_const = FALSE;
11223                                 MonoVTable *vtable = NULL;
11224                                 gpointer addr = NULL;
11225
11226                                 if (!context_used) {
11227                                         vtable = mono_class_vtable (cfg->domain, klass);
11228                                         CHECK_TYPELOAD (klass);
11229                                 }
11230                                 if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) ||
11231                                                 (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) {
11232                                         int ro_type = ftype->type;
11233                                         if (!addr)
11234                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11235                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
11236                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
11237                                         }
11238
11239                                         GSHAREDVT_FAILURE (op);
11240
11241                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
11242                                         is_const = TRUE;
11243                                         switch (ro_type) {
11244                                         case MONO_TYPE_BOOLEAN:
11245                                         case MONO_TYPE_U1:
11246                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
11247                                                 sp++;
11248                                                 break;
11249                                         case MONO_TYPE_I1:
11250                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
11251                                                 sp++;
11252                                                 break;                                          
11253                                         case MONO_TYPE_CHAR:
11254                                         case MONO_TYPE_U2:
11255                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
11256                                                 sp++;
11257                                                 break;
11258                                         case MONO_TYPE_I2:
11259                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
11260                                                 sp++;
11261                                                 break;
11262                                                 break;
11263                                         case MONO_TYPE_I4:
11264                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
11265                                                 sp++;
11266                                                 break;                                          
11267                                         case MONO_TYPE_U4:
11268                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
11269                                                 sp++;
11270                                                 break;
11271                                         case MONO_TYPE_I:
11272                                         case MONO_TYPE_U:
11273                                         case MONO_TYPE_PTR:
11274                                         case MONO_TYPE_FNPTR:
11275                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11276                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
11277                                                 sp++;
11278                                                 break;
11279                                         case MONO_TYPE_STRING:
11280                                         case MONO_TYPE_OBJECT:
11281                                         case MONO_TYPE_CLASS:
11282                                         case MONO_TYPE_SZARRAY:
11283                                         case MONO_TYPE_ARRAY:
11284                                                 if (!mono_gc_is_moving ()) {
11285                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11286                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
11287                                                         sp++;
11288                                                 } else {
11289                                                         is_const = FALSE;
11290                                                 }
11291                                                 break;
11292                                         case MONO_TYPE_I8:
11293                                         case MONO_TYPE_U8:
11294                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
11295                                                 sp++;
11296                                                 break;
11297                                         case MONO_TYPE_R4:
11298                                         case MONO_TYPE_R8:
11299                                         case MONO_TYPE_VALUETYPE:
11300                                         default:
11301                                                 is_const = FALSE;
11302                                                 break;
11303                                         }
11304                                 }
11305
11306                                 if (!is_const) {
11307                                         MonoInst *load;
11308
11309                                         CHECK_STACK_OVF (1);
11310
11311                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
11312                                         load->flags |= ins_flag;
11313                                         ins_flag = 0;
11314                                         *sp++ = load;
11315                                 }
11316                         }
11317
11318                         if ((op == CEE_LDFLD || op == CEE_LDSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11319                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
11320                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
11321                         }
11322
11323                         ins_flag = 0;
11324                         ip += 5;
11325                         break;
11326                 }
11327                 case CEE_STOBJ:
11328                         CHECK_STACK (2);
11329                         sp -= 2;
11330                         CHECK_OPSIZE (5);
11331                         token = read32 (ip + 1);
11332                         klass = mini_get_class (method, token, generic_context);
11333                         CHECK_TYPELOAD (klass);
11334                         if (ins_flag & MONO_INST_VOLATILE) {
11335                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11336                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11337                         }
11338                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
11339                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
11340                         ins->flags |= ins_flag;
11341                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
11342                                         generic_class_is_reference_type (cfg, klass)) {
11343                                 /* insert call to write barrier */
11344                                 emit_write_barrier (cfg, sp [0], sp [1]);
11345                         }
11346                         ins_flag = 0;
11347                         ip += 5;
11348                         inline_costs += 1;
11349                         break;
11350
11351                         /*
11352                          * Array opcodes
11353                          */
11354                 case CEE_NEWARR: {
11355                         MonoInst *len_ins;
11356                         const char *data_ptr;
11357                         int data_size = 0;
11358                         guint32 field_token;
11359
11360                         CHECK_STACK (1);
11361                         --sp;
11362
11363                         CHECK_OPSIZE (5);
11364                         token = read32 (ip + 1);
11365
11366                         klass = mini_get_class (method, token, generic_context);
11367                         CHECK_TYPELOAD (klass);
11368
11369                         context_used = mini_class_check_context_used (cfg, klass);
11370
11371                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
11372                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_OVF_U4);
11373                                 ins->sreg1 = sp [0]->dreg;
11374                                 ins->type = STACK_I4;
11375                                 ins->dreg = alloc_ireg (cfg);
11376                                 MONO_ADD_INS (cfg->cbb, ins);
11377                                 *sp = mono_decompose_opcode (cfg, ins, &bblock);
11378                         }
11379
11380                         if (context_used) {
11381                                 MonoInst *args [3];
11382                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11383                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
11384
11385                                 /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
11386
11387                                 /* vtable */
11388                                 args [0] = emit_get_rgctx_klass (cfg, context_used,
11389                                         array_class, MONO_RGCTX_INFO_VTABLE);
11390                                 /* array len */
11391                                 args [1] = sp [0];
11392
11393                                 if (managed_alloc)
11394                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
11395                                 else
11396                                         ins = mono_emit_jit_icall (cfg, mono_array_new_specific, args);
11397                         } else {
11398                                 if (cfg->opt & MONO_OPT_SHARED) {
11399                                         /* Decompose now to avoid problems with references to the domainvar */
11400                                         MonoInst *iargs [3];
11401
11402                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11403                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11404                                         iargs [2] = sp [0];
11405
11406                                         ins = mono_emit_jit_icall (cfg, mono_array_new, iargs);
11407                                 } else {
11408                                         /* Decompose later since it is needed by abcrem */
11409                                         MonoClass *array_type = mono_array_class_get (klass, 1);
11410                                         mono_class_vtable (cfg->domain, array_type);
11411                                         CHECK_TYPELOAD (array_type);
11412
11413                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
11414                                         ins->dreg = alloc_ireg_ref (cfg);
11415                                         ins->sreg1 = sp [0]->dreg;
11416                                         ins->inst_newa_class = klass;
11417                                         ins->type = STACK_OBJ;
11418                                         ins->klass = array_type;
11419                                         MONO_ADD_INS (cfg->cbb, ins);
11420                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11421                                         cfg->cbb->has_array_access = TRUE;
11422
11423                                         /* Needed so mono_emit_load_get_addr () gets called */
11424                                         mono_get_got_var (cfg);
11425                                 }
11426                         }
11427
11428                         len_ins = sp [0];
11429                         ip += 5;
11430                         *sp++ = ins;
11431                         inline_costs += 1;
11432
11433                         /* 
11434                          * we inline/optimize the initialization sequence if possible.
11435                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
11436                          * for small sizes open code the memcpy
11437                          * ensure the rva field is big enough
11438                          */
11439                         if ((cfg->opt & MONO_OPT_INTRINS) && ip + 6 < end && ip_in_bb (cfg, bblock, 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))) {
11440                                 MonoMethod *memcpy_method = get_memcpy_method ();
11441                                 MonoInst *iargs [3];
11442                                 int add_reg = alloc_ireg_mp (cfg);
11443
11444                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, MONO_STRUCT_OFFSET (MonoArray, vector));
11445                                 if (cfg->compile_aot) {
11446                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
11447                                 } else {
11448                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
11449                                 }
11450                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
11451                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
11452                                 ip += 11;
11453                         }
11454
11455                         break;
11456                 }
11457                 case CEE_LDLEN:
11458                         CHECK_STACK (1);
11459                         --sp;
11460                         if (sp [0]->type != STACK_OBJ)
11461                                 UNVERIFIED;
11462
11463                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
11464                         ins->dreg = alloc_preg (cfg);
11465                         ins->sreg1 = sp [0]->dreg;
11466                         ins->type = STACK_I4;
11467                         /* This flag will be inherited by the decomposition */
11468                         ins->flags |= MONO_INST_FAULT;
11469                         MONO_ADD_INS (cfg->cbb, ins);
11470                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11471                         cfg->cbb->has_array_access = TRUE;
11472                         ip ++;
11473                         *sp++ = ins;
11474                         break;
11475                 case CEE_LDELEMA:
11476                         CHECK_STACK (2);
11477                         sp -= 2;
11478                         CHECK_OPSIZE (5);
11479                         if (sp [0]->type != STACK_OBJ)
11480                                 UNVERIFIED;
11481
11482                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11483
11484                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11485                         CHECK_TYPELOAD (klass);
11486                         /* we need to make sure that this array is exactly the type it needs
11487                          * to be for correctness. the wrappers are lax with their usage
11488                          * so we need to ignore them here
11489                          */
11490                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
11491                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11492                                 mini_emit_check_array_type (cfg, sp [0], array_class);
11493                                 CHECK_TYPELOAD (array_class);
11494                         }
11495
11496                         readonly = FALSE;
11497                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11498                         *sp++ = ins;
11499                         ip += 5;
11500                         break;
11501                 case CEE_LDELEM:
11502                 case CEE_LDELEM_I1:
11503                 case CEE_LDELEM_U1:
11504                 case CEE_LDELEM_I2:
11505                 case CEE_LDELEM_U2:
11506                 case CEE_LDELEM_I4:
11507                 case CEE_LDELEM_U4:
11508                 case CEE_LDELEM_I8:
11509                 case CEE_LDELEM_I:
11510                 case CEE_LDELEM_R4:
11511                 case CEE_LDELEM_R8:
11512                 case CEE_LDELEM_REF: {
11513                         MonoInst *addr;
11514
11515                         CHECK_STACK (2);
11516                         sp -= 2;
11517
11518                         if (*ip == CEE_LDELEM) {
11519                                 CHECK_OPSIZE (5);
11520                                 token = read32 (ip + 1);
11521                                 klass = mini_get_class (method, token, generic_context);
11522                                 CHECK_TYPELOAD (klass);
11523                                 mono_class_init (klass);
11524                         }
11525                         else
11526                                 klass = array_access_to_klass (*ip);
11527
11528                         if (sp [0]->type != STACK_OBJ)
11529                                 UNVERIFIED;
11530
11531                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11532
11533                         if (mini_is_gsharedvt_variable_klass (cfg, klass)) {
11534                                 // FIXME-VT: OP_ICONST optimization
11535                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11536                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11537                                 ins->opcode = OP_LOADV_MEMBASE;
11538                         } else if (sp [1]->opcode == OP_ICONST) {
11539                                 int array_reg = sp [0]->dreg;
11540                                 int index_reg = sp [1]->dreg;
11541                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
11542
11543                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
11544                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
11545                         } else {
11546                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11547                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11548                         }
11549                         *sp++ = ins;
11550                         if (*ip == CEE_LDELEM)
11551                                 ip += 5;
11552                         else
11553                                 ++ip;
11554                         break;
11555                 }
11556                 case CEE_STELEM_I:
11557                 case CEE_STELEM_I1:
11558                 case CEE_STELEM_I2:
11559                 case CEE_STELEM_I4:
11560                 case CEE_STELEM_I8:
11561                 case CEE_STELEM_R4:
11562                 case CEE_STELEM_R8:
11563                 case CEE_STELEM_REF:
11564                 case CEE_STELEM: {
11565                         CHECK_STACK (3);
11566                         sp -= 3;
11567
11568                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11569
11570                         if (*ip == CEE_STELEM) {
11571                                 CHECK_OPSIZE (5);
11572                                 token = read32 (ip + 1);
11573                                 klass = mini_get_class (method, token, generic_context);
11574                                 CHECK_TYPELOAD (klass);
11575                                 mono_class_init (klass);
11576                         }
11577                         else
11578                                 klass = array_access_to_klass (*ip);
11579
11580                         if (sp [0]->type != STACK_OBJ)
11581                                 UNVERIFIED;
11582
11583                         emit_array_store (cfg, klass, sp, TRUE);
11584
11585                         if (*ip == CEE_STELEM)
11586                                 ip += 5;
11587                         else
11588                                 ++ip;
11589                         inline_costs += 1;
11590                         break;
11591                 }
11592                 case CEE_CKFINITE: {
11593                         CHECK_STACK (1);
11594                         --sp;
11595
11596                         MONO_INST_NEW (cfg, ins, OP_CKFINITE);
11597                         ins->sreg1 = sp [0]->dreg;
11598                         ins->dreg = alloc_freg (cfg);
11599                         ins->type = STACK_R8;
11600                         MONO_ADD_INS (bblock, ins);
11601
11602                         *sp++ = mono_decompose_opcode (cfg, ins, &bblock);
11603
11604                         ++ip;
11605                         break;
11606                 }
11607                 case CEE_REFANYVAL: {
11608                         MonoInst *src_var, *src;
11609
11610                         int klass_reg = alloc_preg (cfg);
11611                         int dreg = alloc_preg (cfg);
11612
11613                         GSHAREDVT_FAILURE (*ip);
11614
11615                         CHECK_STACK (1);
11616                         MONO_INST_NEW (cfg, ins, *ip);
11617                         --sp;
11618                         CHECK_OPSIZE (5);
11619                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11620                         CHECK_TYPELOAD (klass);
11621
11622                         context_used = mini_class_check_context_used (cfg, klass);
11623
11624                         // FIXME:
11625                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
11626                         if (!src_var)
11627                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
11628                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
11629                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass));
11630
11631                         if (context_used) {
11632                                 MonoInst *klass_ins;
11633
11634                                 klass_ins = emit_get_rgctx_klass (cfg, context_used,
11635                                                 klass, MONO_RGCTX_INFO_KLASS);
11636
11637                                 // FIXME:
11638                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
11639                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
11640                         } else {
11641                                 mini_emit_class_check (cfg, klass_reg, klass);
11642                         }
11643                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value));
11644                         ins->type = STACK_MP;
11645                         *sp++ = ins;
11646                         ip += 5;
11647                         break;
11648                 }
11649                 case CEE_MKREFANY: {
11650                         MonoInst *loc, *addr;
11651
11652                         GSHAREDVT_FAILURE (*ip);
11653
11654                         CHECK_STACK (1);
11655                         MONO_INST_NEW (cfg, ins, *ip);
11656                         --sp;
11657                         CHECK_OPSIZE (5);
11658                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11659                         CHECK_TYPELOAD (klass);
11660
11661                         context_used = mini_class_check_context_used (cfg, klass);
11662
11663                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
11664                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
11665
11666                         if (context_used) {
11667                                 MonoInst *const_ins;
11668                                 int type_reg = alloc_preg (cfg);
11669
11670                                 const_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
11671                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
11672                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11673                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11674                         } else if (cfg->compile_aot) {
11675                                 int const_reg = alloc_preg (cfg);
11676                                 int type_reg = alloc_preg (cfg);
11677
11678                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
11679                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
11680                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11681                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11682                         } else {
11683                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), &klass->byval_arg);
11684                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), klass);
11685                         }
11686                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
11687
11688                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
11689                         ins->type = STACK_VTYPE;
11690                         ins->klass = mono_defaults.typed_reference_class;
11691                         *sp++ = ins;
11692                         ip += 5;
11693                         break;
11694                 }
11695                 case CEE_LDTOKEN: {
11696                         gpointer handle;
11697                         MonoClass *handle_class;
11698
11699                         CHECK_STACK_OVF (1);
11700
11701                         CHECK_OPSIZE (5);
11702                         n = read32 (ip + 1);
11703
11704                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
11705                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
11706                                 handle = mono_method_get_wrapper_data (method, n);
11707                                 handle_class = mono_method_get_wrapper_data (method, n + 1);
11708                                 if (handle_class == mono_defaults.typehandle_class)
11709                                         handle = &((MonoClass*)handle)->byval_arg;
11710                         }
11711                         else {
11712                                 handle = mono_ldtoken_checked (image, n, &handle_class, generic_context, &cfg->error);
11713                                 CHECK_CFG_ERROR;
11714                         }
11715                         if (!handle)
11716                                 LOAD_ERROR;
11717                         mono_class_init (handle_class);
11718                         if (cfg->generic_sharing_context) {
11719                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
11720                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
11721                                         /* This case handles ldtoken
11722                                            of an open type, like for
11723                                            typeof(Gen<>). */
11724                                         context_used = 0;
11725                                 } else if (handle_class == mono_defaults.typehandle_class) {
11726                                         context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type (handle));
11727                                 } else if (handle_class == mono_defaults.fieldhandle_class)
11728                                         context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
11729                                 else if (handle_class == mono_defaults.methodhandle_class)
11730                                         context_used = mini_method_check_context_used (cfg, handle);
11731                                 else
11732                                         g_assert_not_reached ();
11733                         }
11734
11735                         if ((cfg->opt & MONO_OPT_SHARED) &&
11736                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
11737                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
11738                                 MonoInst *addr, *vtvar, *iargs [3];
11739                                 int method_context_used;
11740
11741                                 method_context_used = mini_method_check_context_used (cfg, method);
11742
11743                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
11744
11745                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
11746                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
11747                                 if (method_context_used) {
11748                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
11749                                                 method, MONO_RGCTX_INFO_METHOD);
11750                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
11751                                 } else {
11752                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
11753                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
11754                                 }
11755                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11756
11757                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11758
11759                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11760                         } else {
11761                                 if ((ip + 5 < end) && ip_in_bb (cfg, bblock, ip + 5) && 
11762                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
11763                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
11764                                         (cmethod->klass == mono_defaults.systemtype_class) &&
11765                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
11766                                         MonoClass *tclass = mono_class_from_mono_type (handle);
11767
11768                                         mono_class_init (tclass);
11769                                         if (context_used) {
11770                                                 ins = emit_get_rgctx_klass (cfg, context_used,
11771                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
11772                                         } else if (cfg->compile_aot) {
11773                                                 if (method->wrapper_type) {
11774                                                         mono_error_init (&error); //got to do it since there are multiple conditionals below
11775                                                         if (mono_class_get_checked (tclass->image, tclass->type_token, &error) == tclass && !generic_context) {
11776                                                                 /* Special case for static synchronized wrappers */
11777                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
11778                                                         } else {
11779                                                                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
11780                                                                 /* FIXME: n is not a normal token */
11781                                                                 DISABLE_AOT (cfg);
11782                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11783                                                         }
11784                                                 } else {
11785                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
11786                                                 }
11787                                         } else {
11788                                                 EMIT_NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
11789                                         }
11790                                         ins->type = STACK_OBJ;
11791                                         ins->klass = cmethod->klass;
11792                                         ip += 5;
11793                                 } else {
11794                                         MonoInst *addr, *vtvar;
11795
11796                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
11797
11798                                         if (context_used) {
11799                                                 if (handle_class == mono_defaults.typehandle_class) {
11800                                                         ins = emit_get_rgctx_klass (cfg, context_used,
11801                                                                         mono_class_from_mono_type (handle),
11802                                                                         MONO_RGCTX_INFO_TYPE);
11803                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
11804                                                         ins = emit_get_rgctx_method (cfg, context_used,
11805                                                                         handle, MONO_RGCTX_INFO_METHOD);
11806                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
11807                                                         ins = emit_get_rgctx_field (cfg, context_used,
11808                                                                         handle, MONO_RGCTX_INFO_CLASS_FIELD);
11809                                                 } else {
11810                                                         g_assert_not_reached ();
11811                                                 }
11812                                         } else if (cfg->compile_aot) {
11813                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n, generic_context);
11814                                         } else {
11815                                                 EMIT_NEW_PCONST (cfg, ins, handle);
11816                                         }
11817                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11818                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11819                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11820                                 }
11821                         }
11822
11823                         *sp++ = ins;
11824                         ip += 5;
11825                         break;
11826                 }
11827                 case CEE_THROW:
11828                         CHECK_STACK (1);
11829                         MONO_INST_NEW (cfg, ins, OP_THROW);
11830                         --sp;
11831                         ins->sreg1 = sp [0]->dreg;
11832                         ip++;
11833                         bblock->out_of_line = TRUE;
11834                         MONO_ADD_INS (bblock, ins);
11835                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
11836                         MONO_ADD_INS (bblock, ins);
11837                         sp = stack_start;
11838                         
11839                         link_bblock (cfg, bblock, end_bblock);
11840                         start_new_bblock = 1;
11841                         break;
11842                 case CEE_ENDFINALLY:
11843                         /* mono_save_seq_point_info () depends on this */
11844                         if (sp != stack_start)
11845                                 emit_seq_point (cfg, method, ip, FALSE, FALSE);
11846                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
11847                         MONO_ADD_INS (bblock, ins);
11848                         ip++;
11849                         start_new_bblock = 1;
11850
11851                         /*
11852                          * Control will leave the method so empty the stack, otherwise
11853                          * the next basic block will start with a nonempty stack.
11854                          */
11855                         while (sp != stack_start) {
11856                                 sp--;
11857                         }
11858                         break;
11859                 case CEE_LEAVE:
11860                 case CEE_LEAVE_S: {
11861                         GList *handlers;
11862
11863                         if (*ip == CEE_LEAVE) {
11864                                 CHECK_OPSIZE (5);
11865                                 target = ip + 5 + (gint32)read32(ip + 1);
11866                         } else {
11867                                 CHECK_OPSIZE (2);
11868                                 target = ip + 2 + (signed char)(ip [1]);
11869                         }
11870
11871                         /* empty the stack */
11872                         while (sp != stack_start) {
11873                                 sp--;
11874                         }
11875
11876                         /* 
11877                          * If this leave statement is in a catch block, check for a
11878                          * pending exception, and rethrow it if necessary.
11879                          * We avoid doing this in runtime invoke wrappers, since those are called
11880                          * by native code which excepts the wrapper to catch all exceptions.
11881                          */
11882                         for (i = 0; i < header->num_clauses; ++i) {
11883                                 MonoExceptionClause *clause = &header->clauses [i];
11884
11885                                 /* 
11886                                  * Use <= in the final comparison to handle clauses with multiple
11887                                  * leave statements, like in bug #78024.
11888                                  * The ordering of the exception clauses guarantees that we find the
11889                                  * innermost clause.
11890                                  */
11891                                 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) {
11892                                         MonoInst *exc_ins;
11893                                         MonoBasicBlock *dont_throw;
11894
11895                                         /*
11896                                           MonoInst *load;
11897
11898                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
11899                                         */
11900
11901                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
11902
11903                                         NEW_BBLOCK (cfg, dont_throw);
11904
11905                                         /*
11906                                          * Currently, we always rethrow the abort exception, despite the 
11907                                          * fact that this is not correct. See thread6.cs for an example. 
11908                                          * But propagating the abort exception is more important than 
11909                                          * getting the sematics right.
11910                                          */
11911                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
11912                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
11913                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
11914
11915                                         MONO_START_BB (cfg, dont_throw);
11916                                         bblock = cfg->cbb;
11917                                 }
11918                         }
11919
11920                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
11921                                 GList *tmp;
11922                                 MonoExceptionClause *clause;
11923
11924                                 for (tmp = handlers; tmp; tmp = tmp->next) {
11925                                         clause = tmp->data;
11926                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
11927                                         g_assert (tblock);
11928                                         link_bblock (cfg, bblock, tblock);
11929                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
11930                                         ins->inst_target_bb = tblock;
11931                                         ins->inst_eh_block = clause;
11932                                         MONO_ADD_INS (bblock, ins);
11933                                         bblock->has_call_handler = 1;
11934                                         if (COMPILE_LLVM (cfg)) {
11935                                                 MonoBasicBlock *target_bb;
11936
11937                                                 /* 
11938                                                  * Link the finally bblock with the target, since it will
11939                                                  * conceptually branch there.
11940                                                  * FIXME: Have to link the bblock containing the endfinally.
11941                                                  */
11942                                                 GET_BBLOCK (cfg, target_bb, target);
11943                                                 link_bblock (cfg, tblock, target_bb);
11944                                         }
11945                                 }
11946                                 g_list_free (handlers);
11947                         } 
11948
11949                         MONO_INST_NEW (cfg, ins, OP_BR);
11950                         MONO_ADD_INS (bblock, ins);
11951                         GET_BBLOCK (cfg, tblock, target);
11952                         link_bblock (cfg, bblock, tblock);
11953                         ins->inst_target_bb = tblock;
11954                         start_new_bblock = 1;
11955
11956                         if (*ip == CEE_LEAVE)
11957                                 ip += 5;
11958                         else
11959                                 ip += 2;
11960
11961                         break;
11962                 }
11963
11964                         /*
11965                          * Mono specific opcodes
11966                          */
11967                 case MONO_CUSTOM_PREFIX: {
11968
11969                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
11970
11971                         CHECK_OPSIZE (2);
11972                         switch (ip [1]) {
11973                         case CEE_MONO_ICALL: {
11974                                 gpointer func;
11975                                 MonoJitICallInfo *info;
11976
11977                                 token = read32 (ip + 2);
11978                                 func = mono_method_get_wrapper_data (method, token);
11979                                 info = mono_find_jit_icall_by_addr (func);
11980                                 if (!info)
11981                                         g_error ("Could not find icall address in wrapper %s", mono_method_full_name (method, 1));
11982                                 g_assert (info);
11983
11984                                 CHECK_STACK (info->sig->param_count);
11985                                 sp -= info->sig->param_count;
11986
11987                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
11988                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
11989                                         *sp++ = ins;
11990
11991                                 ip += 6;
11992                                 inline_costs += 10 * num_calls++;
11993
11994                                 break;
11995                         }
11996                         case CEE_MONO_LDPTR: {
11997                                 gpointer ptr;
11998
11999                                 CHECK_STACK_OVF (1);
12000                                 CHECK_OPSIZE (6);
12001                                 token = read32 (ip + 2);
12002
12003                                 ptr = mono_method_get_wrapper_data (method, token);
12004                                 /* FIXME: Generalize this */
12005                                 if (cfg->compile_aot && ptr == mono_thread_interruption_request_flag ()) {
12006                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
12007                                         *sp++ = ins;
12008                                         ip += 6;
12009                                         break;
12010                                 }
12011                                 EMIT_NEW_PCONST (cfg, ins, ptr);
12012                                 *sp++ = ins;
12013                                 ip += 6;
12014                                 inline_costs += 10 * num_calls++;
12015                                 /* Can't embed random pointers into AOT code */
12016                                 DISABLE_AOT (cfg);
12017                                 break;
12018                         }
12019                         case CEE_MONO_JIT_ICALL_ADDR: {
12020                                 MonoJitICallInfo *callinfo;
12021                                 gpointer ptr;
12022
12023                                 CHECK_STACK_OVF (1);
12024                                 CHECK_OPSIZE (6);
12025                                 token = read32 (ip + 2);
12026
12027                                 ptr = mono_method_get_wrapper_data (method, token);
12028                                 callinfo = mono_find_jit_icall_by_addr (ptr);
12029                                 g_assert (callinfo);
12030                                 EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
12031                                 *sp++ = ins;
12032                                 ip += 6;
12033                                 inline_costs += 10 * num_calls++;
12034                                 break;
12035                         }
12036                         case CEE_MONO_ICALL_ADDR: {
12037                                 MonoMethod *cmethod;
12038                                 gpointer ptr;
12039
12040                                 CHECK_STACK_OVF (1);
12041                                 CHECK_OPSIZE (6);
12042                                 token = read32 (ip + 2);
12043
12044                                 cmethod = mono_method_get_wrapper_data (method, token);
12045
12046                                 if (cfg->compile_aot) {
12047                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
12048                                 } else {
12049                                         ptr = mono_lookup_internal_call (cmethod);
12050                                         g_assert (ptr);
12051                                         EMIT_NEW_PCONST (cfg, ins, ptr);
12052                                 }
12053                                 *sp++ = ins;
12054                                 ip += 6;
12055                                 break;
12056                         }
12057                         case CEE_MONO_VTADDR: {
12058                                 MonoInst *src_var, *src;
12059
12060                                 CHECK_STACK (1);
12061                                 --sp;
12062
12063                                 // FIXME:
12064                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12065                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
12066                                 *sp++ = src;
12067                                 ip += 2;
12068                                 break;
12069                         }
12070                         case CEE_MONO_NEWOBJ: {
12071                                 MonoInst *iargs [2];
12072
12073                                 CHECK_STACK_OVF (1);
12074                                 CHECK_OPSIZE (6);
12075                                 token = read32 (ip + 2);
12076                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12077                                 mono_class_init (klass);
12078                                 NEW_DOMAINCONST (cfg, iargs [0]);
12079                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
12080                                 NEW_CLASSCONST (cfg, iargs [1], klass);
12081                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
12082                                 *sp++ = mono_emit_jit_icall (cfg, mono_object_new, iargs);
12083                                 ip += 6;
12084                                 inline_costs += 10 * num_calls++;
12085                                 break;
12086                         }
12087                         case CEE_MONO_OBJADDR:
12088                                 CHECK_STACK (1);
12089                                 --sp;
12090                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
12091                                 ins->dreg = alloc_ireg_mp (cfg);
12092                                 ins->sreg1 = sp [0]->dreg;
12093                                 ins->type = STACK_MP;
12094                                 MONO_ADD_INS (cfg->cbb, ins);
12095                                 *sp++ = ins;
12096                                 ip += 2;
12097                                 break;
12098                         case CEE_MONO_LDNATIVEOBJ:
12099                                 /*
12100                                  * Similar to LDOBJ, but instead load the unmanaged 
12101                                  * representation of the vtype to the stack.
12102                                  */
12103                                 CHECK_STACK (1);
12104                                 CHECK_OPSIZE (6);
12105                                 --sp;
12106                                 token = read32 (ip + 2);
12107                                 klass = mono_method_get_wrapper_data (method, token);
12108                                 g_assert (klass->valuetype);
12109                                 mono_class_init (klass);
12110
12111                                 {
12112                                         MonoInst *src, *dest, *temp;
12113
12114                                         src = sp [0];
12115                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
12116                                         temp->backend.is_pinvoke = 1;
12117                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
12118                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
12119
12120                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
12121                                         dest->type = STACK_VTYPE;
12122                                         dest->klass = klass;
12123
12124                                         *sp ++ = dest;
12125                                         ip += 6;
12126                                 }
12127                                 break;
12128                         case CEE_MONO_RETOBJ: {
12129                                 /*
12130                                  * Same as RET, but return the native representation of a vtype
12131                                  * to the caller.
12132                                  */
12133                                 g_assert (cfg->ret);
12134                                 g_assert (mono_method_signature (method)->pinvoke); 
12135                                 CHECK_STACK (1);
12136                                 --sp;
12137                                 
12138                                 CHECK_OPSIZE (6);
12139                                 token = read32 (ip + 2);    
12140                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12141
12142                                 if (!cfg->vret_addr) {
12143                                         g_assert (cfg->ret_var_is_local);
12144
12145                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
12146                                 } else {
12147                                         EMIT_NEW_RETLOADA (cfg, ins);
12148                                 }
12149                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
12150                                 
12151                                 if (sp != stack_start)
12152                                         UNVERIFIED;
12153                                 
12154                                 MONO_INST_NEW (cfg, ins, OP_BR);
12155                                 ins->inst_target_bb = end_bblock;
12156                                 MONO_ADD_INS (bblock, ins);
12157                                 link_bblock (cfg, bblock, end_bblock);
12158                                 start_new_bblock = 1;
12159                                 ip += 6;
12160                                 break;
12161                         }
12162                         case CEE_MONO_CISINST:
12163                         case CEE_MONO_CCASTCLASS: {
12164                                 int token;
12165                                 CHECK_STACK (1);
12166                                 --sp;
12167                                 CHECK_OPSIZE (6);
12168                                 token = read32 (ip + 2);
12169                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12170                                 if (ip [1] == CEE_MONO_CISINST)
12171                                         ins = handle_cisinst (cfg, klass, sp [0]);
12172                                 else
12173                                         ins = handle_ccastclass (cfg, klass, sp [0]);
12174                                 bblock = cfg->cbb;
12175                                 *sp++ = ins;
12176                                 ip += 6;
12177                                 break;
12178                         }
12179                         case CEE_MONO_SAVE_LMF:
12180                         case CEE_MONO_RESTORE_LMF:
12181 #ifdef MONO_ARCH_HAVE_LMF_OPS
12182                                 MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_SAVE_LMF) ? OP_SAVE_LMF : OP_RESTORE_LMF);
12183                                 MONO_ADD_INS (bblock, ins);
12184                                 cfg->need_lmf_area = TRUE;
12185 #endif
12186                                 ip += 2;
12187                                 break;
12188                         case CEE_MONO_CLASSCONST:
12189                                 CHECK_STACK_OVF (1);
12190                                 CHECK_OPSIZE (6);
12191                                 token = read32 (ip + 2);
12192                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
12193                                 *sp++ = ins;
12194                                 ip += 6;
12195                                 inline_costs += 10 * num_calls++;
12196                                 break;
12197                         case CEE_MONO_NOT_TAKEN:
12198                                 bblock->out_of_line = TRUE;
12199                                 ip += 2;
12200                                 break;
12201                         case CEE_MONO_TLS: {
12202                                 int key;
12203
12204                                 CHECK_STACK_OVF (1);
12205                                 CHECK_OPSIZE (6);
12206                                 key = (gint32)read32 (ip + 2);
12207                                 g_assert (key < TLS_KEY_NUM);
12208
12209                                 ins = mono_create_tls_get (cfg, key);
12210                                 if (!ins) {
12211                                         if (cfg->compile_aot) {
12212                                                 DISABLE_AOT (cfg);
12213                                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
12214                                                 ins->dreg = alloc_preg (cfg);
12215                                                 ins->type = STACK_PTR;
12216                                         } else {
12217                                                 g_assert_not_reached ();
12218                                         }
12219                                 }
12220                                 ins->type = STACK_PTR;
12221                                 MONO_ADD_INS (bblock, ins);
12222                                 *sp++ = ins;
12223                                 ip += 6;
12224                                 break;
12225                         }
12226                         case CEE_MONO_DYN_CALL: {
12227                                 MonoCallInst *call;
12228
12229                                 /* It would be easier to call a trampoline, but that would put an
12230                                  * extra frame on the stack, confusing exception handling. So
12231                                  * implement it inline using an opcode for now.
12232                                  */
12233
12234                                 if (!cfg->dyn_call_var) {
12235                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12236                                         /* prevent it from being register allocated */
12237                                         cfg->dyn_call_var->flags |= MONO_INST_VOLATILE;
12238                                 }
12239
12240                                 /* Has to use a call inst since it local regalloc expects it */
12241                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
12242                                 ins = (MonoInst*)call;
12243                                 sp -= 2;
12244                                 ins->sreg1 = sp [0]->dreg;
12245                                 ins->sreg2 = sp [1]->dreg;
12246                                 MONO_ADD_INS (bblock, ins);
12247
12248                                 cfg->param_area = MAX (cfg->param_area, MONO_ARCH_DYN_CALL_PARAM_AREA);
12249
12250                                 ip += 2;
12251                                 inline_costs += 10 * num_calls++;
12252
12253                                 break;
12254                         }
12255                         case CEE_MONO_MEMORY_BARRIER: {
12256                                 CHECK_OPSIZE (6);
12257                                 emit_memory_barrier (cfg, (int)read32 (ip + 2));
12258                                 ip += 6;
12259                                 break;
12260                         }
12261                         case CEE_MONO_JIT_ATTACH: {
12262                                 MonoInst *args [16], *domain_ins;
12263                                 MonoInst *ad_ins, *jit_tls_ins;
12264                                 MonoBasicBlock *next_bb = NULL, *call_bb = NULL;
12265
12266                                 cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12267
12268                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12269                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12270
12271                                 ad_ins = mono_get_domain_intrinsic (cfg);
12272                                 jit_tls_ins = mono_get_jit_tls_intrinsic (cfg);
12273
12274                                 if (MONO_ARCH_HAVE_TLS_GET && ad_ins && jit_tls_ins) {
12275                                         NEW_BBLOCK (cfg, next_bb);
12276                                         NEW_BBLOCK (cfg, call_bb);
12277
12278                                         if (cfg->compile_aot) {
12279                                                 /* AOT code is only used in the root domain */
12280                                                 EMIT_NEW_PCONST (cfg, domain_ins, NULL);
12281                                         } else {
12282                                                 EMIT_NEW_PCONST (cfg, domain_ins, cfg->domain);
12283                                         }
12284                                         MONO_ADD_INS (cfg->cbb, ad_ins);
12285                                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, ad_ins->dreg, domain_ins->dreg);
12286                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, call_bb);
12287
12288                                         MONO_ADD_INS (cfg->cbb, jit_tls_ins);
12289                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, jit_tls_ins->dreg, 0);
12290                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, call_bb);
12291
12292                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, next_bb);
12293                                         MONO_START_BB (cfg, call_bb);
12294                                 }
12295
12296                                 if (cfg->compile_aot) {
12297                                         /* AOT code is only used in the root domain */
12298                                         EMIT_NEW_PCONST (cfg, args [0], NULL);
12299                                 } else {
12300                                         EMIT_NEW_PCONST (cfg, args [0], cfg->domain);
12301                                 }
12302                                 ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
12303                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12304
12305                                 if (next_bb) {
12306                                         MONO_START_BB (cfg, next_bb);
12307                                         bblock = cfg->cbb;
12308                                 }
12309                                 ip += 2;
12310                                 break;
12311                         }
12312                         case CEE_MONO_JIT_DETACH: {
12313                                 MonoInst *args [16];
12314
12315                                 /* Restore the original domain */
12316                                 dreg = alloc_ireg (cfg);
12317                                 EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->orig_domain_var->dreg);
12318                                 mono_emit_jit_icall (cfg, mono_jit_set_domain, args);
12319                                 ip += 2;
12320                                 break;
12321                         }
12322                         default:
12323                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
12324                                 break;
12325                         }
12326                         break;
12327                 }
12328
12329                 case CEE_PREFIX1: {
12330                         CHECK_OPSIZE (2);
12331                         switch (ip [1]) {
12332                         case CEE_ARGLIST: {
12333                                 /* somewhat similar to LDTOKEN */
12334                                 MonoInst *addr, *vtvar;
12335                                 CHECK_STACK_OVF (1);
12336                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
12337
12338                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12339                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
12340
12341                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12342                                 ins->type = STACK_VTYPE;
12343                                 ins->klass = mono_defaults.argumenthandle_class;
12344                                 *sp++ = ins;
12345                                 ip += 2;
12346                                 break;
12347                         }
12348                         case CEE_CEQ:
12349                         case CEE_CGT:
12350                         case CEE_CGT_UN:
12351                         case CEE_CLT:
12352                         case CEE_CLT_UN: {
12353                                 MonoInst *cmp, *arg1, *arg2;
12354
12355                                 CHECK_STACK (2);
12356                                 sp -= 2;
12357                                 arg1 = sp [0];
12358                                 arg2 = sp [1];
12359
12360                                 /*
12361                                  * The following transforms:
12362                                  *    CEE_CEQ    into OP_CEQ
12363                                  *    CEE_CGT    into OP_CGT
12364                                  *    CEE_CGT_UN into OP_CGT_UN
12365                                  *    CEE_CLT    into OP_CLT
12366                                  *    CEE_CLT_UN into OP_CLT_UN
12367                                  */
12368                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
12369
12370                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
12371                                 cmp->sreg1 = arg1->dreg;
12372                                 cmp->sreg2 = arg2->dreg;
12373                                 type_from_op (cfg, cmp, arg1, arg2);
12374                                 CHECK_TYPE (cmp);
12375                                 add_widen_op (cfg, cmp, &arg1, &arg2);
12376                                 if ((arg1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((arg1->type == STACK_PTR) || (arg1->type == STACK_OBJ) || (arg1->type == STACK_MP))))
12377                                         cmp->opcode = OP_LCOMPARE;
12378                                 else if (arg1->type == STACK_R4)
12379                                         cmp->opcode = OP_RCOMPARE;
12380                                 else if (arg1->type == STACK_R8)
12381                                         cmp->opcode = OP_FCOMPARE;
12382                                 else
12383                                         cmp->opcode = OP_ICOMPARE;
12384                                 MONO_ADD_INS (bblock, cmp);
12385                                 ins->type = STACK_I4;
12386                                 ins->dreg = alloc_dreg (cfg, ins->type);
12387                                 type_from_op (cfg, ins, arg1, arg2);
12388
12389                                 if (cmp->opcode == OP_FCOMPARE || cmp->opcode == OP_RCOMPARE) {
12390                                         /*
12391                                          * The backends expect the fceq opcodes to do the
12392                                          * comparison too.
12393                                          */
12394                                         ins->sreg1 = cmp->sreg1;
12395                                         ins->sreg2 = cmp->sreg2;
12396                                         NULLIFY_INS (cmp);
12397                                 }
12398                                 MONO_ADD_INS (bblock, ins);
12399                                 *sp++ = ins;
12400                                 ip += 2;
12401                                 break;
12402                         }
12403                         case CEE_LDFTN: {
12404                                 MonoInst *argconst;
12405                                 MonoMethod *cil_method;
12406
12407                                 CHECK_STACK_OVF (1);
12408                                 CHECK_OPSIZE (6);
12409                                 n = read32 (ip + 2);
12410                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12411                                 if (!cmethod || mono_loader_get_last_error ())
12412                                         LOAD_ERROR;
12413                                 mono_class_init (cmethod->klass);
12414
12415                                 mono_save_token_info (cfg, image, n, cmethod);
12416
12417                                 context_used = mini_method_check_context_used (cfg, cmethod);
12418
12419                                 cil_method = cmethod;
12420                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
12421                                         METHOD_ACCESS_FAILURE (method, cil_method);
12422
12423                                 if (mono_security_cas_enabled ()) {
12424                                         if (check_linkdemand (cfg, method, cmethod))
12425                                                 INLINE_FAILURE ("linkdemand");
12426                                         CHECK_CFG_EXCEPTION;
12427                                 } else if (mono_security_core_clr_enabled ()) {
12428                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
12429                                 }
12430
12431                                 /* 
12432                                  * Optimize the common case of ldftn+delegate creation
12433                                  */
12434                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, bblock, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
12435                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12436                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12437                                                 MonoInst *target_ins, *handle_ins;
12438                                                 MonoMethod *invoke;
12439                                                 int invoke_context_used;
12440
12441                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12442                                                 if (!invoke || !mono_method_signature (invoke))
12443                                                         LOAD_ERROR;
12444
12445                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12446
12447                                                 target_ins = sp [-1];
12448
12449                                                 if (mono_security_core_clr_enabled ())
12450                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method, bblock, ip);
12451
12452                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
12453                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
12454                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
12455                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
12456                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
12457                                                         }
12458                                                 }
12459
12460 #if defined(MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE)
12461                                                 /* FIXME: SGEN support */
12462                                                 if (invoke_context_used == 0) {
12463                                                         ip += 6;
12464                                                         if (cfg->verbose_level > 3)
12465                                                                 g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
12466                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, FALSE))) {
12467                                                                 sp --;
12468                                                                 *sp = handle_ins;
12469                                                                 CHECK_CFG_EXCEPTION;
12470                                                                 ip += 5;
12471                                                                 sp ++;
12472                                                                 break;
12473                                                         }
12474                                                         ip -= 6;
12475                                                 }
12476 #endif
12477                                         }
12478                                 }
12479
12480                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
12481                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
12482                                 *sp++ = ins;
12483                                 
12484                                 ip += 6;
12485                                 inline_costs += 10 * num_calls++;
12486                                 break;
12487                         }
12488                         case CEE_LDVIRTFTN: {
12489                                 MonoInst *args [2];
12490
12491                                 CHECK_STACK (1);
12492                                 CHECK_OPSIZE (6);
12493                                 n = read32 (ip + 2);
12494                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12495                                 if (!cmethod || mono_loader_get_last_error ())
12496                                         LOAD_ERROR;
12497                                 mono_class_init (cmethod->klass);
12498  
12499                                 context_used = mini_method_check_context_used (cfg, cmethod);
12500
12501                                 if (mono_security_cas_enabled ()) {
12502                                         if (check_linkdemand (cfg, method, cmethod))
12503                                                 INLINE_FAILURE ("linkdemand");
12504                                         CHECK_CFG_EXCEPTION;
12505                                 } else if (mono_security_core_clr_enabled ()) {
12506                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
12507                                 }
12508
12509                                 /*
12510                                  * Optimize the common case of ldvirtftn+delegate creation
12511                                  */
12512                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, bblock, ip + 6) && (ip [6] == CEE_NEWOBJ) && (ip > header->code && ip [-1] == CEE_DUP)) {
12513                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12514                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12515                                                 MonoInst *target_ins, *handle_ins;
12516                                                 MonoMethod *invoke;
12517                                                 int invoke_context_used;
12518
12519                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12520                                                 if (!invoke || !mono_method_signature (invoke))
12521                                                         LOAD_ERROR;
12522
12523                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12524
12525                                                 target_ins = sp [-1];
12526
12527                                                 if (mono_security_core_clr_enabled ())
12528                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method, bblock, ip);
12529
12530 #if defined(MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE)
12531                                                 /* FIXME: SGEN support */
12532                                                 if (invoke_context_used == 0) {
12533                                                         ip += 6;
12534                                                         if (cfg->verbose_level > 3)
12535                                                                 g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
12536                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, TRUE))) {
12537                                                                 sp -= 2;
12538                                                                 *sp = handle_ins;
12539                                                                 CHECK_CFG_EXCEPTION;
12540                                                                 ip += 5;
12541                                                                 sp ++;
12542                                                                 break;
12543                                                         }
12544                                                         ip -= 6;
12545                                                 }
12546 #endif
12547                                         }
12548                                 }
12549
12550                                 --sp;
12551                                 args [0] = *sp;
12552
12553                                 args [1] = emit_get_rgctx_method (cfg, context_used,
12554                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
12555
12556                                 if (context_used)
12557                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
12558                                 else
12559                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
12560
12561                                 ip += 6;
12562                                 inline_costs += 10 * num_calls++;
12563                                 break;
12564                         }
12565                         case CEE_LDARG:
12566                                 CHECK_STACK_OVF (1);
12567                                 CHECK_OPSIZE (4);
12568                                 n = read16 (ip + 2);
12569                                 CHECK_ARG (n);
12570                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
12571                                 *sp++ = ins;
12572                                 ip += 4;
12573                                 break;
12574                         case CEE_LDARGA:
12575                                 CHECK_STACK_OVF (1);
12576                                 CHECK_OPSIZE (4);
12577                                 n = read16 (ip + 2);
12578                                 CHECK_ARG (n);
12579                                 NEW_ARGLOADA (cfg, ins, n);
12580                                 MONO_ADD_INS (cfg->cbb, ins);
12581                                 *sp++ = ins;
12582                                 ip += 4;
12583                                 break;
12584                         case CEE_STARG:
12585                                 CHECK_STACK (1);
12586                                 --sp;
12587                                 CHECK_OPSIZE (4);
12588                                 n = read16 (ip + 2);
12589                                 CHECK_ARG (n);
12590                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
12591                                         UNVERIFIED;
12592                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
12593                                 ip += 4;
12594                                 break;
12595                         case CEE_LDLOC:
12596                                 CHECK_STACK_OVF (1);
12597                                 CHECK_OPSIZE (4);
12598                                 n = read16 (ip + 2);
12599                                 CHECK_LOCAL (n);
12600                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
12601                                 *sp++ = ins;
12602                                 ip += 4;
12603                                 break;
12604                         case CEE_LDLOCA: {
12605                                 unsigned char *tmp_ip;
12606                                 CHECK_STACK_OVF (1);
12607                                 CHECK_OPSIZE (4);
12608                                 n = read16 (ip + 2);
12609                                 CHECK_LOCAL (n);
12610
12611                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
12612                                         ip = tmp_ip;
12613                                         inline_costs += 1;
12614                                         break;
12615                                 }                       
12616                                 
12617                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
12618                                 *sp++ = ins;
12619                                 ip += 4;
12620                                 break;
12621                         }
12622                         case CEE_STLOC:
12623                                 CHECK_STACK (1);
12624                                 --sp;
12625                                 CHECK_OPSIZE (4);
12626                                 n = read16 (ip + 2);
12627                                 CHECK_LOCAL (n);
12628                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
12629                                         UNVERIFIED;
12630                                 emit_stloc_ir (cfg, sp, header, n);
12631                                 ip += 4;
12632                                 inline_costs += 1;
12633                                 break;
12634                         case CEE_LOCALLOC:
12635                                 CHECK_STACK (1);
12636                                 --sp;
12637                                 if (sp != stack_start) 
12638                                         UNVERIFIED;
12639                                 if (cfg->method != method) 
12640                                         /* 
12641                                          * Inlining this into a loop in a parent could lead to 
12642                                          * stack overflows which is different behavior than the
12643                                          * non-inlined case, thus disable inlining in this case.
12644                                          */
12645                                         INLINE_FAILURE("localloc");
12646
12647                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
12648                                 ins->dreg = alloc_preg (cfg);
12649                                 ins->sreg1 = sp [0]->dreg;
12650                                 ins->type = STACK_PTR;
12651                                 MONO_ADD_INS (cfg->cbb, ins);
12652
12653                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12654                                 if (init_locals)
12655                                         ins->flags |= MONO_INST_INIT;
12656
12657                                 *sp++ = ins;
12658                                 ip += 2;
12659                                 break;
12660                         case CEE_ENDFILTER: {
12661                                 MonoExceptionClause *clause, *nearest;
12662                                 int cc, nearest_num;
12663
12664                                 CHECK_STACK (1);
12665                                 --sp;
12666                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
12667                                         UNVERIFIED;
12668                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
12669                                 ins->sreg1 = (*sp)->dreg;
12670                                 MONO_ADD_INS (bblock, ins);
12671                                 start_new_bblock = 1;
12672                                 ip += 2;
12673
12674                                 nearest = NULL;
12675                                 nearest_num = 0;
12676                                 for (cc = 0; cc < header->num_clauses; ++cc) {
12677                                         clause = &header->clauses [cc];
12678                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
12679                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
12680                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset))) {
12681                                                 nearest = clause;
12682                                                 nearest_num = cc;
12683                                         }
12684                                 }
12685                                 g_assert (nearest);
12686                                 if ((ip - header->code) != nearest->handler_offset)
12687                                         UNVERIFIED;
12688
12689                                 break;
12690                         }
12691                         case CEE_UNALIGNED_:
12692                                 ins_flag |= MONO_INST_UNALIGNED;
12693                                 /* FIXME: record alignment? we can assume 1 for now */
12694                                 CHECK_OPSIZE (3);
12695                                 ip += 3;
12696                                 break;
12697                         case CEE_VOLATILE_:
12698                                 ins_flag |= MONO_INST_VOLATILE;
12699                                 ip += 2;
12700                                 break;
12701                         case CEE_TAIL_:
12702                                 ins_flag   |= MONO_INST_TAILCALL;
12703                                 cfg->flags |= MONO_CFG_HAS_TAIL;
12704                                 /* Can't inline tail calls at this time */
12705                                 inline_costs += 100000;
12706                                 ip += 2;
12707                                 break;
12708                         case CEE_INITOBJ:
12709                                 CHECK_STACK (1);
12710                                 --sp;
12711                                 CHECK_OPSIZE (6);
12712                                 token = read32 (ip + 2);
12713                                 klass = mini_get_class (method, token, generic_context);
12714                                 CHECK_TYPELOAD (klass);
12715                                 if (generic_class_is_reference_type (cfg, klass))
12716                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
12717                                 else
12718                                         mini_emit_initobj (cfg, *sp, NULL, klass);
12719                                 ip += 6;
12720                                 inline_costs += 1;
12721                                 break;
12722                         case CEE_CONSTRAINED_:
12723                                 CHECK_OPSIZE (6);
12724                                 token = read32 (ip + 2);
12725                                 constrained_call = mini_get_class (method, token, generic_context);
12726                                 CHECK_TYPELOAD (constrained_call);
12727                                 ip += 6;
12728                                 break;
12729                         case CEE_CPBLK:
12730                         case CEE_INITBLK: {
12731                                 MonoInst *iargs [3];
12732                                 CHECK_STACK (3);
12733                                 sp -= 3;
12734
12735                                 /* Skip optimized paths for volatile operations. */
12736                                 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)) {
12737                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
12738                                 } 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)) {
12739                                         /* emit_memset only works when val == 0 */
12740                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
12741                                 } else {
12742                                         MonoInst *call;
12743                                         iargs [0] = sp [0];
12744                                         iargs [1] = sp [1];
12745                                         iargs [2] = sp [2];
12746                                         if (ip [1] == CEE_CPBLK) {
12747                                                 /*
12748                                                  * FIXME: It's unclear whether we should be emitting both the acquire
12749                                                  * and release barriers for cpblk. It is technically both a load and
12750                                                  * store operation, so it seems like that's the sensible thing to do.
12751                                                  *
12752                                                  * FIXME: We emit full barriers on both sides of the operation for
12753                                                  * simplicity. We should have a separate atomic memcpy method instead.
12754                                                  */
12755                                                 MonoMethod *memcpy_method = get_memcpy_method ();
12756
12757                                                 if (ins_flag & MONO_INST_VOLATILE)
12758                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12759
12760                                                 call = mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
12761                                                 call->flags |= ins_flag;
12762
12763                                                 if (ins_flag & MONO_INST_VOLATILE)
12764                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12765                                         } else {
12766                                                 MonoMethod *memset_method = get_memset_method ();
12767                                                 if (ins_flag & MONO_INST_VOLATILE) {
12768                                                         /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
12769                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
12770                                                 }
12771                                                 call = mono_emit_method_call (cfg, memset_method, iargs, NULL);
12772                                                 call->flags |= ins_flag;
12773                                         }
12774                                 }
12775                                 ip += 2;
12776                                 ins_flag = 0;
12777                                 inline_costs += 1;
12778                                 break;
12779                         }
12780                         case CEE_NO_:
12781                                 CHECK_OPSIZE (3);
12782                                 if (ip [2] & 0x1)
12783                                         ins_flag |= MONO_INST_NOTYPECHECK;
12784                                 if (ip [2] & 0x2)
12785                                         ins_flag |= MONO_INST_NORANGECHECK;
12786                                 /* we ignore the no-nullcheck for now since we
12787                                  * really do it explicitly only when doing callvirt->call
12788                                  */
12789                                 ip += 3;
12790                                 break;
12791                         case CEE_RETHROW: {
12792                                 MonoInst *load;
12793                                 int handler_offset = -1;
12794
12795                                 for (i = 0; i < header->num_clauses; ++i) {
12796                                         MonoExceptionClause *clause = &header->clauses [i];
12797                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
12798                                                 handler_offset = clause->handler_offset;
12799                                                 break;
12800                                         }
12801                                 }
12802
12803                                 bblock->flags |= BB_EXCEPTION_UNSAFE;
12804
12805                                 if (handler_offset == -1)
12806                                         UNVERIFIED;
12807
12808                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
12809                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
12810                                 ins->sreg1 = load->dreg;
12811                                 MONO_ADD_INS (bblock, ins);
12812
12813                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
12814                                 MONO_ADD_INS (bblock, ins);
12815
12816                                 sp = stack_start;
12817                                 link_bblock (cfg, bblock, end_bblock);
12818                                 start_new_bblock = 1;
12819                                 ip += 2;
12820                                 break;
12821                         }
12822                         case CEE_SIZEOF: {
12823                                 guint32 val;
12824                                 int ialign;
12825
12826                                 CHECK_STACK_OVF (1);
12827                                 CHECK_OPSIZE (6);
12828                                 token = read32 (ip + 2);
12829                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !image_is_dynamic (method->klass->image) && !generic_context) {
12830                                         MonoType *type = mono_type_create_from_typespec_checked (image, token, &cfg->error);
12831                                         CHECK_CFG_ERROR;
12832
12833                                         val = mono_type_size (type, &ialign);
12834                                 } else {
12835                                         MonoClass *klass = mini_get_class (method, token, generic_context);
12836                                         CHECK_TYPELOAD (klass);
12837
12838                                         val = mono_type_size (&klass->byval_arg, &ialign);
12839
12840                                         if (mini_is_gsharedvt_klass (cfg, klass))
12841                                                 GSHAREDVT_FAILURE (*ip);
12842                                 }
12843                                 EMIT_NEW_ICONST (cfg, ins, val);
12844                                 *sp++= ins;
12845                                 ip += 6;
12846                                 break;
12847                         }
12848                         case CEE_REFANYTYPE: {
12849                                 MonoInst *src_var, *src;
12850
12851                                 GSHAREDVT_FAILURE (*ip);
12852
12853                                 CHECK_STACK (1);
12854                                 --sp;
12855
12856                                 // FIXME:
12857                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12858                                 if (!src_var)
12859                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
12860                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
12861                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type));
12862                                 *sp++ = ins;
12863                                 ip += 2;
12864                                 break;
12865                         }
12866                         case CEE_READONLY_:
12867                                 readonly = TRUE;
12868                                 ip += 2;
12869                                 break;
12870
12871                         case CEE_UNUSED56:
12872                         case CEE_UNUSED57:
12873                         case CEE_UNUSED70:
12874                         case CEE_UNUSED:
12875                         case CEE_UNUSED99:
12876                                 UNVERIFIED;
12877                                 
12878                         default:
12879                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
12880                                 UNVERIFIED;
12881                         }
12882                         break;
12883                 }
12884                 case CEE_UNUSED58:
12885                 case CEE_UNUSED1:
12886                         UNVERIFIED;
12887
12888                 default:
12889                         g_warning ("opcode 0x%02x not handled", *ip);
12890                         UNVERIFIED;
12891                 }
12892         }
12893         if (start_new_bblock != 1)
12894                 UNVERIFIED;
12895
12896         bblock->cil_length = ip - bblock->cil_code;
12897         if (bblock->next_bb) {
12898                 /* This could already be set because of inlining, #693905 */
12899                 MonoBasicBlock *bb = bblock;
12900
12901                 while (bb->next_bb)
12902                         bb = bb->next_bb;
12903                 bb->next_bb = end_bblock;
12904         } else {
12905                 bblock->next_bb = end_bblock;
12906         }
12907
12908         if (cfg->method == method && cfg->domainvar) {
12909                 MonoInst *store;
12910                 MonoInst *get_domain;
12911
12912                 cfg->cbb = init_localsbb;
12913
12914                 if ((get_domain = mono_get_domain_intrinsic (cfg))) {
12915                         MONO_ADD_INS (cfg->cbb, get_domain);
12916                 } else {
12917                         get_domain = mono_emit_jit_icall (cfg, mono_domain_get, NULL);
12918                 }
12919                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
12920                 MONO_ADD_INS (cfg->cbb, store);
12921         }
12922
12923 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
12924         if (cfg->compile_aot)
12925                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
12926                 mono_get_got_var (cfg);
12927 #endif
12928
12929         if (cfg->method == method && cfg->got_var)
12930                 mono_emit_load_got_addr (cfg);
12931
12932         if (init_localsbb) {
12933                 cfg->cbb = init_localsbb;
12934                 cfg->ip = NULL;
12935                 for (i = 0; i < header->num_locals; ++i) {
12936                         emit_init_local (cfg, i, header->locals [i], init_locals);
12937                 }
12938         }
12939
12940         if (cfg->init_ref_vars && cfg->method == method) {
12941                 /* Emit initialization for ref vars */
12942                 // FIXME: Avoid duplication initialization for IL locals.
12943                 for (i = 0; i < cfg->num_varinfo; ++i) {
12944                         MonoInst *ins = cfg->varinfo [i];
12945
12946                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
12947                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
12948                 }
12949         }
12950
12951         if (cfg->lmf_var && cfg->method == method) {
12952                 cfg->cbb = init_localsbb;
12953                 emit_push_lmf (cfg);
12954         }
12955
12956         cfg->cbb = init_localsbb;
12957         emit_instrumentation_call (cfg, mono_profiler_method_enter);
12958
12959         if (seq_points) {
12960                 MonoBasicBlock *bb;
12961
12962                 /*
12963                  * Make seq points at backward branch targets interruptable.
12964                  */
12965                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
12966                         if (bb->code && bb->in_count > 1 && bb->code->opcode == OP_SEQ_POINT)
12967                                 bb->code->flags |= MONO_INST_SINGLE_STEP_LOC;
12968         }
12969
12970         /* Add a sequence point for method entry/exit events */
12971         if (cfg->gen_seq_points_debug_data) {
12972                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
12973                 MONO_ADD_INS (init_localsbb, ins);
12974                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
12975                 MONO_ADD_INS (cfg->bb_exit, ins);
12976         }
12977
12978         /*
12979          * Add seq points for IL offsets which have line number info, but wasn't generated a seq point during JITting because
12980          * the code they refer to was dead (#11880).
12981          */
12982         if (sym_seq_points) {
12983                 for (i = 0; i < header->code_size; ++i) {
12984                         if (mono_bitset_test_fast (seq_point_locs, i) && !mono_bitset_test_fast (seq_point_set_locs, i)) {
12985                                 MonoInst *ins;
12986
12987                                 NEW_SEQ_POINT (cfg, ins, i, FALSE);
12988                                 mono_add_seq_point (cfg, NULL, ins, SEQ_POINT_NATIVE_OFFSET_DEAD_CODE);
12989                         }
12990                 }
12991         }
12992
12993         cfg->ip = NULL;
12994
12995         if (cfg->method == method) {
12996                 MonoBasicBlock *bb;
12997                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
12998                         bb->region = mono_find_block_region (cfg, bb->real_offset);
12999                         if (cfg->spvars)
13000                                 mono_create_spvar_for_region (cfg, bb->region);
13001                         if (cfg->verbose_level > 2)
13002                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
13003                 }
13004         }
13005
13006         if (inline_costs < 0) {
13007                 char *mname;
13008
13009                 /* Method is too large */
13010                 mname = mono_method_full_name (method, TRUE);
13011                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
13012                 cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
13013                 g_free (mname);
13014         }
13015
13016         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
13017                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
13018
13019         goto cleanup;
13020
13021 mono_error_exit:
13022         g_assert (!mono_error_ok (&cfg->error));
13023         goto cleanup;
13024  
13025  exception_exit:
13026         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
13027         goto cleanup;
13028
13029  unverified:
13030         set_exception_type_from_invalid_il (cfg, method, ip);
13031         goto cleanup;
13032
13033  cleanup:
13034         g_slist_free (class_inits);
13035         mono_basic_block_free (original_bb);
13036         cfg->dont_inline = g_list_remove (cfg->dont_inline, method);
13037         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
13038         if (cfg->exception_type)
13039                 return -1;
13040         else
13041                 return inline_costs;
13042 }
13043
13044 static int
13045 store_membase_reg_to_store_membase_imm (int opcode)
13046 {
13047         switch (opcode) {
13048         case OP_STORE_MEMBASE_REG:
13049                 return OP_STORE_MEMBASE_IMM;
13050         case OP_STOREI1_MEMBASE_REG:
13051                 return OP_STOREI1_MEMBASE_IMM;
13052         case OP_STOREI2_MEMBASE_REG:
13053                 return OP_STOREI2_MEMBASE_IMM;
13054         case OP_STOREI4_MEMBASE_REG:
13055                 return OP_STOREI4_MEMBASE_IMM;
13056         case OP_STOREI8_MEMBASE_REG:
13057                 return OP_STOREI8_MEMBASE_IMM;
13058         default:
13059                 g_assert_not_reached ();
13060         }
13061
13062         return -1;
13063 }               
13064
13065 int
13066 mono_op_to_op_imm (int opcode)
13067 {
13068         switch (opcode) {
13069         case OP_IADD:
13070                 return OP_IADD_IMM;
13071         case OP_ISUB:
13072                 return OP_ISUB_IMM;
13073         case OP_IDIV:
13074                 return OP_IDIV_IMM;
13075         case OP_IDIV_UN:
13076                 return OP_IDIV_UN_IMM;
13077         case OP_IREM:
13078                 return OP_IREM_IMM;
13079         case OP_IREM_UN:
13080                 return OP_IREM_UN_IMM;
13081         case OP_IMUL:
13082                 return OP_IMUL_IMM;
13083         case OP_IAND:
13084                 return OP_IAND_IMM;
13085         case OP_IOR:
13086                 return OP_IOR_IMM;
13087         case OP_IXOR:
13088                 return OP_IXOR_IMM;
13089         case OP_ISHL:
13090                 return OP_ISHL_IMM;
13091         case OP_ISHR:
13092                 return OP_ISHR_IMM;
13093         case OP_ISHR_UN:
13094                 return OP_ISHR_UN_IMM;
13095
13096         case OP_LADD:
13097                 return OP_LADD_IMM;
13098         case OP_LSUB:
13099                 return OP_LSUB_IMM;
13100         case OP_LAND:
13101                 return OP_LAND_IMM;
13102         case OP_LOR:
13103                 return OP_LOR_IMM;
13104         case OP_LXOR:
13105                 return OP_LXOR_IMM;
13106         case OP_LSHL:
13107                 return OP_LSHL_IMM;
13108         case OP_LSHR:
13109                 return OP_LSHR_IMM;
13110         case OP_LSHR_UN:
13111                 return OP_LSHR_UN_IMM;
13112 #if SIZEOF_REGISTER == 8
13113         case OP_LREM:
13114                 return OP_LREM_IMM;
13115 #endif
13116
13117         case OP_COMPARE:
13118                 return OP_COMPARE_IMM;
13119         case OP_ICOMPARE:
13120                 return OP_ICOMPARE_IMM;
13121         case OP_LCOMPARE:
13122                 return OP_LCOMPARE_IMM;
13123
13124         case OP_STORE_MEMBASE_REG:
13125                 return OP_STORE_MEMBASE_IMM;
13126         case OP_STOREI1_MEMBASE_REG:
13127                 return OP_STOREI1_MEMBASE_IMM;
13128         case OP_STOREI2_MEMBASE_REG:
13129                 return OP_STOREI2_MEMBASE_IMM;
13130         case OP_STOREI4_MEMBASE_REG:
13131                 return OP_STOREI4_MEMBASE_IMM;
13132
13133 #if defined(TARGET_X86) || defined (TARGET_AMD64)
13134         case OP_X86_PUSH:
13135                 return OP_X86_PUSH_IMM;
13136         case OP_X86_COMPARE_MEMBASE_REG:
13137                 return OP_X86_COMPARE_MEMBASE_IMM;
13138 #endif
13139 #if defined(TARGET_AMD64)
13140         case OP_AMD64_ICOMPARE_MEMBASE_REG:
13141                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13142 #endif
13143         case OP_VOIDCALL_REG:
13144                 return OP_VOIDCALL;
13145         case OP_CALL_REG:
13146                 return OP_CALL;
13147         case OP_LCALL_REG:
13148                 return OP_LCALL;
13149         case OP_FCALL_REG:
13150                 return OP_FCALL;
13151         case OP_LOCALLOC:
13152                 return OP_LOCALLOC_IMM;
13153         }
13154
13155         return -1;
13156 }
13157
13158 static int
13159 ldind_to_load_membase (int opcode)
13160 {
13161         switch (opcode) {
13162         case CEE_LDIND_I1:
13163                 return OP_LOADI1_MEMBASE;
13164         case CEE_LDIND_U1:
13165                 return OP_LOADU1_MEMBASE;
13166         case CEE_LDIND_I2:
13167                 return OP_LOADI2_MEMBASE;
13168         case CEE_LDIND_U2:
13169                 return OP_LOADU2_MEMBASE;
13170         case CEE_LDIND_I4:
13171                 return OP_LOADI4_MEMBASE;
13172         case CEE_LDIND_U4:
13173                 return OP_LOADU4_MEMBASE;
13174         case CEE_LDIND_I:
13175                 return OP_LOAD_MEMBASE;
13176         case CEE_LDIND_REF:
13177                 return OP_LOAD_MEMBASE;
13178         case CEE_LDIND_I8:
13179                 return OP_LOADI8_MEMBASE;
13180         case CEE_LDIND_R4:
13181                 return OP_LOADR4_MEMBASE;
13182         case CEE_LDIND_R8:
13183                 return OP_LOADR8_MEMBASE;
13184         default:
13185                 g_assert_not_reached ();
13186         }
13187
13188         return -1;
13189 }
13190
13191 static int
13192 stind_to_store_membase (int opcode)
13193 {
13194         switch (opcode) {
13195         case CEE_STIND_I1:
13196                 return OP_STOREI1_MEMBASE_REG;
13197         case CEE_STIND_I2:
13198                 return OP_STOREI2_MEMBASE_REG;
13199         case CEE_STIND_I4:
13200                 return OP_STOREI4_MEMBASE_REG;
13201         case CEE_STIND_I:
13202         case CEE_STIND_REF:
13203                 return OP_STORE_MEMBASE_REG;
13204         case CEE_STIND_I8:
13205                 return OP_STOREI8_MEMBASE_REG;
13206         case CEE_STIND_R4:
13207                 return OP_STORER4_MEMBASE_REG;
13208         case CEE_STIND_R8:
13209                 return OP_STORER8_MEMBASE_REG;
13210         default:
13211                 g_assert_not_reached ();
13212         }
13213
13214         return -1;
13215 }
13216
13217 int
13218 mono_load_membase_to_load_mem (int opcode)
13219 {
13220         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
13221 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13222         switch (opcode) {
13223         case OP_LOAD_MEMBASE:
13224                 return OP_LOAD_MEM;
13225         case OP_LOADU1_MEMBASE:
13226                 return OP_LOADU1_MEM;
13227         case OP_LOADU2_MEMBASE:
13228                 return OP_LOADU2_MEM;
13229         case OP_LOADI4_MEMBASE:
13230                 return OP_LOADI4_MEM;
13231         case OP_LOADU4_MEMBASE:
13232                 return OP_LOADU4_MEM;
13233 #if SIZEOF_REGISTER == 8
13234         case OP_LOADI8_MEMBASE:
13235                 return OP_LOADI8_MEM;
13236 #endif
13237         }
13238 #endif
13239
13240         return -1;
13241 }
13242
13243 static inline int
13244 op_to_op_dest_membase (int store_opcode, int opcode)
13245 {
13246 #if defined(TARGET_X86)
13247         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
13248                 return -1;
13249
13250         switch (opcode) {
13251         case OP_IADD:
13252                 return OP_X86_ADD_MEMBASE_REG;
13253         case OP_ISUB:
13254                 return OP_X86_SUB_MEMBASE_REG;
13255         case OP_IAND:
13256                 return OP_X86_AND_MEMBASE_REG;
13257         case OP_IOR:
13258                 return OP_X86_OR_MEMBASE_REG;
13259         case OP_IXOR:
13260                 return OP_X86_XOR_MEMBASE_REG;
13261         case OP_ADD_IMM:
13262         case OP_IADD_IMM:
13263                 return OP_X86_ADD_MEMBASE_IMM;
13264         case OP_SUB_IMM:
13265         case OP_ISUB_IMM:
13266                 return OP_X86_SUB_MEMBASE_IMM;
13267         case OP_AND_IMM:
13268         case OP_IAND_IMM:
13269                 return OP_X86_AND_MEMBASE_IMM;
13270         case OP_OR_IMM:
13271         case OP_IOR_IMM:
13272                 return OP_X86_OR_MEMBASE_IMM;
13273         case OP_XOR_IMM:
13274         case OP_IXOR_IMM:
13275                 return OP_X86_XOR_MEMBASE_IMM;
13276         case OP_MOVE:
13277                 return OP_NOP;
13278         }
13279 #endif
13280
13281 #if defined(TARGET_AMD64)
13282         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
13283                 return -1;
13284
13285         switch (opcode) {
13286         case OP_IADD:
13287                 return OP_X86_ADD_MEMBASE_REG;
13288         case OP_ISUB:
13289                 return OP_X86_SUB_MEMBASE_REG;
13290         case OP_IAND:
13291                 return OP_X86_AND_MEMBASE_REG;
13292         case OP_IOR:
13293                 return OP_X86_OR_MEMBASE_REG;
13294         case OP_IXOR:
13295                 return OP_X86_XOR_MEMBASE_REG;
13296         case OP_IADD_IMM:
13297                 return OP_X86_ADD_MEMBASE_IMM;
13298         case OP_ISUB_IMM:
13299                 return OP_X86_SUB_MEMBASE_IMM;
13300         case OP_IAND_IMM:
13301                 return OP_X86_AND_MEMBASE_IMM;
13302         case OP_IOR_IMM:
13303                 return OP_X86_OR_MEMBASE_IMM;
13304         case OP_IXOR_IMM:
13305                 return OP_X86_XOR_MEMBASE_IMM;
13306         case OP_LADD:
13307                 return OP_AMD64_ADD_MEMBASE_REG;
13308         case OP_LSUB:
13309                 return OP_AMD64_SUB_MEMBASE_REG;
13310         case OP_LAND:
13311                 return OP_AMD64_AND_MEMBASE_REG;
13312         case OP_LOR:
13313                 return OP_AMD64_OR_MEMBASE_REG;
13314         case OP_LXOR:
13315                 return OP_AMD64_XOR_MEMBASE_REG;
13316         case OP_ADD_IMM:
13317         case OP_LADD_IMM:
13318                 return OP_AMD64_ADD_MEMBASE_IMM;
13319         case OP_SUB_IMM:
13320         case OP_LSUB_IMM:
13321                 return OP_AMD64_SUB_MEMBASE_IMM;
13322         case OP_AND_IMM:
13323         case OP_LAND_IMM:
13324                 return OP_AMD64_AND_MEMBASE_IMM;
13325         case OP_OR_IMM:
13326         case OP_LOR_IMM:
13327                 return OP_AMD64_OR_MEMBASE_IMM;
13328         case OP_XOR_IMM:
13329         case OP_LXOR_IMM:
13330                 return OP_AMD64_XOR_MEMBASE_IMM;
13331         case OP_MOVE:
13332                 return OP_NOP;
13333         }
13334 #endif
13335
13336         return -1;
13337 }
13338
13339 static inline int
13340 op_to_op_store_membase (int store_opcode, int opcode)
13341 {
13342 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13343         switch (opcode) {
13344         case OP_ICEQ:
13345                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13346                         return OP_X86_SETEQ_MEMBASE;
13347         case OP_CNE:
13348                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13349                         return OP_X86_SETNE_MEMBASE;
13350         }
13351 #endif
13352
13353         return -1;
13354 }
13355
13356 static inline int
13357 op_to_op_src1_membase (int load_opcode, int opcode)
13358 {
13359 #ifdef TARGET_X86
13360         /* FIXME: This has sign extension issues */
13361         /*
13362         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13363                 return OP_X86_COMPARE_MEMBASE8_IMM;
13364         */
13365
13366         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13367                 return -1;
13368
13369         switch (opcode) {
13370         case OP_X86_PUSH:
13371                 return OP_X86_PUSH_MEMBASE;
13372         case OP_COMPARE_IMM:
13373         case OP_ICOMPARE_IMM:
13374                 return OP_X86_COMPARE_MEMBASE_IMM;
13375         case OP_COMPARE:
13376         case OP_ICOMPARE:
13377                 return OP_X86_COMPARE_MEMBASE_REG;
13378         }
13379 #endif
13380
13381 #ifdef TARGET_AMD64
13382         /* FIXME: This has sign extension issues */
13383         /*
13384         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13385                 return OP_X86_COMPARE_MEMBASE8_IMM;
13386         */
13387
13388         switch (opcode) {
13389         case OP_X86_PUSH:
13390 #ifdef __mono_ilp32__
13391                 if (load_opcode == OP_LOADI8_MEMBASE)
13392 #else
13393                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13394 #endif
13395                         return OP_X86_PUSH_MEMBASE;
13396                 break;
13397                 /* FIXME: This only works for 32 bit immediates
13398         case OP_COMPARE_IMM:
13399         case OP_LCOMPARE_IMM:
13400                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13401                         return OP_AMD64_COMPARE_MEMBASE_IMM;
13402                 */
13403         case OP_ICOMPARE_IMM:
13404                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13405                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13406                 break;
13407         case OP_COMPARE:
13408         case OP_LCOMPARE:
13409 #ifdef __mono_ilp32__
13410                 if (load_opcode == OP_LOAD_MEMBASE)
13411                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13412                 if (load_opcode == OP_LOADI8_MEMBASE)
13413 #else
13414                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13415 #endif
13416                         return OP_AMD64_COMPARE_MEMBASE_REG;
13417                 break;
13418         case OP_ICOMPARE:
13419                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13420                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13421                 break;
13422         }
13423 #endif
13424
13425         return -1;
13426 }
13427
13428 static inline int
13429 op_to_op_src2_membase (int load_opcode, int opcode)
13430 {
13431 #ifdef TARGET_X86
13432         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13433                 return -1;
13434         
13435         switch (opcode) {
13436         case OP_COMPARE:
13437         case OP_ICOMPARE:
13438                 return OP_X86_COMPARE_REG_MEMBASE;
13439         case OP_IADD:
13440                 return OP_X86_ADD_REG_MEMBASE;
13441         case OP_ISUB:
13442                 return OP_X86_SUB_REG_MEMBASE;
13443         case OP_IAND:
13444                 return OP_X86_AND_REG_MEMBASE;
13445         case OP_IOR:
13446                 return OP_X86_OR_REG_MEMBASE;
13447         case OP_IXOR:
13448                 return OP_X86_XOR_REG_MEMBASE;
13449         }
13450 #endif
13451
13452 #ifdef TARGET_AMD64
13453 #ifdef __mono_ilp32__
13454         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE) ) {
13455 #else
13456         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)) {
13457 #endif
13458                 switch (opcode) {
13459                 case OP_ICOMPARE:
13460                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
13461                 case OP_IADD:
13462                         return OP_X86_ADD_REG_MEMBASE;
13463                 case OP_ISUB:
13464                         return OP_X86_SUB_REG_MEMBASE;
13465                 case OP_IAND:
13466                         return OP_X86_AND_REG_MEMBASE;
13467                 case OP_IOR:
13468                         return OP_X86_OR_REG_MEMBASE;
13469                 case OP_IXOR:
13470                         return OP_X86_XOR_REG_MEMBASE;
13471                 }
13472 #ifdef __mono_ilp32__
13473         } else if (load_opcode == OP_LOADI8_MEMBASE) {
13474 #else
13475         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE)) {
13476 #endif
13477                 switch (opcode) {
13478                 case OP_COMPARE:
13479                 case OP_LCOMPARE:
13480                         return OP_AMD64_COMPARE_REG_MEMBASE;
13481                 case OP_LADD:
13482                         return OP_AMD64_ADD_REG_MEMBASE;
13483                 case OP_LSUB:
13484                         return OP_AMD64_SUB_REG_MEMBASE;
13485                 case OP_LAND:
13486                         return OP_AMD64_AND_REG_MEMBASE;
13487                 case OP_LOR:
13488                         return OP_AMD64_OR_REG_MEMBASE;
13489                 case OP_LXOR:
13490                         return OP_AMD64_XOR_REG_MEMBASE;
13491                 }
13492         }
13493 #endif
13494
13495         return -1;
13496 }
13497
13498 int
13499 mono_op_to_op_imm_noemul (int opcode)
13500 {
13501         switch (opcode) {
13502 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
13503         case OP_LSHR:
13504         case OP_LSHL:
13505         case OP_LSHR_UN:
13506                 return -1;
13507 #endif
13508 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
13509         case OP_IDIV:
13510         case OP_IDIV_UN:
13511         case OP_IREM:
13512         case OP_IREM_UN:
13513                 return -1;
13514 #endif
13515 #if defined(MONO_ARCH_EMULATE_MUL_DIV)
13516         case OP_IMUL:
13517                 return -1;
13518 #endif
13519         default:
13520                 return mono_op_to_op_imm (opcode);
13521         }
13522 }
13523
13524 /**
13525  * mono_handle_global_vregs:
13526  *
13527  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
13528  * for them.
13529  */
13530 void
13531 mono_handle_global_vregs (MonoCompile *cfg)
13532 {
13533         gint32 *vreg_to_bb;
13534         MonoBasicBlock *bb;
13535         int i, pos;
13536
13537         vreg_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
13538
13539 #ifdef MONO_ARCH_SIMD_INTRINSICS
13540         if (cfg->uses_simd_intrinsics)
13541                 mono_simd_simplify_indirection (cfg);
13542 #endif
13543
13544         /* Find local vregs used in more than one bb */
13545         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13546                 MonoInst *ins = bb->code;       
13547                 int block_num = bb->block_num;
13548
13549                 if (cfg->verbose_level > 2)
13550                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
13551
13552                 cfg->cbb = bb;
13553                 for (; ins; ins = ins->next) {
13554                         const char *spec = INS_INFO (ins->opcode);
13555                         int regtype = 0, regindex;
13556                         gint32 prev_bb;
13557
13558                         if (G_UNLIKELY (cfg->verbose_level > 2))
13559                                 mono_print_ins (ins);
13560
13561                         g_assert (ins->opcode >= MONO_CEE_LAST);
13562
13563                         for (regindex = 0; regindex < 4; regindex ++) {
13564                                 int vreg = 0;
13565
13566                                 if (regindex == 0) {
13567                                         regtype = spec [MONO_INST_DEST];
13568                                         if (regtype == ' ')
13569                                                 continue;
13570                                         vreg = ins->dreg;
13571                                 } else if (regindex == 1) {
13572                                         regtype = spec [MONO_INST_SRC1];
13573                                         if (regtype == ' ')
13574                                                 continue;
13575                                         vreg = ins->sreg1;
13576                                 } else if (regindex == 2) {
13577                                         regtype = spec [MONO_INST_SRC2];
13578                                         if (regtype == ' ')
13579                                                 continue;
13580                                         vreg = ins->sreg2;
13581                                 } else if (regindex == 3) {
13582                                         regtype = spec [MONO_INST_SRC3];
13583                                         if (regtype == ' ')
13584                                                 continue;
13585                                         vreg = ins->sreg3;
13586                                 }
13587
13588 #if SIZEOF_REGISTER == 4
13589                                 /* In the LLVM case, the long opcodes are not decomposed */
13590                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
13591                                         /*
13592                                          * Since some instructions reference the original long vreg,
13593                                          * and some reference the two component vregs, it is quite hard
13594                                          * to determine when it needs to be global. So be conservative.
13595                                          */
13596                                         if (!get_vreg_to_inst (cfg, vreg)) {
13597                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13598
13599                                                 if (cfg->verbose_level > 2)
13600                                                         printf ("LONG VREG R%d made global.\n", vreg);
13601                                         }
13602
13603                                         /*
13604                                          * Make the component vregs volatile since the optimizations can
13605                                          * get confused otherwise.
13606                                          */
13607                                         get_vreg_to_inst (cfg, vreg + 1)->flags |= MONO_INST_VOLATILE;
13608                                         get_vreg_to_inst (cfg, vreg + 2)->flags |= MONO_INST_VOLATILE;
13609                                 }
13610 #endif
13611
13612                                 g_assert (vreg != -1);
13613
13614                                 prev_bb = vreg_to_bb [vreg];
13615                                 if (prev_bb == 0) {
13616                                         /* 0 is a valid block num */
13617                                         vreg_to_bb [vreg] = block_num + 1;
13618                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
13619                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
13620                                                 continue;
13621
13622                                         if (!get_vreg_to_inst (cfg, vreg)) {
13623                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13624                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
13625
13626                                                 switch (regtype) {
13627                                                 case 'i':
13628                                                         if (vreg_is_ref (cfg, vreg))
13629                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg);
13630                                                         else
13631                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
13632                                                         break;
13633                                                 case 'l':
13634                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13635                                                         break;
13636                                                 case 'f':
13637                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
13638                                                         break;
13639                                                 case 'v':
13640                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
13641                                                         break;
13642                                                 default:
13643                                                         g_assert_not_reached ();
13644                                                 }
13645                                         }
13646
13647                                         /* Flag as having been used in more than one bb */
13648                                         vreg_to_bb [vreg] = -1;
13649                                 }
13650                         }
13651                 }
13652         }
13653
13654         /* If a variable is used in only one bblock, convert it into a local vreg */
13655         for (i = 0; i < cfg->num_varinfo; i++) {
13656                 MonoInst *var = cfg->varinfo [i];
13657                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
13658
13659                 switch (var->type) {
13660                 case STACK_I4:
13661                 case STACK_OBJ:
13662                 case STACK_PTR:
13663                 case STACK_MP:
13664                 case STACK_VTYPE:
13665 #if SIZEOF_REGISTER == 8
13666                 case STACK_I8:
13667 #endif
13668 #if !defined(TARGET_X86)
13669                 /* Enabling this screws up the fp stack on x86 */
13670                 case STACK_R8:
13671 #endif
13672                         if (mono_arch_is_soft_float ())
13673                                 break;
13674
13675                         /* Arguments are implicitly global */
13676                         /* Putting R4 vars into registers doesn't work currently */
13677                         /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
13678                         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) {
13679                                 /* 
13680                                  * Make that the variable's liveness interval doesn't contain a call, since
13681                                  * that would cause the lvreg to be spilled, making the whole optimization
13682                                  * useless.
13683                                  */
13684                                 /* This is too slow for JIT compilation */
13685 #if 0
13686                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
13687                                         MonoInst *ins;
13688                                         int def_index, call_index, ins_index;
13689                                         gboolean spilled = FALSE;
13690
13691                                         def_index = -1;
13692                                         call_index = -1;
13693                                         ins_index = 0;
13694                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
13695                                                 const char *spec = INS_INFO (ins->opcode);
13696
13697                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
13698                                                         def_index = ins_index;
13699
13700                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
13701                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
13702                                                         if (call_index > def_index) {
13703                                                                 spilled = TRUE;
13704                                                                 break;
13705                                                         }
13706                                                 }
13707
13708                                                 if (MONO_IS_CALL (ins))
13709                                                         call_index = ins_index;
13710
13711                                                 ins_index ++;
13712                                         }
13713
13714                                         if (spilled)
13715                                                 break;
13716                                 }
13717 #endif
13718
13719                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13720                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
13721                                 var->flags |= MONO_INST_IS_DEAD;
13722                                 cfg->vreg_to_inst [var->dreg] = NULL;
13723                         }
13724                         break;
13725                 }
13726         }
13727
13728         /* 
13729          * Compress the varinfo and vars tables so the liveness computation is faster and
13730          * takes up less space.
13731          */
13732         pos = 0;
13733         for (i = 0; i < cfg->num_varinfo; ++i) {
13734                 MonoInst *var = cfg->varinfo [i];
13735                 if (pos < i && cfg->locals_start == i)
13736                         cfg->locals_start = pos;
13737                 if (!(var->flags & MONO_INST_IS_DEAD)) {
13738                         if (pos < i) {
13739                                 cfg->varinfo [pos] = cfg->varinfo [i];
13740                                 cfg->varinfo [pos]->inst_c0 = pos;
13741                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
13742                                 cfg->vars [pos].idx = pos;
13743 #if SIZEOF_REGISTER == 4
13744                                 if (cfg->varinfo [pos]->type == STACK_I8) {
13745                                         /* Modify the two component vars too */
13746                                         MonoInst *var1;
13747
13748                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 1);
13749                                         var1->inst_c0 = pos;
13750                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 2);
13751                                         var1->inst_c0 = pos;
13752                                 }
13753 #endif
13754                         }
13755                         pos ++;
13756                 }
13757         }
13758         cfg->num_varinfo = pos;
13759         if (cfg->locals_start > cfg->num_varinfo)
13760                 cfg->locals_start = cfg->num_varinfo;
13761 }
13762
13763 /**
13764  * mono_spill_global_vars:
13765  *
13766  *   Generate spill code for variables which are not allocated to registers, 
13767  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
13768  * code is generated which could be optimized by the local optimization passes.
13769  */
13770 void
13771 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
13772 {
13773         MonoBasicBlock *bb;
13774         char spec2 [16];
13775         int orig_next_vreg;
13776         guint32 *vreg_to_lvreg;
13777         guint32 *lvregs;
13778         guint32 i, lvregs_len;
13779         gboolean dest_has_lvreg = FALSE;
13780         guint32 stacktypes [128];
13781         MonoInst **live_range_start, **live_range_end;
13782         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
13783         int *gsharedvt_vreg_to_idx = NULL;
13784
13785         *need_local_opts = FALSE;
13786
13787         memset (spec2, 0, sizeof (spec2));
13788
13789         /* FIXME: Move this function to mini.c */
13790         stacktypes ['i'] = STACK_PTR;
13791         stacktypes ['l'] = STACK_I8;
13792         stacktypes ['f'] = STACK_R8;
13793 #ifdef MONO_ARCH_SIMD_INTRINSICS
13794         stacktypes ['x'] = STACK_VTYPE;
13795 #endif
13796
13797 #if SIZEOF_REGISTER == 4
13798         /* Create MonoInsts for longs */
13799         for (i = 0; i < cfg->num_varinfo; i++) {
13800                 MonoInst *ins = cfg->varinfo [i];
13801
13802                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
13803                         switch (ins->type) {
13804                         case STACK_R8:
13805                         case STACK_I8: {
13806                                 MonoInst *tree;
13807
13808                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
13809                                         break;
13810
13811                                 g_assert (ins->opcode == OP_REGOFFSET);
13812
13813                                 tree = get_vreg_to_inst (cfg, ins->dreg + 1);
13814                                 g_assert (tree);
13815                                 tree->opcode = OP_REGOFFSET;
13816                                 tree->inst_basereg = ins->inst_basereg;
13817                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
13818
13819                                 tree = get_vreg_to_inst (cfg, ins->dreg + 2);
13820                                 g_assert (tree);
13821                                 tree->opcode = OP_REGOFFSET;
13822                                 tree->inst_basereg = ins->inst_basereg;
13823                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
13824                                 break;
13825                         }
13826                         default:
13827                                 break;
13828                         }
13829                 }
13830         }
13831 #endif
13832
13833         if (cfg->compute_gc_maps) {
13834                 /* registers need liveness info even for !non refs */
13835                 for (i = 0; i < cfg->num_varinfo; i++) {
13836                         MonoInst *ins = cfg->varinfo [i];
13837
13838                         if (ins->opcode == OP_REGVAR)
13839                                 ins->flags |= MONO_INST_GC_TRACK;
13840                 }
13841         }
13842
13843         if (cfg->gsharedvt) {
13844                 gsharedvt_vreg_to_idx = mono_mempool_alloc0 (cfg->mempool, sizeof (int) * cfg->next_vreg);
13845
13846                 for (i = 0; i < cfg->num_varinfo; ++i) {
13847                         MonoInst *ins = cfg->varinfo [i];
13848                         int idx;
13849
13850                         if (mini_is_gsharedvt_variable_type (cfg, ins->inst_vtype)) {
13851                                 if (i >= cfg->locals_start) {
13852                                         /* Local */
13853                                         idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
13854                                         gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
13855                                         ins->opcode = OP_GSHAREDVT_LOCAL;
13856                                         ins->inst_imm = idx;
13857                                 } else {
13858                                         /* Arg */
13859                                         gsharedvt_vreg_to_idx [ins->dreg] = -1;
13860                                         ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
13861                                 }
13862                         }
13863                 }
13864         }
13865                 
13866         /* FIXME: widening and truncation */
13867
13868         /*
13869          * As an optimization, when a variable allocated to the stack is first loaded into 
13870          * an lvreg, we will remember the lvreg and use it the next time instead of loading
13871          * the variable again.
13872          */
13873         orig_next_vreg = cfg->next_vreg;
13874         vreg_to_lvreg = mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
13875         lvregs = mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
13876         lvregs_len = 0;
13877
13878         /* 
13879          * These arrays contain the first and last instructions accessing a given
13880          * variable.
13881          * Since we emit bblocks in the same order we process them here, and we
13882          * don't split live ranges, these will precisely describe the live range of
13883          * the variable, i.e. the instruction range where a valid value can be found
13884          * in the variables location.
13885          * The live range is computed using the liveness info computed by the liveness pass.
13886          * We can't use vmv->range, since that is an abstract live range, and we need
13887          * one which is instruction precise.
13888          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
13889          */
13890         /* FIXME: Only do this if debugging info is requested */
13891         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
13892         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
13893         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
13894         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
13895         
13896         /* Add spill loads/stores */
13897         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13898                 MonoInst *ins;
13899
13900                 if (cfg->verbose_level > 2)
13901                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
13902
13903                 /* Clear vreg_to_lvreg array */
13904                 for (i = 0; i < lvregs_len; i++)
13905                         vreg_to_lvreg [lvregs [i]] = 0;
13906                 lvregs_len = 0;
13907
13908                 cfg->cbb = bb;
13909                 MONO_BB_FOR_EACH_INS (bb, ins) {
13910                         const char *spec = INS_INFO (ins->opcode);
13911                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
13912                         gboolean store, no_lvreg;
13913                         int sregs [MONO_MAX_SRC_REGS];
13914
13915                         if (G_UNLIKELY (cfg->verbose_level > 2))
13916                                 mono_print_ins (ins);
13917
13918                         if (ins->opcode == OP_NOP)
13919                                 continue;
13920
13921                         /* 
13922                          * We handle LDADDR here as well, since it can only be decomposed
13923                          * when variable addresses are known.
13924                          */
13925                         if (ins->opcode == OP_LDADDR) {
13926                                 MonoInst *var = ins->inst_p0;
13927
13928                                 if (var->opcode == OP_VTARG_ADDR) {
13929                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
13930                                         MonoInst *vtaddr = var->inst_left;
13931                                         if (vtaddr->opcode == OP_REGVAR) {
13932                                                 ins->opcode = OP_MOVE;
13933                                                 ins->sreg1 = vtaddr->dreg;
13934                                         }
13935                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
13936                                                 ins->opcode = OP_LOAD_MEMBASE;
13937                                                 ins->inst_basereg = vtaddr->inst_basereg;
13938                                                 ins->inst_offset = vtaddr->inst_offset;
13939                                         } else
13940                                                 NOT_IMPLEMENTED;
13941                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg] < 0) {
13942                                         /* gsharedvt arg passed by ref */
13943                                         g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
13944
13945                                         ins->opcode = OP_LOAD_MEMBASE;
13946                                         ins->inst_basereg = var->inst_basereg;
13947                                         ins->inst_offset = var->inst_offset;
13948                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg]) {
13949                                         MonoInst *load, *load2, *load3;
13950                                         int idx = gsharedvt_vreg_to_idx [var->dreg] - 1;
13951                                         int reg1, reg2, reg3;
13952                                         MonoInst *info_var = cfg->gsharedvt_info_var;
13953                                         MonoInst *locals_var = cfg->gsharedvt_locals_var;
13954
13955                                         /*
13956                                          * gsharedvt local.
13957                                          * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
13958                                          */
13959
13960                                         g_assert (var->opcode == OP_GSHAREDVT_LOCAL);
13961
13962                                         g_assert (info_var);
13963                                         g_assert (locals_var);
13964
13965                                         /* Mark the instruction used to compute the locals var as used */
13966                                         cfg->gsharedvt_locals_var_ins = NULL;
13967
13968                                         /* Load the offset */
13969                                         if (info_var->opcode == OP_REGOFFSET) {
13970                                                 reg1 = alloc_ireg (cfg);
13971                                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, reg1, info_var->inst_basereg, info_var->inst_offset);
13972                                         } else if (info_var->opcode == OP_REGVAR) {
13973                                                 load = NULL;
13974                                                 reg1 = info_var->dreg;
13975                                         } else {
13976                                                 g_assert_not_reached ();
13977                                         }
13978                                         reg2 = alloc_ireg (cfg);
13979                                         NEW_LOAD_MEMBASE (cfg, load2, OP_LOADI4_MEMBASE, reg2, reg1, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
13980                                         /* Load the locals area address */
13981                                         reg3 = alloc_ireg (cfg);
13982                                         if (locals_var->opcode == OP_REGOFFSET) {
13983                                                 NEW_LOAD_MEMBASE (cfg, load3, OP_LOAD_MEMBASE, reg3, locals_var->inst_basereg, locals_var->inst_offset);
13984                                         } else if (locals_var->opcode == OP_REGVAR) {
13985                                                 NEW_UNALU (cfg, load3, OP_MOVE, reg3, locals_var->dreg);
13986                                         } else {
13987                                                 g_assert_not_reached ();
13988                                         }
13989                                         /* Compute the address */
13990                                         ins->opcode = OP_PADD;
13991                                         ins->sreg1 = reg3;
13992                                         ins->sreg2 = reg2;
13993
13994                                         mono_bblock_insert_before_ins (bb, ins, load3);
13995                                         mono_bblock_insert_before_ins (bb, load3, load2);
13996                                         if (load)
13997                                                 mono_bblock_insert_before_ins (bb, load2, load);
13998                                 } else {
13999                                         g_assert (var->opcode == OP_REGOFFSET);
14000
14001                                         ins->opcode = OP_ADD_IMM;
14002                                         ins->sreg1 = var->inst_basereg;
14003                                         ins->inst_imm = var->inst_offset;
14004                                 }
14005
14006                                 *need_local_opts = TRUE;
14007                                 spec = INS_INFO (ins->opcode);
14008                         }
14009
14010                         if (ins->opcode < MONO_CEE_LAST) {
14011                                 mono_print_ins (ins);
14012                                 g_assert_not_reached ();
14013                         }
14014
14015                         /*
14016                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
14017                          * src register.
14018                          * FIXME:
14019                          */
14020                         if (MONO_IS_STORE_MEMBASE (ins)) {
14021                                 tmp_reg = ins->dreg;
14022                                 ins->dreg = ins->sreg2;
14023                                 ins->sreg2 = tmp_reg;
14024                                 store = TRUE;
14025
14026                                 spec2 [MONO_INST_DEST] = ' ';
14027                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14028                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14029                                 spec2 [MONO_INST_SRC3] = ' ';
14030                                 spec = spec2;
14031                         } else if (MONO_IS_STORE_MEMINDEX (ins))
14032                                 g_assert_not_reached ();
14033                         else
14034                                 store = FALSE;
14035                         no_lvreg = FALSE;
14036
14037                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
14038                                 printf ("\t %.3s %d", spec, ins->dreg);
14039                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
14040                                 for (srcindex = 0; srcindex < num_sregs; ++srcindex)
14041                                         printf (" %d", sregs [srcindex]);
14042                                 printf ("\n");
14043                         }
14044
14045                         /***************/
14046                         /*    DREG     */
14047                         /***************/
14048                         regtype = spec [MONO_INST_DEST];
14049                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
14050                         prev_dreg = -1;
14051
14052                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
14053                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
14054                                 MonoInst *store_ins;
14055                                 int store_opcode;
14056                                 MonoInst *def_ins = ins;
14057                                 int dreg = ins->dreg; /* The original vreg */
14058
14059                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
14060
14061                                 if (var->opcode == OP_REGVAR) {
14062                                         ins->dreg = var->dreg;
14063                                 } 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)) {
14064                                         /* 
14065                                          * Instead of emitting a load+store, use a _membase opcode.
14066                                          */
14067                                         g_assert (var->opcode == OP_REGOFFSET);
14068                                         if (ins->opcode == OP_MOVE) {
14069                                                 NULLIFY_INS (ins);
14070                                                 def_ins = NULL;
14071                                         } else {
14072                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
14073                                                 ins->inst_basereg = var->inst_basereg;
14074                                                 ins->inst_offset = var->inst_offset;
14075                                                 ins->dreg = -1;
14076                                         }
14077                                         spec = INS_INFO (ins->opcode);
14078                                 } else {
14079                                         guint32 lvreg;
14080
14081                                         g_assert (var->opcode == OP_REGOFFSET);
14082
14083                                         prev_dreg = ins->dreg;
14084
14085                                         /* Invalidate any previous lvreg for this vreg */
14086                                         vreg_to_lvreg [ins->dreg] = 0;
14087
14088                                         lvreg = 0;
14089
14090                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
14091                                                 regtype = 'l';
14092                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
14093                                         }
14094
14095                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
14096
14097 #if SIZEOF_REGISTER != 8
14098                                         if (regtype == 'l') {
14099                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET, ins->dreg + 1);
14100                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14101                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET, ins->dreg + 2);
14102                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14103                                                 def_ins = store_ins;
14104                                         }
14105                                         else
14106 #endif
14107                                         {
14108                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
14109
14110                                                 /* Try to fuse the store into the instruction itself */
14111                                                 /* FIXME: Add more instructions */
14112                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
14113                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
14114                                                         ins->inst_imm = ins->inst_c0;
14115                                                         ins->inst_destbasereg = var->inst_basereg;
14116                                                         ins->inst_offset = var->inst_offset;
14117                                                         spec = INS_INFO (ins->opcode);
14118                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE) || (ins->opcode == OP_RMOVE))) {
14119                                                         ins->opcode = store_opcode;
14120                                                         ins->inst_destbasereg = var->inst_basereg;
14121                                                         ins->inst_offset = var->inst_offset;
14122
14123                                                         no_lvreg = TRUE;
14124
14125                                                         tmp_reg = ins->dreg;
14126                                                         ins->dreg = ins->sreg2;
14127                                                         ins->sreg2 = tmp_reg;
14128                                                         store = TRUE;
14129
14130                                                         spec2 [MONO_INST_DEST] = ' ';
14131                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14132                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14133                                                         spec2 [MONO_INST_SRC3] = ' ';
14134                                                         spec = spec2;
14135                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
14136                                                         // FIXME: The backends expect the base reg to be in inst_basereg
14137                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
14138                                                         ins->dreg = -1;
14139                                                         ins->inst_basereg = var->inst_basereg;
14140                                                         ins->inst_offset = var->inst_offset;
14141                                                         spec = INS_INFO (ins->opcode);
14142                                                 } else {
14143                                                         /* printf ("INS: "); mono_print_ins (ins); */
14144                                                         /* Create a store instruction */
14145                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
14146
14147                                                         /* Insert it after the instruction */
14148                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
14149
14150                                                         def_ins = store_ins;
14151
14152                                                         /* 
14153                                                          * We can't assign ins->dreg to var->dreg here, since the
14154                                                          * sregs could use it. So set a flag, and do it after
14155                                                          * the sregs.
14156                                                          */
14157                                                         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)))
14158                                                                 dest_has_lvreg = TRUE;
14159                                                 }
14160                                         }
14161                                 }
14162
14163                                 if (def_ins && !live_range_start [dreg]) {
14164                                         live_range_start [dreg] = def_ins;
14165                                         live_range_start_bb [dreg] = bb;
14166                                 }
14167
14168                                 if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) {
14169                                         MonoInst *tmp;
14170
14171                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
14172                                         tmp->inst_c1 = dreg;
14173                                         mono_bblock_insert_after_ins (bb, def_ins, tmp);
14174                                 }
14175                         }
14176
14177                         /************/
14178                         /*  SREGS   */
14179                         /************/
14180                         num_sregs = mono_inst_get_src_registers (ins, sregs);
14181                         for (srcindex = 0; srcindex < 3; ++srcindex) {
14182                                 regtype = spec [MONO_INST_SRC1 + srcindex];
14183                                 sreg = sregs [srcindex];
14184
14185                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
14186                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
14187                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
14188                                         MonoInst *use_ins = ins;
14189                                         MonoInst *load_ins;
14190                                         guint32 load_opcode;
14191
14192                                         if (var->opcode == OP_REGVAR) {
14193                                                 sregs [srcindex] = var->dreg;
14194                                                 //mono_inst_set_src_registers (ins, sregs);
14195                                                 live_range_end [sreg] = use_ins;
14196                                                 live_range_end_bb [sreg] = bb;
14197
14198                                                 if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14199                                                         MonoInst *tmp;
14200
14201                                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14202                                                         /* var->dreg is a hreg */
14203                                                         tmp->inst_c1 = sreg;
14204                                                         mono_bblock_insert_after_ins (bb, ins, tmp);
14205                                                 }
14206
14207                                                 continue;
14208                                         }
14209
14210                                         g_assert (var->opcode == OP_REGOFFSET);
14211                                                 
14212                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
14213
14214                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
14215
14216                                         if (vreg_to_lvreg [sreg]) {
14217                                                 g_assert (vreg_to_lvreg [sreg] != -1);
14218
14219                                                 /* The variable is already loaded to an lvreg */
14220                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14221                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
14222                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
14223                                                 //mono_inst_set_src_registers (ins, sregs);
14224                                                 continue;
14225                                         }
14226
14227                                         /* Try to fuse the load into the instruction */
14228                                         if ((srcindex == 0) && (op_to_op_src1_membase (load_opcode, ins->opcode) != -1)) {
14229                                                 ins->opcode = op_to_op_src1_membase (load_opcode, ins->opcode);
14230                                                 sregs [0] = var->inst_basereg;
14231                                                 //mono_inst_set_src_registers (ins, sregs);
14232                                                 ins->inst_offset = var->inst_offset;
14233                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (load_opcode, ins->opcode) != -1)) {
14234                                                 ins->opcode = op_to_op_src2_membase (load_opcode, ins->opcode);
14235                                                 sregs [1] = var->inst_basereg;
14236                                                 //mono_inst_set_src_registers (ins, sregs);
14237                                                 ins->inst_offset = var->inst_offset;
14238                                         } else {
14239                                                 if (MONO_IS_REAL_MOVE (ins)) {
14240                                                         ins->opcode = OP_NOP;
14241                                                         sreg = ins->dreg;
14242                                                 } else {
14243                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
14244
14245                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
14246
14247                                                         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) {
14248                                                                 if (var->dreg == prev_dreg) {
14249                                                                         /*
14250                                                                          * sreg refers to the value loaded by the load
14251                                                                          * emitted below, but we need to use ins->dreg
14252                                                                          * since it refers to the store emitted earlier.
14253                                                                          */
14254                                                                         sreg = ins->dreg;
14255                                                                 }
14256                                                                 g_assert (sreg != -1);
14257                                                                 vreg_to_lvreg [var->dreg] = sreg;
14258                                                                 g_assert (lvregs_len < 1024);
14259                                                                 lvregs [lvregs_len ++] = var->dreg;
14260                                                         }
14261                                                 }
14262
14263                                                 sregs [srcindex] = sreg;
14264                                                 //mono_inst_set_src_registers (ins, sregs);
14265
14266 #if SIZEOF_REGISTER != 8
14267                                                 if (regtype == 'l') {
14268                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 2, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
14269                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14270                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 1, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
14271                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14272                                                         use_ins = load_ins;
14273                                                 }
14274                                                 else
14275 #endif
14276                                                 {
14277 #if SIZEOF_REGISTER == 4
14278                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
14279 #endif
14280                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
14281                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14282                                                         use_ins = load_ins;
14283                                                 }
14284                                         }
14285
14286                                         if (var->dreg < orig_next_vreg) {
14287                                                 live_range_end [var->dreg] = use_ins;
14288                                                 live_range_end_bb [var->dreg] = bb;
14289                                         }
14290
14291                                         if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14292                                                 MonoInst *tmp;
14293
14294                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14295                                                 tmp->inst_c1 = var->dreg;
14296                                                 mono_bblock_insert_after_ins (bb, ins, tmp);
14297                                         }
14298                                 }
14299                         }
14300                         mono_inst_set_src_registers (ins, sregs);
14301
14302                         if (dest_has_lvreg) {
14303                                 g_assert (ins->dreg != -1);
14304                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
14305                                 g_assert (lvregs_len < 1024);
14306                                 lvregs [lvregs_len ++] = prev_dreg;
14307                                 dest_has_lvreg = FALSE;
14308                         }
14309
14310                         if (store) {
14311                                 tmp_reg = ins->dreg;
14312                                 ins->dreg = ins->sreg2;
14313                                 ins->sreg2 = tmp_reg;
14314                         }
14315
14316                         if (MONO_IS_CALL (ins)) {
14317                                 /* Clear vreg_to_lvreg array */
14318                                 for (i = 0; i < lvregs_len; i++)
14319                                         vreg_to_lvreg [lvregs [i]] = 0;
14320                                 lvregs_len = 0;
14321                         } else if (ins->opcode == OP_NOP) {
14322                                 ins->dreg = -1;
14323                                 MONO_INST_NULLIFY_SREGS (ins);
14324                         }
14325
14326                         if (cfg->verbose_level > 2)
14327                                 mono_print_ins_index (1, ins);
14328                 }
14329
14330                 /* Extend the live range based on the liveness info */
14331                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
14332                         for (i = 0; i < cfg->num_varinfo; i ++) {
14333                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
14334
14335                                 if (vreg_is_volatile (cfg, vi->vreg))
14336                                         /* The liveness info is incomplete */
14337                                         continue;
14338
14339                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
14340                                         /* Live from at least the first ins of this bb */
14341                                         live_range_start [vi->vreg] = bb->code;
14342                                         live_range_start_bb [vi->vreg] = bb;
14343                                 }
14344
14345                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
14346                                         /* Live at least until the last ins of this bb */
14347                                         live_range_end [vi->vreg] = bb->last_ins;
14348                                         live_range_end_bb [vi->vreg] = bb;
14349                                 }
14350                         }
14351                 }
14352         }
14353         
14354 #ifdef MONO_ARCH_HAVE_LIVERANGE_OPS
14355         /*
14356          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
14357          * by storing the current native offset into MonoMethodVar->live_range_start/end.
14358          */
14359         if (cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
14360                 for (i = 0; i < cfg->num_varinfo; ++i) {
14361                         int vreg = MONO_VARINFO (cfg, i)->vreg;
14362                         MonoInst *ins;
14363
14364                         if (live_range_start [vreg]) {
14365                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
14366                                 ins->inst_c0 = i;
14367                                 ins->inst_c1 = vreg;
14368                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
14369                         }
14370                         if (live_range_end [vreg]) {
14371                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
14372                                 ins->inst_c0 = i;
14373                                 ins->inst_c1 = vreg;
14374                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
14375                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
14376                                 else
14377                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
14378                         }
14379                 }
14380         }
14381 #endif
14382
14383         if (cfg->gsharedvt_locals_var_ins) {
14384                 /* Nullify if unused */
14385                 cfg->gsharedvt_locals_var_ins->opcode = OP_PCONST;
14386                 cfg->gsharedvt_locals_var_ins->inst_imm = 0;
14387         }
14388
14389         g_free (live_range_start);
14390         g_free (live_range_end);
14391         g_free (live_range_start_bb);
14392         g_free (live_range_end_bb);
14393 }
14394
14395 /**
14396  * FIXME:
14397  * - use 'iadd' instead of 'int_add'
14398  * - handling ovf opcodes: decompose in method_to_ir.
14399  * - unify iregs/fregs
14400  *   -> partly done, the missing parts are:
14401  *   - a more complete unification would involve unifying the hregs as well, so
14402  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
14403  *     would no longer map to the machine hregs, so the code generators would need to
14404  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
14405  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
14406  *     fp/non-fp branches speeds it up by about 15%.
14407  * - use sext/zext opcodes instead of shifts
14408  * - add OP_ICALL
14409  * - get rid of TEMPLOADs if possible and use vregs instead
14410  * - clean up usage of OP_P/OP_ opcodes
14411  * - cleanup usage of DUMMY_USE
14412  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
14413  *   stack
14414  * - set the stack type and allocate a dreg in the EMIT_NEW macros
14415  * - get rid of all the <foo>2 stuff when the new JIT is ready.
14416  * - make sure handle_stack_args () is called before the branch is emitted
14417  * - when the new IR is done, get rid of all unused stuff
14418  * - COMPARE/BEQ as separate instructions or unify them ?
14419  *   - keeping them separate allows specialized compare instructions like
14420  *     compare_imm, compare_membase
14421  *   - most back ends unify fp compare+branch, fp compare+ceq
14422  * - integrate mono_save_args into inline_method
14423  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
14424  * - handle long shift opts on 32 bit platforms somehow: they require 
14425  *   3 sregs (2 for arg1 and 1 for arg2)
14426  * - make byref a 'normal' type.
14427  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
14428  *   variable if needed.
14429  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
14430  *   like inline_method.
14431  * - remove inlining restrictions
14432  * - fix LNEG and enable cfold of INEG
14433  * - generalize x86 optimizations like ldelema as a peephole optimization
14434  * - add store_mem_imm for amd64
14435  * - optimize the loading of the interruption flag in the managed->native wrappers
14436  * - avoid special handling of OP_NOP in passes
14437  * - move code inserting instructions into one function/macro.
14438  * - try a coalescing phase after liveness analysis
14439  * - add float -> vreg conversion + local optimizations on !x86
14440  * - figure out how to handle decomposed branches during optimizations, ie.
14441  *   compare+branch, op_jump_table+op_br etc.
14442  * - promote RuntimeXHandles to vregs
14443  * - vtype cleanups:
14444  *   - add a NEW_VARLOADA_VREG macro
14445  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
14446  *   accessing vtype fields.
14447  * - get rid of I8CONST on 64 bit platforms
14448  * - dealing with the increase in code size due to branches created during opcode
14449  *   decomposition:
14450  *   - use extended basic blocks
14451  *     - all parts of the JIT
14452  *     - handle_global_vregs () && local regalloc
14453  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
14454  * - sources of increase in code size:
14455  *   - vtypes
14456  *   - long compares
14457  *   - isinst and castclass
14458  *   - lvregs not allocated to global registers even if used multiple times
14459  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
14460  *   meaningful.
14461  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
14462  * - add all micro optimizations from the old JIT
14463  * - put tree optimizations into the deadce pass
14464  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
14465  *   specific function.
14466  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
14467  *   fcompare + branchCC.
14468  * - create a helper function for allocating a stack slot, taking into account 
14469  *   MONO_CFG_HAS_SPILLUP.
14470  * - merge r68207.
14471  * - merge the ia64 switch changes.
14472  * - optimize mono_regstate2_alloc_int/float.
14473  * - fix the pessimistic handling of variables accessed in exception handler blocks.
14474  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
14475  *   parts of the tree could be separated by other instructions, killing the tree
14476  *   arguments, or stores killing loads etc. Also, should we fold loads into other
14477  *   instructions if the result of the load is used multiple times ?
14478  * - make the REM_IMM optimization in mini-x86.c arch-independent.
14479  * - LAST MERGE: 108395.
14480  * - when returning vtypes in registers, generate IR and append it to the end of the
14481  *   last bb instead of doing it in the epilog.
14482  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
14483  */
14484
14485 /*
14486
14487 NOTES
14488 -----
14489
14490 - When to decompose opcodes:
14491   - earlier: this makes some optimizations hard to implement, since the low level IR
14492   no longer contains the neccessary information. But it is easier to do.
14493   - later: harder to implement, enables more optimizations.
14494 - Branches inside bblocks:
14495   - created when decomposing complex opcodes. 
14496     - branches to another bblock: harmless, but not tracked by the branch 
14497       optimizations, so need to branch to a label at the start of the bblock.
14498     - branches to inside the same bblock: very problematic, trips up the local
14499       reg allocator. Can be fixed by spitting the current bblock, but that is a
14500       complex operation, since some local vregs can become global vregs etc.
14501 - Local/global vregs:
14502   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
14503     local register allocator.
14504   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
14505     structure, created by mono_create_var (). Assigned to hregs or the stack by
14506     the global register allocator.
14507 - When to do optimizations like alu->alu_imm:
14508   - earlier -> saves work later on since the IR will be smaller/simpler
14509   - later -> can work on more instructions
14510 - Handling of valuetypes:
14511   - When a vtype is pushed on the stack, a new temporary is created, an 
14512     instruction computing its address (LDADDR) is emitted and pushed on
14513     the stack. Need to optimize cases when the vtype is used immediately as in
14514     argument passing, stloc etc.
14515 - Instead of the to_end stuff in the old JIT, simply call the function handling
14516   the values on the stack before emitting the last instruction of the bb.
14517 */
14518
14519 #endif /* DISABLE_JIT */